Repository navigation
06 MCP Integration
Attaching RAGRAF to an agent as an MCP server: configuration, the working regimen, and the rules that keep the agent honest. Normative source: docs/implementation/INTEGRATION.md.
RAGRAF speaks JSON-RPC 2.0 over stdio (MCP protocol version 2024-11-05). No HTTP, no daemon — the client spawns the process.
{
"mcpServers": {
"ragraf": {
"command": "python",
"args": [
"/path/to/RAGRAF/tools/ragraf-mcp.py",
"--project", "/path/to/RAGRAF/config/mycorpus.yaml",
"--agent", "my-agent",
"--agent-kind", "external"
]
}
}
}| Arg | Required | Meaning |
|---|---|---|
--project |
yes | corpus config. Create it with ragraf init <project-dir> (prints the path) |
--agent |
no | agent name for per-agent statistics; without it, clientInfo from initialize is used, else unknown
|
--agent-kind |
no |
autoclaw · external · internal — family-level statistics |
--debug |
no | verbose server logging to stderr |
Use the venv interpreter explicitly for reliability: ~/.ragraf/venv/Scripts/python.exe (Windows) or ~/.ragraf/venv/bin/python (POSIX).
The config directory
config/is machine-local and git-ignored by design — see Configuration.
All tools are the facade operations (same names, same envelope), prefixed ragraf_:
| Group | Tools |
|---|---|
| Session start |
ragraf_index_status · ragraf_drift_report
|
| Navigation |
ragraf_search (supports with_text) · ragraf_symbol · ragraf_references · ragraf_repo_map · ragraf_code (entry_ids) |
| Graph |
ragraf_callers · ragraf_callees · ragraf_impact · ragraf_slice (needs capability=full) |
| DB & contracts |
ragraf_schema · ragraf_table_usage · ragraf_write_check · ragraf_routes
|
| Policy & UI |
ragraf_policy_trace · ragraf_class_usage
|
| Freshness & meta |
ragraf_freshness · ragraf_live_read · ragraf_drift_ack · ragraf_usage · ragraf_catalog · ragraf_ensure
|
There is no graph-query tool and there will be none (FT-15). An attempt to pass MATCH ... RETURN is rejected with JSON-RPC -32602.
⚠️ Known issue: the rejection filter is substring-based and can false-positive on legitimate text arguments containing words likereturn(e.g. a search query «when does the function return false»). Tracked as defect C-02 / roadmap R-SEC-2 — the structural guarantee (no query endpoint) is what actually enforces FT-15.
Per-tool semantics, parameters and reading rules: Operations Reference.
1. ragraf_index_status → revision, parse completeness, capability, ledger size
2. ragraf_drift_report → if the ledger is non-empty: account for divergences BEFORE any conclusions
Between the index and the code there may be differences: the index is immutable within a revision while the code has been edited. An agent that skips the ledger may rely on a fact that is already false — and not notice.
| The agent asks | Tool |
|---|---|
| «where does this live?» |
ragraf_symbol; unsure → ragraf_search
|
| «how is the module built?» |
ragraf_repo_map (budget; chars_used is actual volume) |
| «who calls this?» / «what does it call?» |
ragraf_callers / ragraf_callees
|
| «what breaks if I change it?» |
ragraf_impact — mandatory before the edit
|
| «where else is it used?» | ragraf_references |
| «what data flows here?» |
ragraf_slice (only at capability=full) |
| «what's in the table / who touches it?» |
ragraf_schema · ragraf_table_usage
|
| «is this write valid?» |
ragraf_write_check — before writing SQL
|
| «who gets this permission?» | ragraf_policy_trace |
| «what is this fragment?» |
ragraf_search + with_text: true (address+text in one call) |
| «show me that place in detail» |
ragraf_code + entry_ids from the hit |
-
Whole-file reads are the last resort — after «not found» or a
stalemark. -
A fact with
stale_warningsis not a basis for conclusions —ragraf_live_readfirst. -
Bodies don't arrive in
impact/slice/repo_map— by design; fetch withsearch with_textorcode entry_idsin ONE call if needed. -
Separate
statedfromderived— conclusions onderivedare «requires verification». -
Respect
capability—degradedmeans slices/flows are unavailable (refusal with reason), not an empty result. -
Read
limits— every answer lists what it cannot see. - The index is not updated mid-task — edits go to the ledger.
after edits: ragraf drift --scan (register deltas; index untouched)
extract-method: → a slice_boundary entry appears; revisit conclusions around it after reindex
effort finished: ragraf reindex (new revision; ledger archived into a 3-section report)
## Code knowledge base (RAGRAF)
Before working with code, use RAGRAF instead of reading files blind.
Order:
1. `ragraf_index_status` — index state.
2. `ragraf_drift_report` — if the ledger is non-empty, account for divergences first.
3. Questions about code — through operations: `ragraf_symbol`, `ragraf_callers`,
`ragraf_impact`, `ragraf_search`, `ragraf_repo_map`.
4. `rg` and whole-file reads — only if the index answered «not found» or a fact is
marked `stale` (then `ragraf_live_read` first).
5. Before an edit touching a public method or a table, `ragraf_impact` is mandatory.
6. After edits: `ragraf drift --scan` (the index is NOT updated).
7. When the change effort is done: `ragraf reindex`.
Forbidden:
- writing graph queries (Cypher/CPGQL) — only the fixed operation set exists;
- relying on a `stale`-marked fact without a prior `ragraf_live_read`;
- treating `derived` links as proven;
- ignoring `limits` and `capability` in answers.-
Lifecycle:
initialize→ server answersprotocolVersion: 2024-11-05,capabilities.tools.listChanged: false,serverInfo {name: "ragraf", version}→notifications/initialized→tools/list/tools/call/ping. -
Errors: unknown method →
-32601; query-language attempt →-32602; unknown tool →isError: truecontent (per MCP); operation-layer refusal → normal result witherror+ exit-code-3 semantics surfaced in the payload. -
Known protocol gaps (roadmap R-MCP-1): the server replies to unknown notifications (JSON-RPC forbids it); no negotiation against newer protocol versions (
2025-03-26,2025-06-18); telemetry attribution falls back toclientInfo.name. -
Telemetry: every
tools/callis journaled (op, rev, capability, duration, found, fact counts, chars, arg hash+digest, agent, task). Read back viaragraf_usage. Reading usage never writes.
# one-shot handshake over stdio (PowerShell)
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}',
'{"jsonrpc":"2.0","method":"notifications/initialized"}',
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' |
python tools/ragraf-mcp.py --project config/mycorpus.yaml --agent probeExpect: serverInfo in response 1; 23 tools in response 2. Then in your client, first call of the session: ragraf_index_status.
Next: Configuration →