The context-mcp crate exposes agent-facing tool contracts as Rust functions and through a minimal MCP stdio server.
Start the server:
cargo run -p context-cli -- mcp-stdioindex_repo: index Rust, Java, TypeScript/TSX, and Python files, chunks, symbols, graph edges, and the Tantivy sidecar. It can also run configured external reference providers for compiler/type-checker-grade references and calls.search_code: search indexed chunks and return metadata. Setvectorto true to fuse the deterministic local hash-vector signal with BM25 results.vector_search: run only the deterministic local hash-vector search signal.get_chunk: return exact source text for a chunk.find_references: return graph edges that reference a symbol, including provider, confidence, and evidence. The heuristic provider resolves common local TypeScript/Python import aliases and receiver-style method calls when the referenced file is indexed. Syntactic calls are also persisted ascallsedges for expansion and impact, while this tool continues to return reference/test-reference edges only.expand_context: expand graph context around a chunk.impact_analysis: report affected symbols, files, tests, and risk from caller-supplied changes. This lower-level call requires explicit changed files, changed symbols, and depth. Impact reasons include the graph edge provider label, for examplecalls via scip-java changed symbol.pre_change_context: search before an edit, suggest chunk IDs, and return a budgeted metadata context pack. Whenrepois provided, search/expansion are scoped to that repository and matching project memories are included.post_change_impact: analyze changed files and symbols after an edit, optionally deriving them from diff text.memory_add: persist a repo/file/symbol/span anchored project memory.memory_list: list memories, optionally filtered by repo and status.memory_delete: delete one memory by ID.memory_reconcile: refresh memory anchor statuses for a repo.
index_repo.force is optional. When omitted or false, indexing is incremental and removes stale files. When true, only the selected repository is rebuilt.
All public tool calls require a file-backed SQLite database path. :memory: is reserved for direct storage-layer tests because each public tool opens its own connection.
search_code, pre_change_context, and expand_context return metadata. get_chunk returns source text.
The context budget is metadata-only. total_estimated_tokens sums each selected chunk's estimated_metadata_tokens; it is not an estimate of full source text size.
{
"chunk_id": "chunk:simple-rust-0123:src/lib.rs:run",
"path": "src/lib.rs",
"language": "rust",
"start_line": 1,
"end_line": 3,
"symbol_path": "run",
"kind": "function",
"score": 1.23,
"signals": ["tantivy_bm25", "bm25", "local_hash_vector"]
}local_hash_vector is a deterministic local feature-hashing signal over metadata and source text tokens. It does not download a model and is not represented as semantic ML retrieval.
{
"from_id": "symbol:file-repo:src/lib.rs:wrapper",
"to_id": "symbol:file-repo:src/lib.rs:run",
"kind": "references",
"provider": "heuristic",
"confidence": 0.7,
"evidence": "wrapper references run from src/lib.rs"
}The built-in reference provider is heuristic. It preserves evidence and confidence, but does not claim compiler-grade precision. External rust-analyzer/SCIP/TypeScript/Python providers must use their own provider labels after invoking and validating the real compiler or type checker.
The graph crate exposes registered reference-provider descriptors. The built-in
descriptor advertises the heuristic provider and its possible edge kinds:
defines, references, calls, imports, implements, and
contains_test_for.
For Java, TypeScript/TSX, and Python, heuristic evidence can include local
imports, class relationships such as Service implements Runner or
Worker extends WorkerBase, and receiver calls such as new Worker().run() or
Worker().run(). These edges are intended to improve context selection and
impact hints without claiming full type-checker accuracy.
The persisted edge identity includes provider, so multiple providers can report the same from_id/to_id/kind relationship without overwriting each other's confidence or evidence.
index_repo.reference_providers is optional. Each entry runs one external command with repo as the working directory. The command is invoked by argv, not through a shell string.
{
"name": "scip-rust",
"command": "scip-rust-provider",
"args": ["--workspace", "."],
"languages": ["rust"],
"compiler_grade": true,
"strict": true,
"timeout_ms": 30000
}languages filters providers by indexed chunk language. strict: true fails the whole index if an emitted edge cannot be resolved; strict: false skips unresolved edges. timeout_ms is optional. Provider stdout/stderr are drained concurrently while the process runs, each stream is capped at 16 MiB, and the timeout covers stdin writing plus process completion. On Windows, provider commands are attached to an unnamed Job Object when available; timeout cleanup terminates the Job Object so child processes from .cmd shims, Node, or language servers do not survive the index. Provider stdout diagnostics are surfaced on the index_repo response as provider_diagnostics entries with { "provider": "...", "message": "..." }.
The provider receives JSON on stdin:
{
"protocol_version": 1,
"repo": "/workspace/repo",
"repo_id": "repo-0123",
"provider": "scip-rust",
"compiler_grade": true,
"symbols": [],
"chunks": []
}The provider writes JSON on stdout:
{
"edges": [
{
"from_symbol": "wrapper",
"from_path": "src/lib.rs",
"to_symbol": "run",
"to_path": "src/lib.rs",
"kind": "calls",
"confidence": 1.0,
"evidence": "SCIP call graph wrapper -> run"
}
],
"diagnostics": [
"rust-analyzer command rust-analyzer"
]
}Endpoints can use from_id/to_id for exact symbol IDs, or *_symbol plus optional *_path. Exact IDs are preferred for compiler-grade providers because they avoid same-name ambiguity. Path-qualified endpoints are recommended when IDs are not available. Confidence must be finite and within 0..=1. Unknown or ambiguous endpoints fail in strict mode.
The context-cli binary includes first-party adapters:
context provider rust-analyzer-scip: runsrust-analyzer scip, parses the SCIP index, and emitsreferences/callsedges byfrom_id/to_id.context provider java-scip: runsscip-java index, parses the generatedindex.scip, and emitsreferences/callsedges byfrom_id/to_id.context provider typescript: runstsc --noEmit --strict, then resolves references and call edges through the stable TypeScript compiler/language-service API (typescript/lib/typescript.js).context provider python: runs Pyright diagnostics, then resolves references throughpyright-langserverLSP.
All adapters support --timeout-ms for direct provider subprocess execution. The Python adapter also supports --lsp-startup-delay-ms to avoid a hard-coded Pyright LSP settle wait. These adapters are loaded like any other external provider by setting the provider command to the context binary and args to the matching provider ... subcommand.
{
"chunk_id": "chunk:simple-rust-0123:src/lib.rs:run",
"path": "src/lib.rs",
"start_line": 1,
"end_line": 3,
"symbol_path": "run",
"kind": "function",
"distance": 0,
"reason": "seed",
"estimated_metadata_tokens": 30
}{
"results": [],
"suggested_chunk_ids": [],
"context_pack": [],
"symbols": [],
"edges": [],
"memories": [],
"total_estimated_tokens": 0,
"token_budget": 4000,
"budget_exhausted": false
}{
"id": "memory:repo-0123:abcd",
"repo_id": "repo-0123",
"anchor_kind": "symbol",
"anchor_id": "run",
"anchor_path": "src/lib.rs",
"start_line": null,
"end_line": null,
"text": "run preserves the existing public behavior",
"source": "human",
"confidence": 1.0,
"status": "current",
"created_at_ms": 1785600000000,
"updated_at_ms": 1785600000000
}Memory statuses:
current: the exact anchor still resolves.relocated: the exact ID moved, but a path/span anchor still resolves nearby.stale: the repo/file remains, but the symbol/span no longer resolves.gone: the anchored file or path is no longer indexed.
{
"changed_files": ["src/lib.rs"],
"changed_symbols": ["run"],
"changed_new_line_ranges": {
"src/lib.rs": [{ "start": 1, "end": 1 }]
},
"report": {
"risk_level": "low",
"affected_symbols": [],
"affected_files": [],
"recommended_tests": [],
"evidence": []
}
}post_change_impact.diff accepts unified git diff text. The parser is intentionally pure and does not run git itself. It supports normal file edits, additions, deletions, renames, quoted paths, CRLF input, zero-length new hunks, and malformed-hunk tolerance.