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
| Package | Registry | Version |
|---|---|---|
| contextgraph-types | crates.io | 2.0.0 |
| contextgraph-host | crates.io | 2.0.0 |
| contextgraph-conformance | crates.io | 2.0.0 |
| contextgraph-trace | crates.io | 2.0.0 |
| @contextgraphprotocol/typescript-sdk | npm | 0.1.0 |
| contextgraph-sdk | PyPI | 0.1.0 |
| github.com/macanderson/context-graph-protocol/sdk/go | Go module proxy | v0.1.0 |
| create-contextgraph-provider | npm | Not 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.
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.
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 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.
./.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-exampleRust crates
Four crates are on crates.io at 2.0.0. They speak contextgraph/1.0 and need Rust 1.90 or later.
contextgraph-types: wire types for frames, queries, capabilities, and provenance (API docs)contextgraph-host: host runtime with discovery, transports, negotiation, routing, and consent gating (API docs)contextgraph-conformance: conformance suite and the contextgraph-inspect binary (API docs)contextgraph-trace: host execution trace types and replay oracles, at sketch stage and outside the contextgraph/1.0 stable surface (API docs)
cargo add contextgraph-types@2
cargo add contextgraph-host@2
cargo install contextgraph-conformance[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.