code-graph
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@code-graphfind callers of GET /api/users"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
code-graph
A static connection graph of the Example platform. It scans app-web
(Laravel + React) and app-services (NestJS + Go + Python) and records how the
code is wired together — which files call which HTTP routes, which tables and
queues they read or write, and what they import — into an embedded
Kùzu graph database you can query from the terminal, from
Claude Code (MCP), or with raw Cypher.
It answers the cross-repo reachability questions that are otherwise a multi-file grep-and-guess exercise:
Who actually calls
GET /resource-a?What code touches the
table_btable?How does the web frontend reach a backend service?
Quickstart
uv sync # install (Python 3.11–3.13)
uv run code-graph scan # build graph.kuzu from the sibling repos
uv run code-graph stats # node + per-edge-type counts
uv run code-graph query "callers:/resource-a" # who calls a routeBy default scan looks for app-web and app-services as siblings of this
project (../app-web, ../app-services) and reads route data from
../route-inventory/dist/openapi.json. Point it at your own repos with env vars
instead of editing the code:
export CODE_GRAPH_REPOS="/path/to/web-repo,/path/to/services-repo" # or name=path pairs
export CODE_GRAPH_OPENAPI="/path/to/route-inventory/dist/openapi.json"Missing repos are skipped, not errored. The scan is a static snapshot — re-run it after any change you want reflected. A full scan of two large repos takes roughly 15–20 minutes.
Each scan writes two gitignored artifacts at the project root: graph.kuzu
(the database) and parser-report.txt (scan counts).
The three interfaces
CLI
uv run code-graph scan
uv run code-graph stats
uv run code-graph query "<preset-or-cypher>"
uv run code-graph export --format html|graphml|dotquery takes one argument. If it looks like <preset>:<arg> it runs a preset;
otherwise it runs as raw Cypher.
Preset | Finds |
| files that issue an HTTP call to a matching route |
| outbound edges from matching nodes |
| code that reads/writes a table or uses a queue |
| one-hop neighbours of matching nodes |
| nodes whose id/name contains the text |
export writes graph.{html,graphml,dot} (all gitignored, regenerated on
demand). graph.html is a self-contained offline viewer; GraphML/DOT are for
external graph tools.
MCP (in Claude Code)
CODE_GRAPH_DB=/home/ohad/sh/projects/code-graph/graph.kuzu uv run code-graph-mcpExposes the query layer over stdio as seven read-only tools: find_callers,
what_calls, path_between, who_touches, neighbors, search_nodes,
run_cypher. The server refuses to start until graph.kuzu exists — run scan
first.
Raw Cypher
The CLI query command (when the argument isn't a preset) and the MCP
run_cypher tool run arbitrary Cypher against the model below. The database is
opened read-only at the Kùzu engine level, and run_cypher additionally
rejects write/DDL keywords before executing — the graph cannot be mutated
through either path.
uv run code-graph query "MATCH (f)-[c:HTTP_CALL]->(r) WHERE r.kind='route' RETURN f.id, r.id LIMIT 20"Graph model
One Node table (discriminated by kind) and one relationship table per edge
type — the idiomatic Kùzu shape, so filtering is a kind predicate and every
traversal is a single relationship type.
Node | Represents | Example |
| a source file |
|
| an HTTP route (seeded from route-inventory) |
|
| a database table |
|
| a Redis stream / channel |
|
| an imported package/module |
|
| an HTTP call that didn't resolve to a known route |
|
Edge type | Meaning |
|
| file → route it calls (or | 0.8 resolved / 0.5 external |
| file → table it reads/writes (Laravel | 0.7 |
| file → queue/stream it publishes/consumes | 0.6 |
| file → package or file it imports | 0.9 |
Every edge carries source_file, line, and raw (the matched snippet), plus
mode (read/write/unknown) on DB_ACCESS. confidence describes how the
match was made, not a statistical accuracy — treat low-confidence and
external edges as leads to verify against source_file:line, not ground truth.
How it works
Parsing. tree-sitter plus targeted regex over PHP, TS/TSX, JS/JSX, Go, and Python. No type resolution or control-flow analysis, and deliberately recall-biased — it favours catching real edges over avoiding every false positive.
Routes come from route-inventory. Route nodes aren't discovered by parsing; they're loaded from
route-inventory's generateddist/openapi.json.HTTP_CALLedges resolve a call's(METHOD, path)against that catalog (with a suffix-match fallback and same-origin tie-break); unmatched calls becomeexternalnodes.What's scanned. Both repos are walked recursively for the source extensions above, excluding
node_modules,vendor,dist,build,.git,.claude(covers.claude/worktrees),.next,coverage. Symlinked directories are followed once, guarded by resolved real path.
Example output
From a scan of the real app-web + app-services trees (2026-07-16):
4248 files scanned → 10108 nodes, 0 parse errors
nodes: file 6653 · package 1594 · route 1559 · db_table 261 · external 41
edges: IMPORTS 21212 · DB_ACCESS 794 · HTTP_CALL 189 · QUEUE 0 (22195 total)$ uv run code-graph query "callers:/system/health-check-full"
[
{
"caller": "file:app-web/app-frontend/src/components/callRecord/StatusCheck.jsx",
"route": "route:service-b:GET:/system/health-check-full",
"line": 168,
"confidence": 0.8
}
]IMPORTS dwarfs the other edge types by design — one edge per import statement
across thousands of files, versus per-call-site matches elsewhere.
Known limitations
Minified build bundles add noise.
app-web/public/js/*hashed Vite/webpack output is currently scanned, producing some spuriousHTTP_CALLedges and file nodes. Excluding build output at the walker level is a planned follow-up.Relative imports aren't resolved. A relative specifier (
./x,../y) becomes a literalfile:node id rather than being resolved to the real file it points at, so a share offilenodes are synthetic import targets. Bare package imports resolve correctly.DB_ACCESS.modeisunknownfor PHP. Only the TS/Kysely path (selectFrom/insertInto/…) infers read vs. write; Laravel$table/DB::tablehits have no per-call-site signal, somodeis leftunknownrather than guessed.Queues need string literals.
QUEUE_*edges are only created for string-literal stream/channel names; Kafka-stylesubscribe(variable)calls aren't named. (QUEUE = 0on the current tree is accurate, not a miss.)
Development
uv run pytest # 42 testssrc/code_graph/
cli.py CLI entry point (scan / stats / query / export)
mcp_server.py MCP entry point (code-graph-mcp)
config.py ScanConfig: sibling-repo paths, exclude list, db path
model.py Node/Edge dataclasses + stable id helpers
catalog.py RouteCatalog: loads route-inventory OpenAPI, resolves calls
walker.py source-file walker (language detection, excludes, symlink guard)
parsing.py tree-sitter parse cache + AST helpers
matchers/ HTTP_CALL / DB_ACCESS / QUEUE_PUB+SUB / IMPORTS extraction
graph/
loader.py Kùzu schema + CSV bulk loader
queries.py GraphDB: read-only presets + guarded raw-Cypher escape hatch
scan.py orchestrates walker → matchers → loader, writes parser-report.txt
report.py parser-report.txt writer
skill/SKILL.md Claude Code skill definition
docs/superpowers/ design spec + implementation planThis server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/osadan/code-graph'
If you have feedback or need assistance with the MCP directory API, please join our Discord server