mcp-repo-graph
repo-graph
Structural graph memory for AI coding assistants. Map your codebase. Navigate by structure. Read only what matters.
repo-graph gives LLMs a map of your codebase — entities, relationships, and flows — so they can navigate to the right files without reading everything first.
Instead of flooding an LLM's context window with your entire codebase (or hoping it guesses right), repo-graph builds a lightweight graph of what exists, how things connect, and where the entry points are. The LLM queries the graph, finds the minimal set of files it needs, and reads only those.
Demo
https://github.com/user-attachments/assets/a1e4171b-b225-40d4-9210-39453e14b76a
https://github.com/user-attachments/assets/fc3191e5-fc35-4bd7-8372-72af55995883
Same bug, same model, same prompt — the only difference is whether repo-graph is installed.
The task: fix a reversed comparison operator in a Go + Angular monorepo (566 nodes, 620 edges).
Without repo-graph | With repo-graph | |
Tokens used | 75,308 | 29,838 |
Time to fix | 4m 36s | ~30s |
Files explored | ~15 (grep, read, grep, read...) | 2 (flow lookup + handler file) |
Outcome | Found and fixed the bug | Found and fixed the bug |
2.5x fewer tokens. ~9x faster. Same correct fix.
How the test was run
Both runs used identical conditions to keep the comparison fair:
Same model: Claude Opus, 100% (no Haiku routing)
Same prompt: "Groups that were created recently are showing as closed, and old groups show as open. This is backwards — new groups should be open for members to join. Find and fix the bug."
Fresh context: each run started from
/clearwith no prior conversationNo other tools: CLAUDE.md, plugins, hooks, and all other MCP servers were removed for both runs — the only variable was whether repo-graph was installed
No hints: the prompt describes the symptom, not the location — Claude has to find
group_controller.go:57on its own
Without repo-graph, Claude greps for keywords, reads files, greps again, reads more files, and eventually narrows down to the bug. With repo-graph, Claude calls flow("groups"), gets back the exact handler function and file, reads it, and fixes it.
Browse pre-generated examples for FastAPI, Gin, Hono, and NestJS — real graph output you can inspect without installing anything.
Related MCP server: Serena
The problem
LLMs working on code waste most of their context on orientation:
Reading files that turn out to be irrelevant
Missing connections between components in different languages
Not knowing where a feature starts or what it touches
Loading 50 files when 5 would do
This is expensive, slow, and gets worse as codebases grow.
How repo-graph solves it
repo-graph scans your codebase once and builds a graph of:
Entities: modules, packages, classes, functions, routes, services, components
Relationships: imports, calls, handles, defines, contains, cross-stack HTTP
Flows: end-to-end paths from entry point to data layer
Then it exposes 13 MCP tools that let the LLM:
Orient — "What languages are in this repo? What are the main features?"
Navigate — "Trace the login flow from route to database" / "What's the shortest path between UserService and the payments API?"
Scope — "How many lines would I need to read to understand this feature?" / "Give me just the files I need for this bug fix"
Assess — "What's the blast radius of changing this function?" / "Which files are the biggest maintenance risks?"
The LLM gets structural context in a few hundred tokens instead of reading thousands of lines.
Supported languages
Language | Detection | What it extracts |
Go |
| Packages, functions, HTTP routes (gin/echo/chi/stdlib), imports |
Rust |
| Crates, modules, structs, traits, functions, routes (Actix/Rocket/Axum) |
TypeScript |
| Modules, classes, functions, import relationships |
React |
| Components, hooks, context providers, React Router routes, fetch/axios calls, flows |
Angular |
| Components, services, guards, DI injection, HTTP calls, feature flows |
Vue |
| SFCs, composables, Vue Router routes, fetch/axios calls |
Python |
| Packages, modules, classes, functions, routes (Flask/FastAPI/Django) |
Java/Kotlin |
| Packages, classes, routes (Spring/JAX-RS/Ktor/WebFlux/Micronaut) |
Scala |
| Packages, objects/classes/traits, routes (Play/Akka HTTP/http4s) |
Clojure |
| Namespaces, defn/defprotocol/defrecord, routes (Compojure/Reitit) |
C#/.NET |
| Namespaces, classes, routes (ASP.NET/Minimal API) |
Ruby |
| Files, classes, modules, Rails routes |
PHP |
| Namespaces, classes, interfaces, routes (Laravel/Symfony) |
Swift |
| Files, types (class/struct/enum/protocol/actor), Vapor routes |
C/C++ |
| Sources, headers, classes, structs, enums, namespaces, includes |
Dart/Flutter |
| Modules, classes, widgets, go_router/shelf routes |
Elixir/Phoenix |
| Modules, functions, Phoenix router scopes + routes |
Solidity |
| Contracts, interfaces, libraries, events, inheritance |
Terraform |
| Modules, resources, variables, outputs, module sources |
SCSS |
| File-level bloat analysis |
Cross-cutting extractors (work across all languages):
Data sources — DB/cache/queue/blob/search/email client detection
CLI entrypoints — Python click, JS commander/yargs, Go cobra, Rust clap
gRPC — service/method definitions from
.protofilesQueue consumers — Celery, Dramatiq, BullMQ, Sidekiq, Oban, NATS
Cross-stack HTTP — frontend
fetch/axioscalls linked to backend routes
Multiple languages can match one repo (e.g., Go backend + Angular frontend + SCSS). Each contributes its nodes and edges into a single unified graph.
Install
pip install mcp-repo-graphPython 3.11+. Installs two packages: mcp-repo-graph (the MCP server) and repo-graph-py (the Rust engine, as a prebuilt wheel).
Quick start
1. Initialise the target repo
repo-graph-init --repo /path/to/your/projectThis generates the graph, writes .mcp.json and CLAUDE.md instructions, and gets your AI assistant ready to use repo-graph.
2. Connect to your AI assistant
If you skipped repo-graph-init, add this to your MCP configuration manually:
Claude Code (~/.claude/claude_code_config.json or project .mcp.json):
{
"mcpServers": {
"repo-graph": {
"command": "repo-graph",
"args": ["--repo", "/path/to/your/project"]
}
}
}With environment variable:
{
"mcpServers": {
"repo-graph": {
"command": "repo-graph",
"env": { "REPO_GRAPH_REPO": "/path/to/your/project" }
}
}
}3. Use it
The AI assistant now has access to all 13 tools. Example queries it can answer:
"What does this codebase do?" →
statustool"Trace the checkout flow" →
flowtool"What would break if I change UserService?" →
impacttool"What files do I need for this bug?" →
minimal_readtool"This file is too big, how should I split it?" →
split_plantool"Show me the auth flow visually" →
graph_viewtool
4. Keep it fresh with a git hook (recommended)
Add a call to generate via your MCP client to a pre-commit hook so the graph stays up to date automatically — no LLM context spent on regeneration:
# .git/hooks/pre-commit (or add to your existing hook)
#!/bin/sh
repo-graph --repo . --regenerate
git add .ai/repo-graph/chmod +x .git/hooks/pre-commitEvery commit keeps the graph current. The LLM always has a fresh map without wasting a single token on generate.
Tip: If you don't want graph data in version control, add
.ai/repo-graph/to.gitignoreand skip thegit addline — the graph will just live locally.
MCP tools reference
Generation
Tool | Parameters | Description |
| (none) | Scan the codebase from scratch, rebuild the graph, and reload |
| (none) | Reload graph data from disk (after external regeneration) |
Navigation
Tool | Parameters | Description |
| (none) | Repo overview: git state, detected languages, entity counts, available flows |
|
| End-to-end flow for a feature — from entry point through service layer to data |
|
| Shortest path between any two nodes in the graph |
|
| Fan out from a node to see what it affects or depends on |
|
| All direct connections to and from a node |
Context budgeting
Tool | Parameters | Description |
|
| Total line count for all files in a feature's flow |
|
| Files ranked by |
|
| Smallest file set needed for a specific task within a feature |
Health analysis
Tool | Parameters | Description |
|
| Internal structure of a file: functions/methods ranked by size, type counts |
|
| Concrete suggestions for splitting an oversized file, grouped by responsibility |
|
| Visual ASCII map of a feature flow, node neighbourhood, or full graph overview |
How it works
mcp-repo-graph is a thin Python MCP server that wraps glia, a Rust engine.
Parse — per-language tree-sitter parsers extract raw nodes and unresolved references
Extract — cross-cutting extractors layer on HTTP routes, data sources, CLI entrypoints, gRPC services, queue consumers
Resolve — graph builder resolves intra-repo references; cross-graph resolvers link stacks (frontend HTTP calls → backend routes, etc.)
Store — merged graph lands in
.ai/repo-graph/as a zero-copy.gmap(rkyv + mmap) plus JSON projections for portabilityServe — the MCP server loads the graph into memory and exposes the 13 tools
The Rust engine will split into its own glia repo post-v0.4.12. mcp-repo-graph will remain the MCP-facing thin wrapper.
Config (optional escape hatch)
If auto-detection misses a weird layout, drop .ai/repo-graph/config.yaml in the target repo:
skip:
- legacy # directory basenames excluded from the walk
- scratch
roots: # explicit roots heuristics miss — added on top of auto-detection
- path: apps/weird-layout
kind: python
- path: services/custom
kind: gokind values: go, rust, python, typescript, react, vue, angular, java, scala, clojure, csharp, ruby, php, swift, c_cpp, dart, elixir, solidity, terraform. config.json works too if you prefer.
Graph data format
Generated files live in .ai/repo-graph/ inside the target repo:
nodes.json—[{id, type, name, file_path, confidence, ...}, ...]edges.json—[{from, to, type}, ...]flows/*.yaml— named feature flows with ordered step sequences andkind(http/page/cli/grpc/queue)state.md— human-readable snapshot for quick orientation
Common edge types: imports, defines, contains, uses, calls, handles, handled_by, exports, includes, tests, cross-stack HTTP links.
License
MIT
Support
If repo-graph saved you time, consider buying me a coffee.
Available Tools
6 toolsfindARead-only
Turn any text into the ranked nodes that matter — the on-ramp to the graph. A symbol or keyword returns matching nodes; a pasted stacktrace / failing-test id / diff is resolved to the code it implicates and ranked by relevance. Set expand=true to fan out to the surrounding neighbourhood (spreading activation). Every row carries path:line, so read the top hits directly — no grep.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Force the signal type: 'symbol', 'stacktrace', 'test', 'diff', or 'auto' (sniff the shape). | auto |
| query | Yes | What to locate: a symbol/keyword (e.g. `User`, `checkout`), OR a failure signal — paste a raw stacktrace, a failing-test id (path::test), or a unified diff / changed-file list. | |
| top_k | No | Max results. Default 20. | |
| budget | No | Max chars in the result. 0 = no cap. | |
| expand | No | Return the relevant neighbourhood (Personalized-PageRank ranked) around the matches, not just the matches themselves. Use to discover what surrounds a seed. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only provide readOnlyHint=true, while the description adds rich behavioral detail: ranking by relevance, resolving different input types (stacktrace, diff), neighborhood expansion via spreading activation, and output format (path:line). This goes well beyond the minimal annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (4-5 sentences) yet packs substantial information. It front-loads the core purpose and covers key variations. Every sentence contributes value, avoiding redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (5 parameters, output schema exists), the description covers the primary use cases and output characteristics (path:line). It does not need to restate the output schema, but provides enough context for effective use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
All 5 parameters are described in the schema (100% coverage), but the description adds meaningful context: examples for 'query' (paste raw stacktrace, test id), explanation of 'expand' (Personalized-PageRank), and 'kind' auto-detect behavior. This enhances understanding beyond schema defaults.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool transforms text into ranked graph nodes, serving as an on-ramp to the graph. It specifies that it handles symbols, keywords, stacktraces, test IDs, and diffs, but does not explicitly differentiate from sibling tools like 'trace' or 'orient', though it mentions 'read' for subsequent steps.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context: use for initial search or failure resolution, with 'expand=true' for neighborhood exploration. It suggests reading top hits via 'read', but lacks explicit when-not-to-use guidelines or comparisons with sibling tools like 'impact' or 'trace'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
impactARead-only
Blast radius in one call: fan out from one or more nodes to everything they affect (forward) or depend on / are used by (backward), returned as a complete, deduped, Personalized-PageRank-ranked, located closure. Each row carries path:line, the edge via reason it's in scope, and a ⊘ when the engine finds it unreachable from any entry point (likely dead). Structural import/containment fan-out is excluded — no noise. Depth-1 in both directions is a node's immediate neighbours. Pass several comma-separated nodes to assess a whole diff at once.
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | How many hops to fan out. Default 4. | |
| nodes | Yes | One or more node names/qnames, comma-separated. A diff touching N symbols is one call. | |
| top_k | No | Cap the ranked result. 0 = no cap. | |
| budget | No | Max chars in the result. 0 = no cap. | |
| direction | No | 'forward' (what it affects), 'backward' (what it depends on / who uses it), or 'both'. (Aliases: downstream=forward, upstream=backward.) | both |
| live_only | No | Drop nodes not reachable from any entry point (likely-dead code). Default False = show all, marking dead ones ⊘. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description reveals key behaviors: ranking algorithm (Personalized PageRank), result fields (path:line, via, dead marker), exclusion of structural edges, depth meaning, and handling of multiple nodes. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single dense paragraph that front-loads the core functionality. Every sentence contributes meaningful detail, with no wasted words. It efficiently communicates complex behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and rich parameters/output, the description fully covers result structure, filtering, ranking, and exclusive behavior. It matches the needed detail without relying on output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage, the baseline is 3. The description adds value by explaining node usage for whole diffs, aliases for direction, and the meaning of depth-1. This enriches the schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: computing blast radius/impact from nodes in forward or backward directions. It distinguishes itself from siblings like trace and find by emphasizing its comprehensive, deduped, ranked closure and exclusion of structural edges.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool (assessing impact of changes, whole diff) and even hints at what it excludes (structural fan-out). However, it doesn't explicitly compare to alternatives or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
orientARead-only
Get the lay of the land — ALWAYS the first call on a codebase. With no arguments: a counts + entry-points overview plus a blind spots note flagging which (language, edge-kind) extractions are partial so you know where to fall back to grep. With seed=<node>: the dense structural map scoped to that node's neighbourhood. With full=true: the whole-repo dense map (the full context dump). Orient first, then find to jump to nodes, impact for blast radius, trace for flows.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | With no seed: return the whole-repo dense structural map instead of the counts overview. Ignored when seed is given. | |
| seed | No | Optional node/qname to scope the map around (its activated neighbourhood). Blank = repo overview. | |
| budget | No | Max chars in the result. 0 = default cap (~50k for the full map, uncapped otherwise). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the description doesn't need to repeat that. It meaningfully adds context about output types (counts, entry-points, blind spots, structural maps) and the budget parameter, which are not covered by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured. The critical instruction 'ALWAYS the first call on a codebase' is front-loaded, and each sentence serves a purpose: explaining modes, blind spots, and sibling tool ordering.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (three modes, multiple output types, sibling tools), the description is remarkably complete. It covers each mode's output, mentions limitations (blind spots), and provides a recommended workflow. The presence of an output schema reduces the need to detail return values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage, the baseline is 3. The description adds value by explaining the behavioral differences of each parameter combination (no args vs. seed vs. full) and clarifying the budget default behavior, going beyond what the schema alone provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly specifies the tool's purpose: getting an overview of a codebase. It details three distinct modes (no args, seed, full) and explicitly contrasts with sibling tools (find, impact, trace), making it easy for an agent to select the right tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidance: 'ALWAYS the first call on a codebase' and explains when to use each variant. It also tells when to fall back to grep for blind spots and names alternative tools for subsequent steps.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
readARead-only
Return the source code for one or more nodes, sliced from their files by the graph's line spans. Use after find/impact to read the exact code without grepping — comma-separate several node names to read the whole ranked set in a single call. Each node is a code block headed by its qname and path:start-end, plus a context: footer with structural facts the source alone doesn't show: HTTP method, cross-stack callers, covering tests, and intent/decision/constraint cells when present.
| Name | Required | Description | Default |
|---|---|---|---|
| node | Yes | Node name or qname to read. Comma-separate several (e.g. the top-ranked nodes from `find`/`impact`) to slice them all in one call. | |
| budget | No | Max chars in the result (shared across all nodes when several are given). 0 = no cap. | |
| context_lines | No | Lines of padding above and below the node's span. Default 0. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true, and description adds that it slices from files and returns structured blocks with qname, path, and a context footer. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single paragraph with good front-loading of purpose. It is information-dense but not overly verbose. Could potentially be broken into shorter sentences for readability, but no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the read-only nature and existing annotations, the description fully explains what the tool does, when to use it, how to use parameters, and what the output contains (including structural facts). No gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but description adds valuable context: comma-separating nodes, budget shared across nodes, context_lines as padding. Also ties parameters to use case (after find/impact).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly describes returning source code for nodes, sliced by line spans. Distinguishes itself from sibling tools like find/impact by stating it should be used after those to read code, not to find it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to use after find/impact, and gives usage example like comma-separating node names. Could be more explicit about when not to use (e.g., for non-code files), but the context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refreshA
(Re)build the structural graph with tree-sitter AST parsing across 20 languages, running the cross-stack resolvers (HTTP, gRPC, GraphQL, WebSocket, queues, events, CLI). Incremental by default — only changed files re-parse — so it's cheap to call after edits; set full=true to force a clean reparse. Accepts a local path or a git URL (cloned on demand). Call after a major refactor; routine edits are picked up automatically by the file watcher.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | Force a full reparse instead of reusing the per-file parse cache. Default False (incremental — only changed files re-parse, so this is cheap after edits). | |
| repo_path | No | Path or git URL to (re)scan. Blank = the repo the server is serving. A different path/URL retargets the server at it. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (readOnlyHint=false, openWorldHint=true), the description adds behavioral details: incremental re-parsing by default, cheap after edits, full=true for clean reparse, and support for local path or git URL with on-demand cloning. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (under 100 words), front-loaded with the tool's primary purpose, and each sentence adds value. Well-structured for quick understanding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (graph rebuilding, 20 languages, multiple resolvers) and that an output schema exists, the description adequately covers core behavior, parameters, and usage context. Could be more detailed about output, but output schema fills that gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description rephrases schema info for both parameters (full and repo_path) but does not add significant new meaning beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool rebuilds a structural graph using tree-sitter AST parsing across 20 languages and runs cross-stack resolvers. It distinguishes from siblings like find and trace by focusing on graph regeneration after major refactors.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly advises calling after a major refactor and notes that routine edits are handled automatically by the file watcher. It does not explicitly mention when not to use or list alternative sibling tools, but provides clear usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
traceARead-only
Follow the code across boundaries. One argument: trace a feature end-to-end — the ordered path from entry through the stack, each hop labelled with its mechanism (call / HTTP / queue / event / data), crossing service boundaries (frontend→backend). Two arguments: the shortest path between two specific nodes, hop by hop. This is where the graph beats reading many files — it knows the cross-stack links grep can't see.
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | Max hops for the cross-stack feature trace. Default 6. | |
| budget | No | Max chars in the result. 0 = no cap. | |
| to_node | No | Optional target node. Given → shortest path from_node→to_node. Blank → trace `from_node` as a feature across the stack. | |
| from_node | Yes | A feature/keyword to trace end-to-end (one arg), OR the start node when tracing a path to `to_node`. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, so the agent knows it's a read operation. The description adds behavioral detail: the tool traverses service boundaries, labels mechanisms (call/HTTP/queue/event/data), and behaves differently with one vs two arguments. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise: four sentences, front-loaded with the purpose, each sentence adding value (action, mode distinction, justification). No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 4 parameters, an output schema, and moderate complexity, the description covers the core behavior and use cases. It does not detail node types or mechanism labels, but provides enough for an agent to select the tool appropriately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, baseline 3. The description adds meaning by explaining the dual behavior of from_node (feature or start node) and to_node (target node for shortest path), which complements the schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool traces code across boundaries, explains one-argument (feature end-to-end) and two-argument (shortest path) modes, and distinguishes from siblings like find and impact by emphasizing cross-stack links that grep cannot see.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains that the tool is used for tracing features end-to-end or finding paths between nodes, and contrasts with reading files/grep. It does not explicitly state when not to use it versus specific siblings, but the context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
15 tool updates
v0.4.20- Removed
activate - Removed
dense_text - Changed
find4 fields changed- added
Input schema / properties / expandAdded value: +{ + "default": false, + "description": "Return the relevant neighbourhood (Personalized-PageRank ranked) around the matches, not just the matches themselves. Use to discover what surrounds a seed.", + "title": "Expand", + "type": "boolean" +} - added
Input schema / properties / kindAdded value: +{ + "default": "auto", + "description": "Force the signal type: 'symbol', 'stacktrace', 'test', 'diff', or 'auto' (sniff the shape).", + "title": "Kind", + "type": "string" +} - changed
Input schema / properties / query / descriptionPrevious value: -"Node name or qname pattern to search for. Supports partial matching."New value: +"What to locate: a symbol/keyword (e.g. `User`, `checkout`), OR a failure signal — paste a raw stacktrace, a failing-test id (path::test), or a unified diff / changed-file list." - added
Input schema / properties / top_kAdded value: +{ + "default": 20, + "description": "Max results. Default 20.", + "maximum": 100, + "minimum": 1, + "title": "Top K", + "type": "integer" +}
- Removed
flow - Removed
generate - Removed
graph_view - Changed
impact8 fields changed- changed
Input schema / properties / depth / defaultPrevious value: -3New value: +4 - changed
Input schema / properties / depth / descriptionPrevious value: -"How many hops to traverse. Default 3."New value: +"How many hops to fan out. Default 4." - changed
Input schema / properties / direction / defaultPrevious value: -"downstream"New value: +"both" - changed
Input schema / properties / direction / descriptionPrevious value: -"'downstream' (what it affects) or 'upstream' (what it depends on)."New value: +"'forward' (what it affects), 'backward' (what it depends on / who uses it), or 'both'. (Aliases: downstream=forward, upstream=backward.)" - added
Input schema / properties / live_onlyAdded value: +{ + "default": false, + "description": "Drop nodes not reachable from any entry point (likely-dead code). Default False = show all, marking dead ones ⊘.", + "title": "Live Only", + "type": "boolean" +} - removed
Input schema / properties / modeRemoved value: -{ - "default": "table", - "description": "'table' (tiered list) or 'prose' (primed prose for LLM context).", - "title": "Mode", - "type": "string" -} - changed
Input schema / properties / nodes / descriptionPrevious value: -"One or more node names/qnames, comma-separated. A diff touching N files is one call."New value: +"One or more node names/qnames, comma-separated. A diff touching N symbols is one call." - added
Input schema / properties / top_kAdded value: +{ + "default": 0, + "description": "Cap the ranked result. 0 = no cap.", + "maximum": 200, + "minimum": 0, + "title": "Top K", + "type": "integer" +}
- Removed
locate - Removed
neighbours - Added
orient - Changed
read2 fields changed- changed
Input schema / properties / budget / descriptionPrevious value: -"Max chars in the result. 0 = no cap."New value: +"Max chars in the result (shared across all nodes when several are given). 0 = no cap." - changed
Input schema / properties / node / descriptionPrevious value: -"Node name or qname to read the source for."New value: +"Node name or qname to read. Comma-separate several (e.g. the top-ranked nodes from `find`/`impact`) to slice them all in one call."
- Added
refresh - Removed
reload - Removed
status - Changed
trace6 fields changed- added
Input schema / properties / budgetAdded value: +{ + "default": 0, + "description": "Max chars in the result. 0 = no cap.", + "minimum": 0, + "title": "Budget", + "type": "integer" +} - added
Input schema / properties / depthAdded value: +{ + "default": 6, + "description": "Max hops for the cross-stack feature trace. Default 6.", + "maximum": 12, + "minimum": 1, + "title": "Depth", + "type": "integer" +} - changed
Input schema / properties / from_node / descriptionPrevious value: -"Starting node name or qname pattern."New value: +"A feature/keyword to trace end-to-end (one arg), OR the start node when tracing a path to `to_node`." - added
Input schema / properties / to_node / defaultAdded value: +"" - changed
Input schema / properties / to_node / descriptionPrevious value: -"Target node name or qname pattern."New value: +"Optional target node. Given → shortest path from_node→to_node. Blank → trace `from_node` as a feature across the stack." - changed
Input schema / requiredPrevious value: -[ - "from_node", - "to_node" -]New value: +[ + "from_node" +]
10 tool updates
v0.4.19- Changed
activate3 fields changed- added
Input schema / properties / budgetAdded value: +{ + "default": 0, + "description": "Max chars in the result. 0 = no cap.", + "minimum": 0, + "title": "Budget", + "type": "integer" +} - added
Input schema / properties / modeAdded value: +{ + "default": "table", + "description": "'table' (ranked list) or 'prose' (primed prose for LLM context).", + "title": "Mode", + "type": "string" +} - added
Input schema / properties / profileAdded value: +{ + "default": "default", + "description": "Edge-weight preset: 'default', 'repair' (up-weights call/data), 'review', or 'onboard' (up-weights entry/module).", + "title": "Profile", + "type": "string" +}
- Changed
dense_text2 fields changed- added
Input schema / properties / budgetAdded value: +{ + "default": 0, + "description": "Max chars in the result. 0 = default cap (~50k, or REPO_GRAPH_DENSE_MAX_CHARS).", + "minimum": 0, + "title": "Budget", + "type": "integer" +} - added
Input schema / properties / seedAdded value: +{ + "default": "", + "description": "Optional node/qname to scope the map around (its activated neighbourhood). Blank = whole graph.", + "title": "Seed", + "type": "string" +}
- Changed
find1 field changed- added
Input schema / properties / budgetAdded value: +{ + "default": 0, + "description": "Max chars in the result. 0 = no cap.", + "minimum": 0, + "title": "Budget", + "type": "integer" +}
- Changed
flow1 field changed- added
Input schema / properties / budgetAdded value: +{ + "default": 0, + "description": "Max chars in the result. 0 = no cap.", + "minimum": 0, + "title": "Budget", + "type": "integer" +}
- Changed
generate1 field changed- added
Input schema / properties / incrementalAdded value: +{ + "default": true, + "description": "Reuse the per-file parse cache so unchanged files skip re-parsing (default True). Set False to force a full reparse.", + "title": "Incremental", + "type": "boolean" +}
- Changed
impact6 fields changed- added
Input schema / properties / budgetAdded value: +{ + "default": 0, + "description": "Max chars in the result. 0 = no cap.", + "minimum": 0, + "title": "Budget", + "type": "integer" +} - changed
Input schema / properties / direction / descriptionPrevious value: -"'downstream' or 'upstream'."New value: +"'downstream' (what it affects) or 'upstream' (what it depends on)." - added
Input schema / properties / modeAdded value: +{ + "default": "table", + "description": "'table' (tiered list) or 'prose' (primed prose for LLM context).", + "title": "Mode", + "type": "string" +} - removed
Input schema / properties / nodeRemoved value: -{ - "description": "Node name or qname pattern to analyze.", - "title": "Node", - "type": "string" -} - added
Input schema / properties / nodesAdded value: +{ + "description": "One or more node names/qnames, comma-separated. A diff touching N files is one call.", + "title": "Nodes", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "node" -]New value: +[ + "nodes" +]
- Added
locate - Changed
neighbours1 field changed- added
Input schema / properties / budgetAdded value: +{ + "default": 0, + "description": "Max chars in the result. 0 = no cap.", + "minimum": 0, + "title": "Budget", + "type": "integer" +}
- Added
read - Changed
reload1 field changed- added
Input schema / properties / incrementalAdded value: +{ + "default": true, + "description": "Reuse the per-file parse cache so unchanged files skip re-parsing (default True). Set False to force a full reparse.", + "title": "Incremental", + "type": "boolean" +}
14 tool updates
v0.1.3- Added
activate - Removed
bloat_report - Removed
cost - Added
dense_text - Added
find - Changed
flow1 field changed- added
Input schema / properties / feature / descriptionAdded value: +"Feature name or keyword to match against entry points. Case-insensitive, supports partial matching."
- Changed
generate1 field changed- added
Input schema / properties / repo_path / descriptionAdded value: +"Absolute path to the repository to scan. Defaults to the repo the server was started with."
- Changed
graph_view5 fields changed- added
Input schema / properties / depth / descriptionAdded value: +"Tree depth. Default 2." - added
Input schema / properties / depth / maximumAdded value: +5 - added
Input schema / properties / depth / minimumAdded value: +1 - removed
Input schema / properties / featureRemoved value: -{ - "default": "", - "title": "Feature", - "type": "string" -} - added
Input schema / properties / node / descriptionAdded value: +"Node name or qname to render as a tree. Leave blank for full overview."
- Removed
hotspots - Changed
impact5 fields changed- added
Input schema / properties / depth / descriptionAdded value: +"How many hops to traverse. Default 3." - added
Input schema / properties / depth / maximumAdded value: +10 - added
Input schema / properties / depth / minimumAdded value: +1 - added
Input schema / properties / direction / descriptionAdded value: +"'downstream' or 'upstream'." - added
Input schema / properties / node / descriptionAdded value: +"Node name or qname pattern to analyze."
- Removed
minimal_read - Changed
neighbours1 field changed- added
Input schema / properties / node / descriptionAdded value: +"Node name or qname pattern to inspect."
- Removed
split_plan - Changed
trace2 fields changed- added
Input schema / properties / from_node / descriptionAdded value: +"Starting node name or qname pattern." - added
Input schema / properties / to_node / descriptionAdded value: +"Target node name or qname pattern."
13 tool updates
v0.1.2- First observed
bloat_report - First observed
cost - First observed
flow - First observed
generate - First observed
graph_view - First observed
hotspots - First observed
impact - First observed
minimal_read - First observed
neighbours - First observed
reload - First observed
split_plan - First observed
status - First observed
trace
TDQS
Scored across 6 tools
Each tool has a distinct purpose: find resolves text to nodes, impact shows dependency blast radius, orient provides overviews, read retrieves source code, refresh rebuilds the graph, and trace follows cross-boundary flows. There is no overlap in functionality.
All tool names are single-word, lowercase imperatives (find, impact, orient, read, refresh, trace) following a consistent verb pattern without any mixing of conventions.
With 6 tools, the server covers all necessary operations for code graph analysis—build, explore, search, read, and trace—without being excessive or insufficient.
The tool set covers the full lifecycle: building the graph (refresh), getting oriented (orient), finding nodes (find), reading code (read), analyzing impact (impact), and tracing flows (trace). There are no obvious gaps.
Maintenance
Related MCP Connectors
Code intelligence platform for AI agents. 20 tools for architecture, security & impact analysis.
Codebase intelligence for AI agents — dead code, blast radius, ownership.
Give your AI agent a persistent map of your project's structure, dependencies, and bugs.
Codebase graphs, caller impact analysis, and recorded project context for AI coding agents.
Related MCP Servers
- AlicenseAqualityAmaintenanceA Model Context Protocol (MCP) server that helps large language models index, search, and analyze code repositories with minimal setup14548 PyPI1,004MIT
- AlicenseAqualityAmaintenanceA fully featured coding agent that uses symbolic operations (enabled by language servers) and works well even in large code bases. Essentially a free to use alternative to Cursor and Windsurf Agents, Cline, Roo Code and others.2942,914 PyPI29,226MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that transforms codebases into knowledge graphs using Neo4J, enabling AI assistants to understand code structure, relationships, and metrics for more context-aware assistance.28MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to understand and navigate codebases through structural analysis. Provides code mapping, symbol search, and impact analysis using ast-grep for accurate parsing of Python, JavaScript, TypeScript, and Go projects.452MIT