# Polycodegraph

> Language-agnostic code graph builder, analyzer, PR risk reviewer, and MCP server for Claude Code.

- **Type:** MCP server
- **Install:** `agentstack add mcp-smochan-polycodegraph`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [smochan](https://agentstack.voostack.com/s/smochan)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [smochan](https://github.com/smochan)
- **Source:** https://github.com/smochan/polycodegraph

## Install

```sh
agentstack add mcp-smochan-polycodegraph
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# polycodegraph

[](https://github.com/smochan/polycodegraph/actions/workflows/ci.yml)
[](https://pypi.org/project/polycodegraph/)
[](https://www.python.org/downloads/)
[](LICENSE)
[](#mcp-tools-18-total)

> Parse any repo into a queryable code graph. Trace one parameter from a frontend fetch through every layer to the SQL query. Powers Claude Code, Cursor, and Windsurf via MCP — so your AI assistant reads focused context instead of the entire codebase.

*Same Claude Sonnet 4.6. Same 10 questions about two real repos (codegraph itself + FastAPI). Only the registered MCP server changes. Reproduce with `codegraph bench agent`, raw data in [`bench/RESULTS_AGENT_LATEST.md`](bench/RESULTS_AGENT_LATEST.md).*

---

## Quick start

```bash
pip install polycodegraph     # the PyPI distribution name
codegraph init                # the CLI binary + Python module + MCP server are all `codegraph` (see footnote ↓)
codegraph build               # parse repo → .codegraph/graph.db
codegraph serve               # web dashboard at http://127.0.0.1:8765
```

That's it. Three commands and you have a queryable graph, a 3D dashboard, and an MCP server your IDE can talk to.

### Languages + frameworks (today)

|  | Today (v0.1.0) | Roadmap |
|---|---|---|
| **Languages** | Python · TypeScript · JavaScript · TSX / JSX · Go | Java, Rust, C# (v0.3); Ruby, PHP later |
| **HTTP frameworks** | FastAPI · Flask · aiohttp · Express · NestJS | Spring Boot, Django views, ASP.NET, Rails (alongside their language) |
| **ORMs / DBs** | SQLAlchemy · Prisma (partial) | Django ORM, GORM, Diesel, ActiveRecord (alongside their language) |
| **Frontend fetch** | `fetch` · axios · SWR · React Query · generic `apiClient.*` | RTK Query, Apollo |
| **24 framework decorators** | FastAPI · Flask · aiohttp · Celery · pytest · MCP · Click · Typer · Django · SQLAlchemy · NestJS · … | Spring annotations, .NET attributes |

Adding a new language is a single tree-sitter parser module + fixture file (~3 hours — see `codegraph/parsers/go.py` for the v1 template). PRs welcome.

---

## The MOAT — one graph, everything on top

polycodegraph has exactly one opinion: **build the right graph, and every interesting feature falls out for free.**

The inputs that feed the graph go beyond imports and call edges. polycodegraph reads tree-sitter parses for **Python, TypeScript, JavaScript, and Go**; captures **every call-site's arguments as text**; recognizes **24 framework decorators** so FastAPI / Flask / Celery / pytest / Click / MCP / Django / SQLAlchemy handlers are never confused with dead code; detects **routes** (`@app.get("/x")`) and **frontend fetches** (`fetch`, `axios`, `useSWR`, `useQuery`); and **stitches URLs across the stack** (`/{id} ↔ ${id} ↔ :id`) so it can trace a fetch all the way to its handler.

The outputs that come *for free* once the graph is right:

Decorator-aware dead code, role classification (HANDLER / SERVICE / COMPONENT / REPO), blast radius, cycles, untested-function detection, an end-to-end cross-stack trace with rename annotations, a 3D focus-mode dashboard, a Learn Mode lifecycle modal, local embeddings for semantic + hybrid search, an 18-tool MCP server, and a PR-review CI that graph-diffs the branch against `main`.

One SQLite file. No daemon. No network. Travels with your git branch.

---

## How it works

```text
  ┌─────────────────────────────────────────────────────┐
  │  tree-sitter parsing                                │
  │  (Python, TS/JS, TSX, JSX, Go)                      │
  └─────────────────────────────────────────────────────┘
                        ↓
  ┌─────────────────────────────────────────────────────┐
  │  Cross-file resolution (R1, R2, R3)                 │
  │  ✓ per-name imports  ✓ relative imports             │
  │  ✓ constructor calls ✓ decorators                   │
  │  ✓ self.X.Y chains  ✓ fresh instances               │
  └─────────────────────────────────────────────────────┘
                        ↓
  ┌─────────────────────────────────────────────────────┐
  │  SQLite graph (nodes + edges)                       │
  │  DF0: call-site arguments                           │
  │  DF1: routes (FastAPI, Flask, aiohttp)              │
  │  DF2: fetches (fetch, axios, SWR, useQuery)         │
  │  DF3: URL stitching (/{id} ↔ ${id} ↔ :id)          │
  │  DF4: end-to-end trace (fetch→handler→service→DB)   │
  └─────────────────────────────────────────────────────┘
                   ↙            ↓            ↘
            CLI tools       Web dashboard      MCP server
         (graph, roles,    (3D focus view,  (18 tools for
         cycles, dead      architecture,     Claude Code,
         code, untested)   learn mode)       Cursor, etc.)
```

---

## What you can do

| Screenshot | Use case |
|:---:|:---|
|  | **3D focus view** — Pick any function, trace its real downstream call tree, expand or collapse ancestors and descendants inline. Shown: `build_dashboard_payload` with its 15 direct callees — `find_dead_code`, `find_cycles`, `build_hld`, `find_hotspots`, `compute_metrics`, and the rest of the analysis stack. |
|  | **Architecture map** — Handlers grouped by role (HANDLER, SERVICE, COMPONENT, REPO), infrastructure components (DB, cache, queue), and their connections at a glance. Click a handler → Learn Mode opens a request-lifecycle modal: TCP → TLS → HTTP → query → response. |
|  | **DF4 cross-stack trace** — Click any handler in the Architecture view and Learn Mode animates the full request lifecycle: DNS → TCP → TLS → HTTP → middleware → handler → service → SQL → 200 OK. The `user_id` parameter is highlighted at every hop with rename annotations (`userId → user_id → id`). One graph query, no log dive. |
|  | **MCP tools your AI assistant calls directly** — A real `find_symbol("get_user")` response from polycodegraph's MCP server. Three results in ~50 tokens, role-classified as HANDLER vs SERVICE, no file reads required. Drop this in alongside Claude Code's grep and the assistant stops dumping whole files into its context window — see the benchmark below. |

---

## Benchmark — same Claude, varying graph MCP

Four configurations. Same Claude Sonnet 4.6. Same 10 questions across two real codebases (polycodegraph itself + FastAPI). **All four configs include Claude's native grep + file-reading tools** — what every dev gets out of the box in Claude Code or Cursor. The only thing that changes is whether a graph MCP is *also* registered alongside.

### codegraph-self

| Configuration | Correct | Tokens in | Cost (USD) | Avg latency (s) |
|---|---:|----:|----:|----:|
| `claude+grep` (no graph MCP) | 5 / 5 | 264,756 | $0.92 | 102 |
| `+ code-review-graph` MCP | 2 / 5 | 118,674 | $0.39 | 56 |
| `+ graphify` MCP | 3 / 5 | 99,233 | $0.31 | 83 |
| `+ polycodegraph` MCP | **4 / 5** | **43,705** | **$0.18** | **22** |

### fastapi

| Configuration | Correct | Tokens in | Cost (USD) | Avg latency (s) |
|---|---:|----:|----:|----:|
| `claude+grep` (no graph MCP) | 3 / 5 | 71,833 | $0.25 | 54 |
| `+ code-review-graph` MCP | 1 / 5 | 84,082 | $0.29 | 42 |
| `+ graphify` MCP | 2 / 5 | 55,287 | $0.19 | 46 |
| `+ polycodegraph` MCP | **3 / 5** | **46,347** | **$0.19** | **18** |

The honest read across both repos:

- **`claude+grep` alone is the most correct (8/10)** — Claude can answer most codebase questions by grepping and reading whole files. But it pays the price: **336k tokens, $1.17, 78s avg latency.**
- **`+ polycodegraph` matches that within one question (7/10) at *3× lower cost and 4× lower latency* (90k tokens, $0.37, 20s).** Because polycodegraph returns small focused subgraphs (~20-50 tokens per call) instead of grep-dumping whole files into Claude's context.
- **The other graph MCPs are strictly worse than just grepping.** code-review-graph: 3/10 at $0.68. graphify: 5/10 at $0.50. They add tool overhead without paying off in correctness.

Reproduce: `codegraph bench agent --only claude+grep,claude+grep+polycodegraph,claude+grep+code-review-graph,claude+grep+graphify`. Raw per-run JSONL in [`bench/agent_raw_latest.jsonl`](bench/agent_raw_latest.jsonl). Full methodology in [`bench/README.md`](bench/README.md).

---

## Install & use

### From PyPI

```bash
pip install polycodegraph
codegraph init
codegraph build
```

### Register as an MCP server

`codegraph init` writes a project-level `.mcp.json` in the repo — **Claude Code and Cursor auto-pick that up** as soon as you open the project. For other clients you currently need to add the server to their global config manually (v0.2 will do this for you).

```jsonc
// Claude Code (global)  →  ~/.claude.json
// Cursor (global)       →  ~/.cursor/mcp.json   (or .cursor/mcp.json per workspace)
// Windsurf              →  ~/.windsurf/mcp.json
// OpenAI Codex CLI      →  ~/.codex/mcp.json
// GitHub Copilot CLI    →  ~/.config/copilot/mcp.json
// Zed                   →  ~/.config/zed/settings.json under "context_servers"
// Continue              →  ~/.continue/config.json under "experimental.modelContextProtocolServers"

{
  "mcpServers": {
    "codegraph": {
      "command": "codegraph",
      "args": ["mcp", "serve"]
    }
  }
}
```

The same five-line JSON snippet works for every client — only the file path changes.

Then ask your assistant questions like:

> *"Which HANDLER nodes have no test coverage?"*
> *"Show me all the callers of `UserService.login` with their arguments."*
> *"Trace `GET /api/users/{id}` from the frontend fetch all the way to the database."*
> *"What's the blast radius of changing this function?"*

All 18 tools return small, focused subgraphs — no context-window flooding.

### Optional: local embeddings

```bash
pip install 'polycodegraph[embed]'
codegraph embed     # chunks the repo, embeds with nomic-ai/CodeRankEmbed
```

Unlocks the `semantic_search` and `hybrid_search` MCP tools. ~140 MB model download, runs locally, no API keys.

---

## Live demo

A small FastAPI + SQLAlchemy + React fixture lives in [`examples/cross-stack-demo/`](examples/cross-stack-demo/). Run polycodegraph on it to see DF0, DF1, DF1.5, DF2, DF3, and DF4 all light up:

```bash
codegraph build --no-incremental --root examples/cross-stack-demo
codegraph dataflow trace "GET /api/users/{user_id}"
```

See the [demo README](examples/cross-stack-demo/README.md) for expected output.

---

## Limitations (honest list)

What polycodegraph *doesn't* do yet. Listed here so the benchmark and README claims stay clean.

- **Type inference** (Mypy / Pyright). DF0 captures argument *text*, not types. Roadmap v0.3.
- **Argument-value identity across hops.** DF4 emits ordered hops with rename annotations; full single-value propagation from fetch body → route param → service arg → DB column is deferred (v0.3).
- **Docstrings are stored on every node but not yet consumed by analysis.** Embeddings use them as fallback body text; dead-code, role classification, and dataflow ignore them. Roadmap v0.3.
- **Git-history mining** (commit-message semantics, author / touch-frequency signals). Not implemented. Git is used only for the current HEAD SHA and PR-review diff. Roadmap v0.4.
- **Per-language resolver parity** (v0.1.2). Python ships the full R1/R2/R3 fixes. TypeScript R2 patterns (path aliases, fresh-instance binding, decorator-call edges) are deferred.
- **Typer CLI symbols are not tagged HANDLER** (v0.1.x). DF1.5 only classifies HTTP framework decorators.
- **Async / await visualization** (v0.4). DF4 walks the synchronous call graph only.
- **Error-path branch rendering** (v0.4). Learn Mode shows the happy path.
- **Auth middleware as a distinct phase** (v0.4). Today auth shows up as a regular CALL node.
- **Multi-param simultaneous highlighting** (v0.4). Single-param selection only.
- **Cross-process traces** (v0.4). Can't yet link multiple `.codegraph/graph.db` files.

---

## Roadmap

| Version | Status | What's in / what's planned |
|---|---|---|
| **0.1.0** | **Shipping on PyPI today** | Parsing (Python, TS/JS, Go), DF0–DF4 tracing, 3D dashboard + Architecture + Learn Mode, decorator-aware dead code, cycles, role classification, **local embeddings** (semantic + hybrid search), 18 MCP tools, PR-review CI, cross-repo workspace mode. |
| 0.1.2 | Planned | TypeScript R2 resolver patterns (path aliases, fresh-instance binding, decorator edges); CLI HANDLER classification for Typer / Click. |
| 0.3 | Planned | Type inference (Mypy/Pyright); full single-value arg-flow propagation; docstring-driven analysis hints; multi-param highlighting; more languages (Rust, Java, C#). |
| 0.2 | Planned | Rename CLI binary `codegraph` → `polycodegraph` (keep `codegraph` as a deprecated alias for one release); `codegraph init` writes to *every* detected client's global MCP config (Claude Code / Cursor / Windsurf / Codex / Copilot / Zed / Continue), not just the project-level `.mcp.json`. |
| 0.4 | Planned | Async / await visualization; error-path branches; auth-middleware phase; cross-process traces; git-history semantics. |

---

## On the self-graph: from 451 dead-code findings to 0

We run polycodegraph on its own source as a regression target. Dead-code findings dropped from **451 → 24+ → 15 → 0** as the resolver hardened, decorator-aware entry-point detection landed, and intentional public-API methods were marked with `# pragma: codegraph-public-api`.

Current self-graph stats:

- **3,320 nodes** (files, classes, functions, imports)
- **7,557 edges** (5,245 CALLS, 1,357 DEFINED_IN, 886 IMPORTS, 28 INHERITS, 12 ROUTE, 27 FETCH_CALL, 1 READS_FROM, 1 WRITES_TO)
- **3 cycles**, all documented and accepted (dashboard redraw, parser self-recursion, MCP serve/run resolver false positive)
- **0 dead-code findings** (with pragma exemptions for public-API methods)
- **637 tests passing** (537 Python pytest + 100 Node tests)

---

## Where it fits

| | **polycodegraph** | GitNexus | code-review-graph | better-code-review-graph | JudiniLabs / mcp-code-graph | RepoMapper | Graphify |
|---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| Local-first, single SQLite, no daemon | ✅ | ✅ | ✅ | ✅ | partial | ✅ | varies |
| MCP-native (stdio) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Cross-stack end-to-end trace (fetch → SQL) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Decorator-aware dead code (24 frameworks) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Role classification (HANDLER/SERVICE/...) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Argument-level data flow text capture (DF0) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| 3D focus-mode flow tracer | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | partial |
| Local embeddings (no API key) | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Open source, MIT | ✅ | ❌ (PolyForm NC) | ✅ | ✅ | ✅ | ✅ | varies |

The wedge isn't a fancier graph algorithm — it's that polycodegraph treats *trace this argument across the stack* as a first-class operation, not a follow-up grep. Embedding-based retrieval tools (code-review-graph, Cursor, Cody) handle prose / docstrings well; the right architecture is **graph + embeddings in the same MCP loop**, and v0.1.0 ships both.

---

Full feature reference (16 capabilities)

| Capability | What it does | Example |
|---|---|---|
| **Parsing** | tree-sitter walks Python / TypeScript / JavaScript / TSX / JSX / Go at function/method/class granularity. | `codegraph build` |
| **Single SQLite store** | All graph data in `.codegraph/graph.db`. No daemon, no DB server, no network. | `git commit .codegraph/` |
| **Cross-file resolution** | Per-name imports, relative imports, same-file constructors, decorator-call edges, `self.X.Y` chains, fresh-instance methods. | `from pkg import a, b, c` → 3 separate edges |
| **DF0 call-site arguments** | Captures the text of each argument at parse time (no type inference). Powers signature tooltips and edge labels. | `func(user_id=42)` → edge label shows `user_id=42` |
| **Decorator-aware dead code** | 24 framework decorators recognized (Typer, FastAPI, Click, Celery, pytest, MCP, Flask, Django, SQLAlchemy, etc.). Framework-registered handlers never flagged. | `@app.get("/x")` → handler not dead code |
| **Call/import

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [smochan](https://github.com/smochan)
- **Source:** [smochan/polycodegraph](https://github.com/smochan/polycodegraph)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-smochan-polycodegraph
- Seller: https://agentstack.voostack.com/s/smochan
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
