Connect Your Agent¶
Connect Your Agent¶
axiom-graph is agent-native first. The Model Context Protocol (MCP) server is the primary way to use it: once your coding agent (Claude Code, Cursor, Copilot, Continue, or anything that speaks MCP) is connected, every axiom_graph_* tool appears in the agent’s palette and the agent can query the codebase mesh directly. The human CLI and visualizer are the secondary path.
Why lead with MCP? Because the whole point of axiom-graph is context reduction. Instead of an agent reading a whole file to find one function, or loading an entire design doc to answer one question, it asks the mesh for exactly the context it needs: one search hit, one function by line range, one doc section, or a one-hop traversal to the linked nodes. The agent spends its context budget on the answer, not on the haystack.
This page walks the full onboarding path: install, build the index, register the server in your client, then run an agent through its first intent-scoped retrieval. It closes with the current tool surface and the maintenance tools that keep the mesh trustworthy as code drifts.
Install¶
Install axiom-graph into the virtualenv your project uses:
pip install axiom-graph
That single package ships both the indexer and the MCP server. There is no separate server install.
Note on extras: older guides mentioned a
[semantic]extra for embedding-based search. Semantic search is deprecated as of 2.1.0 and removed in 3.0 (ADR-020) — do not install it. Keyword search (FTS5) is the supported search path and needs no extra.
Build the Index First¶
The MCP server reads a SQLite index at .axiom_graph/graph.db. If that file does not exist, every tool call fails with a “missing index” error. Build it once before connecting:
axiom-graph init . # one-time: scaffold config + first index
axiom-graph build . # incremental rebuild after that
The first build scans every file and can take 30+ seconds on a large codebase; subsequent builds are incremental (an mtime check skips unchanged files). The agent can also call axiom_graph_build itself once the server is connected, but having a baseline index in place means the very first tool call already returns useful results.
See Use the CLI for the full init / build surface and Configuration for what lives in the config file.
Configure Claude Code¶
Create a .mcp.json file in your project root:
{
"mcpServers": {
"axiom-graph": {
"type": "stdio",
"command": "/path/to/your/venv/bin/python",
"args": ["-m", "axiom_graph.mcp_server"],
"env": {
"AXIOM_GRAPH_LOG_LEVEL": "INFO"
}
}
}
}
Point command at the Python executable inside the virtualenv where axiom-graph is installed. Using python -m axiom_graph.mcp_server rather than the bare axiom-graph-mcp console script guarantees the right virtualenv is used regardless of PATH.
Restart Claude Code. All axiom_graph_* tools then appear in the agent’s tool palette. Every tool takes project_root as its first argument — the absolute path to your indexed project.
Configure Cursor and Other MCP Clients¶
The server uses stdio transport: it reads JSON-RPC requests from stdin and writes responses to stdout, while all logging goes to stderr so it never corrupts the protocol stream. Any MCP-capable client can drive it.
Two equivalent entry points exist:
Entry point |
When to use |
|---|---|
|
Most reliable; pins the virtualenv. Recommended. |
|
Console script installed by pip; works when axiom-graph is on PATH. |
For Cursor, add an axiom-graph entry to its MCP server settings using the same command / args shape as the Claude Code example above. For VS Code extensions that support MCP (Copilot, Continue, etc.), add it to .vscode/settings.json:
{
"mcp.servers": {
"axiom-graph": {
"command": "/path/to/your/venv/bin/python",
"args": ["-m", "axiom_graph.mcp_server"],
"env": { "AXIOM_GRAPH_LOG_LEVEL": "INFO" }
}
}
}
The pattern is identical across clients — point at the venv Python and use the module entry point. Only the JSON key differs (mcpServers vs mcp.servers); check your client’s docs for the exact spelling.
To sanity-check the server outside any client, run axiom-graph-mcp in a terminal: it starts and waits for JSON-RPC on stdin. Press Ctrl+C to stop.
Retrieve an Intent-Scoped Bundle¶
Once connected, the agent’s core move is to pull just the part of the mesh sized to its intent, never the whole codebase. The canonical loop is search → source / read_doc / graph, and each step is a deliberate context saving.
1. Locate the node. Full-text search returns one ranked line per hit — node ID plus a one-line summary, with @ path#L10-L45 line ranges for function nodes — instead of a pile of file contents:
axiom_graph_search(project_root, "compute_staleness")
2. Read exactly what you need from that node:
Tool |
Returns |
Context saved |
|---|---|---|
|
The function body by stored line range |
The rest of the file never loads |
|
One DocJSON section as Markdown |
The rest of the document never loads |
|
Just the linked neighbours (one hop) |
No grep across the tree |
# Function body only — no file-path parsing, no offset arithmetic
axiom_graph_source(project_root, "myproject::index.staleness::compute_staleness")
# One doc section, not the whole doc
axiom_graph_read_doc(project_root, "myproject::docs.architecture", section="data-model")
# Traverse to exactly the linked nodes
axiom_graph_graph(project_root, node_id, direction="out")
This is the typed mesh paying off: the same nodes-and-edges that power drift detection are what the agent reads for context. An edge is intent-typed (a doc documents a function; a test validates it), so traversal lands on semantically related nodes, not just textual neighbours.
A note on the graph’s shape. axiom-graph is an orientation and staleness tool, not a full call graph. The scanner emits depends_on edges from imports and composes edges from module-to-definition, but it does not index every function call site. So axiom_graph_graph(direction="in") finds importers and dependents, not literal callers — for “where is this called?” fall back to your editor’s grep. Used for what it is good at — orientation, import dependency, doc coverage, and staleness — the mesh is the cheapest map of the codebase an agent can hold.
For more usage patterns, see the reporting pipeline example and the agent that consumes the mesh to do real work in PEV.
The Tool Surface¶
The server exposes its tools grouped by concern. Every tool takes project_root first and returns a text response (even on error — failures come back as ERROR: strings, not dropped connections). This list reflects the current surface.
Query (read the mesh):
Tool |
Purpose |
|---|---|
|
3-stage full-text search (FTS5 → LIKE-AND → LIKE-OR) over node and doc-section text |
|
Raw source body of a node by line range |
|
Render a DocJSON doc (or one |
|
Traverse |
|
Filtered node listing by type, tag, |
|
Multi-level detail render (level_0–level_3) with inline staleness badges |
|
Read-only SQL against the index |
|
Tag enumeration; code with no linked doc |
|
The semantic layer: axiom-annotation workflow purpose, inputs/outputs, step ordering |
Lifecycle and staleness:
Tool |
Purpose |
|---|---|
|
Rebuild the index (discovery-only; safe to re-run) |
|
One-line staleness headline (own_status + link_status counts) |
|
Filtered / grouped / paginated per-node drift detail |
|
What changed in a node since a baseline commit |
|
Impact report since a checkpoint, SHA, or timestamp |
|
Change timeline; available baselines |
|
Record agent verification (clears promotable own_status) |
|
Manually weld / un-weld a missed rename |
|
Isolated read-only DB snapshot |
|
Remove a node from the index |
Doc editing: axiom_graph_write_doc, axiom_graph_update_section, axiom_graph_patch_section (append / prepend / unique-match replace), axiom_graph_add_section, axiom_graph_delete_section, axiom_graph_delete_doc, axiom_graph_add_link, axiom_graph_delete_link, axiom_graph_update_doc_meta, plus axiom_graph_render_site to republish the consumer site.
Docs at this layer are themselves DocJSON nodes — a section is its own node — so an agent can read, patch, and re-link documentation at section granularity, the same atomic unit it reads.
axiom_graph_reportis an MCP tool, not a CLI subcommand. Thereportview is reached through the agent (or the visualizer), notaxiom-graph report.
Keeping the Mesh Honest¶
Staleness is not a side feature — it is the engine that keeps the mesh worth trusting. When code drifts away from the docs and tests that link to it, the agent needs to know, then act. These tools turn drift into a workflow.
Find the drift. axiom_graph_check gives the headline (own: N CONTENT_UPDATED … · link: N LINKED_STALE … · N VERIFIED). For the specific nodes — filtered by status, scoped by path glob, grouped by feature, paginated so big drift volumes stay under the result cap — use axiom_graph_drift_query:
# Every LINKED_STALE node under one subtree, as bare IDs
axiom_graph_drift_query(project_root, filter="LINKED_STALE",
location_glob="src/viz/**", format="ids")
Inspect a change. axiom_graph_diff shows what changed in a node since its verified baseline — a line-scoped source diff for code, a section-level diff for docs — so the agent reviews only the delta, not the whole file again.
Survive renames. axiom-graph auto-matches renames by scoped similarity, but when a rename falls below threshold the old node goes NOT_FOUND and the renamed code is indexed fresh. axiom_graph_apply_rename(old_id, new_id) welds them — migrating the old node’s history, verification, and edges onto the new identity — and axiom_graph_revert_rename(new_id) un-welds it (idempotent). Because consumer docs link through a dev-doc proxy rather than at raw symbols, those links ride the rename and stay intact.
Isolate reads. axiom_graph_checkout produces a read-only DB snapshot, useful for parallel analysis while a build runs elsewhere.
Clear it once fixed. axiom_graph_mark_clean records that an agent re-verified a node, promoting drifted-but-now-correct own_status back to VERIFIED. LINKED_STALE is not mark-cleanable by fiat — the prose or test actually has to be updated.
This loop is also why these docs stay honest. Published consumer pages are DocJSON nodes linked through a dev-doc proxy to the code; because consumer is a transitive tag, a consumer page inherits LINKED_STALE when the code beneath it drifts. That inherited staleness is the signal to update the page; mark-clean / verification clears it; render-site republishes. This very site is built that way — axiom-graph dogfoods its own staleness engine. See staleness and the docs-honesty loop for the full story, and the mesh for how the typed edges underpin all of it.
Observability and Troubleshooting¶
Log level. AXIOM_GRAPH_LOG_LEVEL (default INFO) controls verbosity: DEBUG, INFO, WARNING, ERROR. At INFO the server already logs every tool call with its duration; DEBUG adds SQL, parser internals, and edge-resolution detail. Logs always go to stderr (stdout is reserved for the protocol). Set AXIOM_GRAPH_LOG_FILE to also write to a rotating file (5 MB × 2 backups), then tail -f it to watch an agent’s search → source → graph sequence in real time:
{
"env": {
"AXIOM_GRAPH_LOG_LEVEL": "DEBUG",
"AXIOM_GRAPH_LOG_FILE": "/tmp/axiom-graph-mcp.log"
}
}
Common issues:
Symptom |
Cause and fix |
|---|---|
No tools appear |
|
Tool calls fail immediately |
No |
“database is locked” |
Two writers contend (e.g. two builds). The DB runs in WAL mode, so unlimited readers are fine — just serialize writes (one build at a time). |
Slow first response |
First build/scan, or a large project. Subsequent builds are incremental. |
Error shape. When a tool fails (bad node ID, parse error, validation rejection) it returns a structured JSON-RPC error with a stable code and a human-readable message, logs the cause to stderr, and keeps the connection up. A single bad call never poisons a long agent session — only catastrophic failures (DB corruption, OOM) bring the server down. Agents that retry should match on the error code, not the message text.