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.
TypeScript
Published on npm as @contextgraphprotocol/typescript-sdk.
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, verify: 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
The contextgraph_sdk package lives in the repository under sdk/python — stdlib-only, typed (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, "verify": 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
Module github.com/macanderson/context-graph-protocol/sdk/go/contextgraph. 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 {
content := "Install the binding, then implement the required methods."
return cg.ContextQueryResult{Frames: []cg.ContextFrame{{
ID: "doc:1", Kind: "doc", Title: "Getting started",
Content: content, Score: 0.9,
TokenCost: cg.BudgetTokens(content),
CitationLabel: "start.md L1-10"}}}
}
func main() { cg.RunStdioProvider(myProvider{}) }Validate any of them
./.github/scripts/conformance-external.sh -- node dist/examples/example-docs.js
./.github/scripts/conformance-external.sh -- python3 examples/example_docs.py
./.github/scripts/conformance-external.sh -- ./cg-go-exampleThe 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.