Skip to main content
Glama
SiwarKhalfaoui

codegraph-mcp

README.md
# codegraph-mcp

An [MCP](https://modelcontextprotocol.io) server that indexes a TypeScript/JavaScript
codebase into a real call graph and import graph — using TypeScript's own
type checker for symbol resolution, not regex or text matching — and exposes
it to Claude (or any MCP client) as queryable tools.

Ask Claude things like:
- *"What would break if I change `queue.ts`?"*
- *"Who calls `createUser`?"*
- *"Show me the dependency graph of this module."*

Instead of Claude re-reading your whole codebase to answer, it gets a precise,
structural answer from a pre-built graph.

No paid APIs, no paid services. Free npm registry / GitHub used only for
testing against real-world code (see below).

## Why this exists

Code-intelligence tools that build a persistent, queryable graph of a
codebase are one of the fastest-moving categories in AI developer tooling
right now — this is a scoped-down, honestly-documented version of that idea,
built to demonstrate the underlying technique rather than compete with the
production tools in that space (see Limitations below).

## How it actually works (the part that matters)

Naive versions of this idea use regex or text matching to find function
calls — which breaks constantly (a call inside a comment, a variable that
happens to share a name with a function, an imported name that shadows a
local one). This project instead uses the **real TypeScript compiler API**:
it builds an actual `ts.Program`, asks the **type checker** to resolve every
call expression to its true declaration, and only records an edge when that
resolution succeeds.

This caught a real, non-obvious bug during development: when an identifier
comes from an `import { x } from "..."`, the checker initially returns an
**alias symbol** pointing at the import binding itself, not the original
declaration — resolving through that alias (`checker.getAliasedSymbol`) is
what makes cross-file call resolution actually work. Without that step, only
same-file calls would ever be found. See `src/parser.ts` for the fix.

## Verified output

**On a hand-written 3-file fixture** (`test/fixtures/sample-project`) — full
automated test suite, 20/20 passing, including cross-file resolution:

```
--- Call edges (the hard part: cross-file resolution via the type checker) ---
PASS: handleSignup calls createUser (CROSS-FILE — requires alias resolution)
PASS: main calls handleSignup (CROSS-FILE — requires alias resolution)
PASS: createUser calls hashPassword (same-file)
PASS: Exactly 3 call edges (no false positives)

--- Query engine ---
PASS: findCallers(createUser) returns exactly handleSignup
PASS: impactAnalysis(userService.ts) finds index.ts at depth 2 (TRANSITIVE, not direct)

20 passed, 0 failed
```

**On a real, published open-source library** ([sindresorhus/p-queue](https://github.com/sindresorhus/p-queue),
a well-known ~2,000-star npm package) — indexed live via the actual MCP tool
call, not a script:

```
Indexed 5 file(s): 32 symbol(s), 7 call edge(s), 7 import edge(s).
```

with a correctly resolved summary — `lowerBound` (a binary-search helper)
shown being called from within `PriorityQueue.enqueue`, and `queue.ts`
correctly identified as the most depended-on file (3 dependents) — matching
p-queue's actual architecture. This also caught a second real bug: p-queue's
source uses ESM-style imports with explicit `.js` extensions
(`import x from './priority-queue.js'`) even though the real file on disk is
`.ts` — extremely common in modern TypeScript/NodeNext projects. The
resolver now handles that extension swap; see `src/parser.ts`.

## Tools

| Tool | Description |
|---|---|
| `index_codebase` | Parse a codebase into a graph. Run this first. |
| `find_definition` | Find where a symbol is defined, by name |
| `find_callers` | Who calls a given symbol (cross-file aware) |
| `find_callees` | What a given symbol calls |
| `get_file_dependencies` | Direct import relationships for a file |
| `impact_analysis` | Transitive closure of files affected by changing a file |
| `get_graph_summary` | Stats: most-called symbols, most-depended-on files |

## Setup

```bash
git clone https://github.com/SiwarKhalfaoui/codegraph-mcp.git
cd codegraph-mcp
npm install
npm run build
```

### As a standalone CLI (no Claude needed)

```bash
node build/cli.js index /path/to/some/project/src
node build/cli.js summary
node build/cli.js find-definition createUser
node build/cli.js impact src/queue.ts
node build/cli.js export-mermaid calls --out call-graph.mmd
```

### Connect it to Claude Desktop

Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`
on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows):

```json
{
  "mcpServers": {
    "codegraph": {
      "command": "node",
      "args": ["/absolute/path/to/codegraph-mcp/build/mcpServer.js"]
    }
  }
}
```

Or test directly without Claude Desktop using [MCP Inspector](https://github.com/modelcontextprotocol/inspector):

```bash
npx @modelcontextprotocol/inspector node build/mcpServer.js
```

## Development

```bash
npm run dev    # run the CLI directly with tsx, no build step
npm test       # full automated test suite against the fixture project
```

## Architecture notes

- `src/fileDiscovery.ts` — walks the filesystem for source files, skipping
  `node_modules`/build output/tests, with cross-platform path normalization
- `src/parser.ts` — the core: builds a `ts.Program`, extracts every
  function/method/class declaration, then resolves every call expression
  and import specifier via the real type checker
- `src/graphStore.ts` — persists the graph as JSON, not SQLite. **Deliberate
  tradeoff**: a native SQLite binding needs platform-specific compilation
  (`node-gyp`), which is exactly the kind of cross-platform friction this
  project avoids. A repo-sized graph fits comfortably in memory as JSON —
  SQLite would be the right upgrade for very large monorepos, not for this
  scope.
- `src/queries.ts` — builds in-memory indices (by id, by name, adjacency
  lists) over the loaded graph and answers the actual questions
- `src/mermaid.ts` — visual export for human inspection
- `src/mcpServer.ts` — wraps the query engine as MCP tools
- `src/cli.ts` — same functionality as a standalone command-line tool

## Known limitations (stated honestly)

- **Single-language scope.** TypeScript/JavaScript only — not the 158
  languages some production code-intelligence tools support. This is a
  focused demonstration of the technique, not a general-purpose tool.
- **Private class members (`#method`) aren't tracked yet.** TypeScript's
  private-field syntax uses a different AST node type than regular method
  names; this project doesn't yet register or resolve calls to them.
- **Static analysis only.** Dynamic dispatch (calling a function stored in
  a variable that could point at several different implementations) isn't
  resolved — only calls the type checker can statically determine.
- **JSON storage, not a real database.** Fine at single-repo scale;
  wouldn't scale cleanly to a huge monorepo (see architecture notes above).

## Possible extensions

- Support private class members (`#foo`) as trackable symbols
- Incremental re-indexing (only re-parse changed files) instead of a full
  rebuild every time
- A small web UI rendering the Mermaid export interactively instead of
  static text

## License

MIT

TDQS

A3.9/5.0

Scored across 7 tools

Disambiguation5/5

Each tool addresses a distinct aspect of code graph analysis: initialization, definition lookup, forward/reverse call relationships, direct file dependencies, transitive impact, and summary statistics. There is no overlap between find_callers, find_callees, and impact_analysis, as each operates at a different level of granularity or direction.

Naming Consistency4/5

Most tools follow a clear verb_noun pattern (index_codebase, find_definition, find_callers, find_callees, get_file_dependencies, get_graph_summary), but impact_analysis breaks the convention as a compound noun rather than an imperative verb phrase. The consistency is strong overall.

Tool Count5/5

Seven tools is a well-scoped count for a code graph server. Each tool covers a necessary capability without redundancy, making the set feel complete and manageable.

Completeness5/5

The tool surface covers the full lifecycle of code graph exploration: building the graph, finding definitions, traversing callers/callees, examining file dependencies, performing transitive impact analysis, and obtaining summary stats. There are no obvious dead ends or missing core operations.

Maintenance

ActivityStale
ResponsivenessNo issues