06 SDKs & host

A provider in three methods

Every SDK is zero-dependency, speaks the line-oriented JSON wire over stdio, and is validated by the same Rust conformance oracle. Implement info(), capabilities(), and query(); the runtime loop handles the rest.

The stdio runtime — runStdioProvider / run_stdio_provider / RunStdioProvider — drives the whole lifecycle a host expects: handshake, query (echoing the correlation id), verify, shutdown, and it stays alive with a typed error on a malformed line rather than crashing. Each SDK also exports the canonical budget rule.

Package versions

Table 5. What each registry served on 2026-10-02.
PackageRegistryVersion
contextgraph-typescrates.io2.0.0
contextgraph-hostcrates.io2.0.0
contextgraph-conformancecrates.io2.0.0
contextgraph-tracecrates.io2.0.0
@contextgraphprotocol/typescript-sdknpm0.1.0
contextgraph-sdkPyPI0.1.0
github.com/macanderson/context-graph-protocol/sdk/goGo module proxyv0.1.0
create-contextgraph-providernpmNot published

The published SDKs are all at 0.1.0 and send contextgraph/1.0-draft, the name the protocol had before the freeze. A contextgraph/1.0 host accepts them, because both names are in the contextgraph/1 family. On the protocol repository’s main, the TypeScript and Python SDKs declare 2.0.0 and send contextgraph/1.0, and create-contextgraph-provider declares 2.0.0 too. None of the three is on npm or PyPI at 2.0.0 yet. Issue #227 tracks the publish.

TypeScript

npm install @contextgraphprotocol/typescript-sdk installs 0.1.0 from npm. The example below runs on that release and on main.

npm install @contextgraphprotocol/typescript-sdktypescript
import {
  runStdioProvider,
  budgetTokens,
  type Provider,
} from "@contextgraphprotocol/typescript-sdk";

const provider: Provider = {
  info: () => ({
    name: "my-docs-provider",
    version: "0.1.0",
    data_flow: { reads: true, writes: false, egress: false,
                 egress_scopes: ["local-only"] },
  }),
  capabilities: () => ({
    query: { kinds: ["doc"] }, correlation: true,
  }),
  query: () => {
    const content = "Install the binding, then implement the required methods.";
    return {
      frames: [{
        id: "doc:1", kind: "doc", title: "Getting started",
        content,
        content_digest: `sha256:${"11".repeat(32)}`,
        score: 0.9,
        token_cost: budgetTokens(content),
        citation_label: "start.md L1-10",
      }],
      truncated: false,
    };
  },
};

runStdioProvider(provider);

Python

pip install contextgraph-sdk installs 0.1.0 from PyPI. The import name is contextgraph_sdk. It uses only the standard library and ships type hints (py.typed). Any object with the three methods is a provider.

pip install contextgraph-sdkpython
from contextgraph_sdk import run_stdio_provider, budget_tokens

class MyDocsProvider:
    def info(self):
        return {"name": "my-docs-provider", "version": "0.1.0",
                "data_flow": {"reads": True, "writes": False,
                              "egress": False,
                              "egress_scopes": ["local-only"]}}

    def capabilities(self):
        return {"query": {"kinds": ["doc"]}, "correlation": True}

    def query(self, query):
        content = "Install the binding, then implement the required methods."
        return {"frames": [{
            "id": "doc:1", "kind": "doc", "title": "Getting started",
            "content": content,
            "content_digest": "sha256:" + ("11" * 32),
            "score": 0.9,
            "token_cost": budget_tokens(content),
            "citation_label": "start.md L1-10"}],
            "truncated": False}

run_stdio_provider(MyDocsProvider())

Go

Import github.com/macanderson/context-graph-protocol/sdk/go/contextgraph. go get resolves the v0.1.0 tag today. The example follows main, where Content is a *string set with cg.Ptr. In v0.1.0, Content is a plain string and cg.Ptr does not exist, so write Content: content there. Implement cg.Verifier to answer verification.

Package contextgraphgo
package main

import cg "github.com/macanderson/context-graph-protocol/sdk/go/contextgraph"

type myProvider struct{}

func (myProvider) Info() cg.ProviderInfo {
	return cg.ProviderInfo{Name: "my-docs-provider", Version: "0.1.0",
		DataFlow: cg.DataFlow{Reads: true,
			EgressScopes: []string{"local-only"}}}
}

func (myProvider) Capabilities() cg.Capabilities {
	return cg.Capabilities{Query: cg.QueryCapability{Kinds: []string{"doc"}},
		Correlation: true}
}

func (myProvider) Query(_ cg.ContextQuery) (cg.ContextQueryResult, error) {
	content := "Install the binding, then implement the required methods."
	return cg.ContextQueryResult{Frames: []cg.ContextFrame{{
		ID: "doc:1", Kind: "doc", Title: "Getting started",
		Content: cg.Ptr(content), Score: 0.9,
		TokenCost:     cg.BudgetTokens(content),
		CitationLabel: "start.md L1-10"}}}, nil
}

func main() { cg.RunStdioProvider(myProvider{}) }

Validate any of them

Run these from the root of the protocol repository, after cargo build --workspace --bins and a build of each SDK’s example provider.

The shared oracleshell
./.github/scripts/conformance-external.sh -- node sdk/typescript/dist/examples/example-docs.js
./.github/scripts/conformance-external.sh -- python3 sdk/python/examples/example_docs.py
./.github/scripts/conformance-external.sh -- ./cg-go-example

Rust crates

Four crates are on crates.io at 2.0.0. They speak contextgraph/1.0 and need Rust 1.90 or later.

Add the cratesshell
cargo add contextgraph-types@2
cargo add contextgraph-host@2
cargo install contextgraph-conformance
Or in Cargo.tomltoml
[dependencies]
contextgraph-types = "2"
contextgraph-host = "2"

cargo install contextgraph-conformance installs contextgraph-inspect. Depend on the major, as in contextgraph-types = "2", and upgrade within 2.x as usual. Only 2.x receives security fixes. The reference providers and the MCP bridge and server stay in the repository and are not published.

The host side

contextgraph-host is the Rust host runtime: provider discovery, stdio and streamable-HTTP transports, capability negotiation, budget-honest fan-out routing, and egress consent gating. Register providers in-process, as child processes, or as remote HTTP endpoints; query_all fans out concurrently with per-provider isolation — a crashed child never affects the others — and classifies budget liars so their frames are dropped and reported.

Composition is deterministic: frames are emitted in canonical FrameId order, independent of arrival order, inside explicit <frame> fences as quoted material. Stable prefixes turn provider prompt caches from an accident into a contract — the worked example in the context-reuse note shows a ~7× reduction on the context portion of a 20-turn session.