
repo2graph
io.github.Srinivasan-78Published by GitHub account Srinivasan-78v5.0.0Updated Nov 1, 2026
Ask a codebase a question, get back the source that answers it — every block cited to file:line.
Overview
Local MCP server that indexes a codebase into a call/import graph and returns cited, token-bounded source answers to an assistant.
- What you can do
- Search a repository with BM25 plus one graph hop and get source blocks headed by file:line citations
- Inspect a symbol's callers, callees, base classes and defining file, with a confidence per edge
- Walk reverse dependencies of a symbol (blast radius) bounded by hop count and visit cap
- Map the repository and keep every reply under a hard token ceiling (12k tokens over MCP)
- Explain why an edge exists or why a block was retrieved
- When to use it
- Useful when an assistant must answer cross-file structural questions about a repository — who calls what, what depends on a symbol, what tests cover a module — and you want cited answers that fit a fixed context budget. For single-file keyword lookups the README says grep is the better tool.
- Requirements
- Runs locally over stdio as a Python package (uvx, Python 3.11–3.14); the repository must be indexed first with the build command. No API key, model, language server or database is needed. Linux needs glibc 2.34+; Alpine/musl and older distros are unsupported. Optional dense retrieval needs extra packages and downloads a model.
Installation
In SourceWeft
- Open repo2graph in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
repo2graph
Cited, token-bounded answers about a codebase, for coding agents and CI.
[repo2graph building a map of a repository, then answering a question about it, in a terminal]Ask a repository a question and get back the source that answers it. Every block is headed
[cite: path:start-end], and the whole reply fits under a token ceiling that the tool enforces.
One tree-sitter pass records who calls whom, who imports what, and which files keep changing
together in git. Retrieval starts from BM25 matches and follows those links.
It needs no model, no API key, no language server and no database. Building, querying and the
MCP server make no network calls; the only exceptions are rag --answer (opt-in, sends the pack
to an LLM), repo2graph github and a rag/query target given as a GitHub spec (both clone a
repository), and --vectors/embed (download the embedding model on first use). Parsers are part of that promise:
tree-sitter-language-pack is pinned below 1.0 so every grammar arrives compiled into the
installed wheel, rather than being downloaded on first parse — see
SECURITY.md. Use it from the CLI, as an MCP server in Claude Code or Cursor, or as a GitHub Action.
Try it
Give an agent the same thing over MCP:
Cursor, Claude Desktop and other clients: docs/mcp.md. Step-by-step with expected
output: demo in docs/cli.md. What it produces on
thirteen well-known repositories — Django, FastAPI, React, Kubernetes, Linux and others, each at a
pinned commit with the command to reproduce it: examples/.
In VS Code, the extension in editors/vscode/ (a preview, built from
source) shows the callers, callees, base classes and co-changed files of the symbol at the cursor,
through the same MCP server.
Is it better than grep?
On cross-file structural questions, yes. On single-file lexical queries, no — grep is the
better tool. Both halves are measured on 40 lexical and 40 structural questions about Flask,
requests, FastAPI and Hono that repo2graph was not tuned against, scored against the
definitions that answer them, every retriever held to the same token budget
(method, full tables and diagnosis; raw rows in
results_holdout_final.json).
Where repo2graph wins: cross-file structural questions
grep structurally cannot traverse dependency edges, compute reverse call closures, or follow cross-module delegation. On questions whose evidence provably spans a cross-file graph edge:
The graph is what does it, and that is the comparison that matters: expansion adds +5/+12/+24 pp over the same retriever with expansion switched off. Against grep the margin is +15/+39/+41 pp — it widens with budget rather than closing, because grep has no edge to follow however much room it is given. It also gets there for fewer tokens than grep at every budget, by 7, 7 and 398 mean tokens, because a cited definition is a smaller thing to return than a window around every textual hit.
Where grep wins: single-file lexical questions
On purely lexical questions where the evidence sits in a single file, text search is grep's
optimum, and this gap is real: −11/−19/−14 pp. We have not closed it. The remaining cause looks
like vocabulary mismatch rather than ranking — a question that says "datetime" does not match
code that says "timestamp" — which is why the
dense-vector path closes it to −2 pp at 8,000
tokens and more BM25 tuning has not. That path needs a downloaded model, so it is opt-in
(pip install "repo2graph[rag]") and the zero-dependency default stays the default.
That extra pulls PyTorch, which on Linux brings the NVIDIA CUDA wheels (several GB); the model is
fetched from Hugging Face on first use and its own licence and training data are yours to review
before you adopt it. Once it is cached, set HF_HUB_OFFLINE=1 so later runs make no request.
If that is too much to carry — on a CI runner, say — pip install "repo2graph[rag-static]" and
--embed-backend static get dense retrieval without torch: model2vec is a token→vector table
plus mean pooling, so inference is numpy, and it costs ~60 MB of packages and a ~31 MB model.
It is a different model (256-dim against 384), not a cheaper way to run the same one, so expect
it to retrieve differently — the figures above are the rag backend's. Pass the same
--embed-backend on the query side as you did to embed: the recorded model id is prefixed per
backend, so a mismatch is refused rather than silently fused.
Where repo2graph wins for agents: fewer turns
In simulated agent workflows (search → read → answer, via scripts/agent_eval.py). No
model is in the loop — the "agent" is a deterministic policy over real ripgrep and a real index:
Four times the structural success rate, and it reaches an answer in one or two turns where grep needs three. The turn count is the number that moved most — structural went 3.1 to 1.9 — because sharper seed ranking puts the answer in the first pack more often, and a turn saved is worth more to an agent than a token saved. It is not cheap: 4.4× grep's tokens on the structural set and 2.8× on the lexical one, and grep wins precision per read on both. repo2graph buys recall and turns with context; the budget-matched comparison is the single-shot tables above.
For completeness, the 35+10 question set this page used to report — visible since the first version of these tables and therefore a regression set, not evidence — now reads 44/63/80% lexical against grep's 35/61/72%, and 60/80/100% structural against grep's 20/20/70%. Those are the better-looking numbers, which is exactly why the held-out set is the one quoted above.
What it does do that grep doesn't:
- Relationships in one hop.
repo_neighboursreturns a symbol's callers, callees, base classes and defining file, each with a line number. Every edge carries aconfidence: a name that could mean several definitions is markedambiguousand priced at1/n, not guessed. - A hard ceiling. The pack is measured, clamped and re-measured before it's returned (12k tokens max over MCP), so an agent can't flood its own context through this tool.
- Reverse closures from the graph.
repo_blast_radiuswalks what depends on a symbol, bounded by hop count and visit cap, with a citation per edge.
How it compares with Serena, Aider's repo map, CodeGraphContext, code-graph-rag, Sourcegraph, Cursor's index and Claude Code's own search, and with the dependency-graph tools Madge, dependency-cruiser and CodeSee, including when to use those instead: docs/comparison.md. Looking for a Sourcetrail alternative? It is not a drop-in replacement — there is no interactive desktop UI — and the comparison says what it does instead.
Five questions to start with
GitHub Action
@v5 follows every 5.x release; pin an exact tag (@v5.0.0) to upgrade by hand. The Action never
calls an LLM. Inputs and outputs: docs/cli.md.
Commands
Full flags: docs/cli.md. Python API: docs/python-api.md. Build cost up to 50,000 files: benchmarks/perf/README.md.
What it can't do
- Resolve calls by type. Calls are matched by name, scoped by class, file, imports and
directory.
x.get()on a receiver of unknown type is recorded as a low-confidence guess, not a fact. For exact references, use a language-server tool, or handbuild --scip index.scipa SCIP index (fromscip-python,scip-typescript, ...) to make the calls and bases it covers exact; see docs/architecture.md. - See dynamic dispatch, reflection or computed imports. A missing edge doesn't prove that no call exists.
- Cross language boundaries (Python calling C++ through bindings).
- See a route that is registered by a call.
build --framework-edgeslinks decorator-declared routes to their handlers (FastAPI, Flask, Starlette, Sanic, NestJS) and adds a node per endpoint, soGET /users/{id}is a thing you can ask about. Express, Hono and Django'surlpatternsregister with a call instead —app.get("/x", handler)— where the handler is an argument and often an inline function, and those get no edge.
Symbols, calls and classes are extracted for Python, JS, TS, TSX, Go, Rust, Java, Ruby, C, C++,
C#, PHP, Kotlin, Swift, Scala, Bash, Lua, Objective-C and HCL (Terraform), plus the <script> blocks
of Vue and Svelte components and the code cells of Jupyter notebooks. Every other file is still
indexed as text. The
specific cases that defeat it — reflection dispatch, string-keyed registries, barrel re-exports —
are pinned as known failures in the
synthetic regression suite, and
per-language coverage is scored, unevenly, in
docs/architecture.md §4.
Two of those nineteen are benchmarked on real repositories: Python (Flask, requests, FastAPI) and TypeScript (Hono). Treat the rest as parsed-and-unmeasured. That is not a formality — the retrieval benchmark found two parse gaps in the one TypeScript repository as soon as it looked, one of which was hiding Hono's entire public API, and neither would have been visible without a real repository to ask questions about.
Status
The 3.x CLI, MCP tools and output schema follow semver. Default paths run locally, send no telemetry and exclude secrets from agent replies unconditionally (what never leaves your machine, how credential files are excluded, reporting a vulnerability). A Dockerfile for read-only, non-root local builds is provided (.github/SECURITY.md).
Platform & Environment Requirements
Run repo2graph doctor to diagnose environment and platform support.
Security & Maintenance Posture
- Single maintainer: repo2graph is developed and maintained by a single author (@Srinivasan-78).
- Automated gates: Pull requests must pass automated CI checks (ruff, mypy, multi-OS test matrix, synthetic regression benchmarks).
- Review policy: Pull requests require 0 third-party review approvals to merge to
main. - Commit signing: Commit signing is not currently enforced on
main. - Integrity: Releases are published to PyPI with provenance attestations.
uv.lockpins every dependency by hash for CI and contributors (uv sync --frozen); a plainpip install repo2graphresolves its own versions within the ranges inpyproject.tomland does not read it.
Contributing
Branch from develop. Start with .github/CONTRIBUTING.md and
docs/architecture.md. The most useful contribution right now is new
questions for the retrieval benchmark, especially on repositories
you know well. All docs: architecture, CLI,
MCP, Python API, comparison.
MIT licensed.
Source: README.md at commit 2a30c17
Tools
0Version history
10- v5.0.0LatestNov 1, 2026
- v4.1.0Oct 23, 2026
- v4.0.0Oct 12, 2026
- v3.0.0Oct 6, 2026
- v2.2.0Sep 27, 2026
- v2.1.0Sep 24, 2026
- v2.0.0Sep 22, 2026
- v1.6.0Sep 20, 2026
- v1.5.4Sep 18, 2026
- v1.5.1Sep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts