Skip to content

gingerknight/graphReviewer

Repository files navigation

graphReviewer

Local code graph analyzer. Parses Rust, Python, JavaScript, and TypeScript source files into a directed call graph using tree-sitter, then serves that graph over the Model Context Protocol (MCP) via stdio. Any MCP client — Claude Code, Cursor, Kiro, or others — can query callers, callees, impact chains, and codebase statistics without leaving the editor.

Building

Requires a Rust toolchain (1.70+) and a C compiler for tree-sitter grammars.

cargo build --release

For git diff analysis (changed-function detection, PR review), enable the git-support feature. This pulls in git2, which links against OpenSSL:

cargo build --release --features git-support

If the OpenSSL build fails, see TROUBLESHOOTING.md.

The binary lands at target/release/graph_reviewer.

Usage

graph_reviewer <COMMAND> [OPTIONS]

Commands

index — Parse a codebase and print graph statistics.

graph_reviewer index --path /path/to/code

mcp — Start the MCP server. By default, communicates over stdio (stdin/stdout). With --port, starts an HTTP server with SSE streaming instead.

graph_reviewer mcp -P /path/to/code [--git-dir /path/to/repo]
graph_reviewer mcp -P /path/to/code --port 3000

-P is the directory to index. --git-dir points to the git repository root (containing .git/); required for the analyze_diff and review_changes tools.

Without --port, the server reads JSON-RPC from stdin and writes to stdout. An MCP client spawns this process as a subprocess.

With --port, the server binds to 127.0.0.1:<port>/mcp and accepts HTTP POST requests. Responses stream back as Server-Sent Events (SSE). The server prints the listening URL to stderr on startup.

query — Run a one-off query from the command line (useful for testing).

graph_reviewer query -P ./my-project --query-type callers --target "authenticate"
graph_reviewer query -P ./my-project --query-type callees --target "main"
graph_reviewer query -P ./my-project --query-type similar --target "process_data"

export — Export the graph to JSON, CSV, or SQL.

graph_reviewer export -P ./my-project -o graph.json -f json
graph_reviewer export -P ./my-project -o graph.sql -f sql

pr-export — Export a subgraph focused on changed functions between two git refs (requires --features git-support).

graph_reviewer pr-export -P . -o pr.sql --from-ref main --to-ref HEAD --hops 2

diff-export — Export the full graph with prefixed SQL table names, for side-by-side comparison of two snapshots.

graph_reviewer diff-export -P . -o before.sql --prefix before_

Client Setup

graphReviewer supports two transports:

  • stdio (default) — the MCP client spawns the binary as a subprocess and talks JSON-RPC over stdin/stdout. Use this for local IDE integration.
  • HTTP SSE (--port) — the binary runs as a standalone HTTP server. The client connects to http://127.0.0.1:<port>/mcp via POST and receives Server-Sent Events. Use this for shared servers or clients that prefer HTTP.

Claude Code

Global config (~/.claude/.mcp.json) — applies to every project:

{
  "mcpServers": {
    "graphReviewer": {
      "command": "/path/to/graph_reviewer",
      "args": ["mcp", "-P", "."],
      "env": {}
    }
  }
}

Or use a wrapper script that auto-detects the repo root:

#!/usr/bin/env bash
set -euo pipefail
BINARY="$HOME/workspace/graphReviewer/target/release/graph_reviewer"
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
  echo "Error: not inside a git repository" >&2
  exit 1
}
exec "$BINARY" mcp -P "$REPO_ROOT" --git-dir "$REPO_ROOT"

Per-project config (.mcp.json in project root):

{
  "mcpServers": {
    "graphReviewer": {
      "command": "/absolute/path/to/graph_reviewer",
      "args": ["mcp", "-P", "/absolute/path/to/project", "--git-dir", "/absolute/path/to/project"]
    }
  }
}

Cursor

Add to .cursor/mcp.json in your project, or ~/.cursor/mcp.json globally:

{
  "mcpServers": {
    "graphReviewer": {
      "command": "/path/to/graph_reviewer",
      "args": ["mcp", "-P", "/path/to/project", "--git-dir", "/path/to/project"]
    }
  }
}

Kiro

Add to .kiro/mcp.json in your project root:

{
  "mcpServers": {
    "graphReviewer": {
      "command": "/path/to/graph_reviewer",
      "args": ["mcp", "-P", "/path/to/project", "--git-dir", "/path/to/project"]
    }
  }
}

HTTP SSE (any client)

Start the server first, then point your client at the URL:

graph_reviewer mcp -P /path/to/project --git-dir /path/to/project --port 3000

The server prints MCP HTTP server listening on http://127.0.0.1:3000/mcp to stderr. Configure your client with:

{
  "mcpServers": {
    "graphReviewer": {
      "url": "http://127.0.0.1:3000/mcp"
    }
  }
}

Verifying the Connection

stdio — pipe an initialize request into the binary:

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' \
  | graph_reviewer mcp -P .

HTTP — start the server, then curl it:

graph_reviewer mcp -P . --port 3000 &
curl -X POST http://127.0.0.1:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'

Both should return a JSON-RPC response with serverInfo and capabilities.

MCP Tools

The server exposes 10 tools. The first 8 work on any codebase; the last 2 require the git-support feature and --git-dir.

find_callers

Find every function that calls the target. Returns a markdown table with qualified name, file path, line range, and signature.

{"function": "authenticate"}

find_callees

Find every function the target calls. Same output format as find_callers.

{"function": "main"}

impact_analysis

Walk the call graph upward from the target to find all direct and transitive callers. Reports affected files and a risk level (Low / Medium / High / Critical) based on caller count and file spread.

{"function": "validate_token", "depth": 5}

depth is optional (default 3, max 10). Depth 1 gives direct callers only.

search_functions

Case-insensitive substring search across all function qualified names. Optionally filter by language.

{"query": "handle", "language": "rust"}

language accepts rust, python, javascript, typescript.

graph_stats

Returns file counts, function counts, and class counts broken down by language, plus the top 10 "hotspot" functions (most callers). Takes no arguments.

find_patterns

Find functions with similar call patterns to the reference function, using Jaccard similarity on callee sets. Returns the top 10 matches above 30%.

{"reference_function": "process_data"}

query_graph

General-purpose query — dispatches to callers, callees, or similar_functions based on the query_type parameter.

{"query_type": "callers", "target": "main"}

reindex

Re-parse the codebase and rebuild the graph. Call this after making code changes so subsequent queries reflect the current state. Takes no arguments.

analyze_diff

Requires git-support. Identify which functions changed between two commits and run impact analysis on each.

{"from_commit": "main", "to_commit": "HEAD"}

review_changes

Requires git-support. Full PR review: lists changed functions with line numbers, runs impact analysis, and optionally includes source context with changed lines marked.

{"from_ref": "main", "to_ref": "HEAD", "include_context": true, "impact_depth": 3}

include_context (default true) and impact_depth (default 3) are optional.

MCP Resources

Resources provide read-only data about the indexed graph. Clients can list and read these via the standard MCP resource protocol.

URI Returns
graph://stats File, function, and class counts by language; top hotspots (JSON)
graph://files Every indexed file with path, language, and line count (JSON array)
graph://functions Every indexed function with qualified name, file, lines, signature (JSON array)
graph://hotspots Top 10 functions by caller count (JSON array)
graph://functions/{name} Single function detail: signature, location, callers, callees (JSON)

MCP Prompts

Prompts provide pre-built context that MCP clients can inject into LLM conversations.

Name Arguments Description
analyze-function function (required) Function signature, callers, callees, and impact assessment
codebase-overview (none) Statistics-based architectural overview
review-pr from_ref, to_ref, include_context, impact_depth Changed functions with impact for PR review (requires git-support)

How It Works

Source files (Rust, Python, JS, TS)
    │
    ▼
TreeSitterParser ──▶ extracts functions, classes, imports, call sites
    │                 resolves qualified names (Type::method, Class.method)
    ▼
CodeGraph (petgraph directed graph)
    │  file_index:     HashMap<PathBuf, NodeIndex>
    │  function_index: HashMap<String, Vec<NodeIndex>>
    │  class_index:    HashMap<String, Vec<NodeIndex>>
    ▼
MCP Server (rmcp SDK, stdio transport)
    │  lazy init: graph built on first tool call
    │  all tools, resources, prompts served inline
    ▼
MCP Client

What gets parsed

Language Extensions Constructs
Rust .rs Functions, impl blocks → Type::method, structs, enums, use, call expressions
Python .py Functions, classes → Class.method, self.method() resolution, imports, calls
JavaScript .js, .jsx Functions, arrow functions (named from variable declarator), classes, imports, calls
TypeScript .ts, .tsx Same as JavaScript

Directory filtering

Hardcoded skip list: .git, node_modules, .venv, venv, env, __pycache__, target, dist, build, out, .next, cdk.out, coverage, .coverage, htmlcov, .pytest_cache, .mypy_cache

Additionally reads .gitignore in the project root and filters matching directory/file names (simple name matching, not full glob).

Graph structure

Nodes: File, Function, Class, Variable, Import

Edges: Calls, Defines, Imports, Uses, Inherits

Variable nodes and Uses/Inherits edges are defined in the type system but not currently created by the parser.

SQL Export and DuckDB Review

The export and pr-export commands can produce SQL files loadable into DuckDB for ad-hoc analysis. See scripts/ for review queries and prompts:

scripts/
  review.sh              # Run codebase review queries
  pr-review.sh           # Run PR-focused review queries
  ingest.sh              # Load SQL export into DuckDB
  snapshot-export.sh     # Export graph snapshots for diff
  review_queries.sql     # Codebase health queries
  pr_review_queries.sql  # PR review queries
  diff_queries.sql       # Snapshot comparison queries
  REVIEW_PROMPT.md       # LLM prompt for codebase review
  PR_REVIEW_PROMPT.md    # LLM prompt for PR review

Testing

cargo test

113 tests across 11 suites (without git-support; git tests add 7 more):

Suite Tests Covers
parser_qualified_names 8 Qualified names: Rust impl, Python class, JS/TS class, arrow functions
parser_edge_cases 9 Nested classes, decorators, closures, multiline signatures
parser_gitignore 6 Directory filtering, .gitignore parsing
graph_queries 18 Callers, callees, impact, similarity, search, stats algorithms
export_integration 21 JSON, CSV, SQL export roundtrips
cli_export 4 CLI export subcommand
mcp_protocol 29 MCP protocol: initialize, tools, resources, prompts (subprocess)
mcp_handlers 15 Tool handler unit tests
mcp_http 3 HTTP SSE transport: initialize, tools/list, tool call (subprocess)
git_diff_line_level 3 Line-level diff, function overlap detection (git-support)
code_review_integration 4 End-to-end review_changes (git-support)

Dependencies

Crate What for
petgraph Directed graph
tree-sitter + language grammars AST parsing
rmcp MCP protocol (server, stdio transport, JSON schema)
serde / serde_json Serialization
tokio Async runtime
clap CLI
git2 (optional) Git integration via libgit2
walkdir Filesystem traversal
csv / chrono Export
anyhow / thiserror Errors
tracing / tracing-subscriber Logging (stderr, RUST_LOG=debug)

Limitations

  • Name-based call resolution: obj.method() matches bare function names in the global index — false edges when classes share method names
  • No import tracing: Calls matched by name, not by following import paths
  • Single-threaded parsing: Files parsed sequentially
  • In-memory graph: Rebuilt on every server start, no persistence
  • Basic .gitignore: Name-component matching only, no nested files, no full glob
  • No TS-specific constructs: Interfaces, enums, namespaces, generics not tracked
  • Python decorators: Not tracked
  • find_patterns is O(n²): Compares every function pair; slow on large codebases

License

MIT

About

Local code graph analyzer with MCP integration for Claude Code

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors