subsriram/codesurgeon

Local-first codebase context engine for AI coding agents

Rust

0

190 commits

updated May 7, 2026

See the code

README

codesurgeon

Local-first codebase context engine for AI coding agents.

codesurgeon parses your codebase into a symbol dependency graph, then serves token-budgeted context capsules to Claude (or any MCP-compatible agent) via the Model Context Protocol. Only the code that matters for your task is returned — full source for the most relevant symbols, signatures-only for adjacent ones.

Benchmark vs baseline

MetricBaseline (full context)codesurgeon
Tokens per query (30-file project)~30,000~3,000
Token reduction~90%
Relevant pivots surfacedall files8 symbols
Setupnonecargo install + 1 config line

Token figures are from the leading competitor's published results. codesurgeon reports your actual per-workspace savings via codesurgeon stats (or the get_stats MCP tool).

SWE-bench Verified

The leading competitor in this space benchmarked against SWE-bench Verified — 100 real GitHub issues, same model and cost cap across all agents:

AgentPass@1$/Task
Leading competitor + Claude Code73%$0.67
OpenHands70%$1.77
Sonar Foundation70%$1.98

Key insight from the per-repo breakdown: dependency-graph context (like codesurgeon's symbol graph) yields large gains on import-heavy, interconnected codebases (astropy: 80% vs 40% for alternatives) but smaller gains on rendering-heavy or procedural code (matplotlib: 43% vs 86%). codesurgeon is best suited for Rust, Python backend, and TypeScript projects with deep module graphs.

codesurgeon will run the same benchmark once Phase 8 (tool parity) and Phase 9 (session memory) are stable.

Compared to the leading alternative:

Leading alternativecodesurgeon
RuntimeTypeScript/Node.js wrapper + Rust corePure Rust, single binary
SearchFTS5 + TF-IDFBM25 (Tantivy) + graph centrality + optional embeddings
EmbeddingsNonenomic-embed-text-v1.5 (768-dim, Apple Silicon Metal)
Call edgescaller → calleecaller → callee + args snippet
Graph extrasimports, calls+ trait impls, type-flow references
Diff supportNoget_diff_capsule for PR review
Session memoryNoCross-session observations, stale detection
LanguagesPython, JS/TS, Rust+ Swift, Shell, HTML, SQL

How it works

Your codebase
     │
     ▼
tree-sitter AST parsing (parallel, rayon)
     │
     ▼
Symbol graph (petgraph DAG)
  Nodes: functions, classes, structs, enums, methods
  Edges: Calls, Imports, Implements, Inherits, References
     │
     ▼
Query: "fix the retry logic in the HTTP client"
     │
     ├─ Intent detection → Debug
     ├─ BM25 search (Tantivy) → top-50 candidates
     ├─ Graph centrality boost → re-rank
     ├─ Semantic similarity blend (embeddings, optional)
     └─ Token-budgeted capsule assembly
           ├─ Pivots (8): full source of most relevant symbols
           └─ Adjacents (20): signatures only (70–90% smaller)

Installation

Requirements

  • macOS or Linux (Windows is untested)
  • Rust 1.75+ — only required if building from source (rustup)
  • Optional: Node.js (for TypeScript enrichment), pyright (for Python enrichment)

Grab the latest release for your platform from the Releases page:

# Apple Silicon
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-aarch64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/

# Intel Mac
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/

# Linux x86_64
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/

1b. Build from source

git clone https://github.com/subsriram/codesurgeon
cd codesurgeon

# Apple Silicon (Metal embeddings, recommended)
cargo build --release --features metal

# CPU-only embeddings
cargo build --release --features embeddings

# No embeddings (BM25 + graph only)
cargo build --release

This produces two binaries in target/release/:

  • codesurgeon — the CLI
  • codesurgeon-mcp — the MCP server (add to Claude Code / Codex)

To use the codesurgeon CLI from anywhere, either symlink them onto your PATH or add target/release to your shell's PATH:

sudo ln -sf "$(pwd)/target/release/codesurgeon" /usr/local/bin/codesurgeon
sudo ln -sf "$(pwd)/target/release/codesurgeon-mcp" /usr/local/bin/codesurgeon-mcp

2. Add to Claude Code

claude mcp add --scope user \
  -e CS_WORKSPACE=/path/to/your/project \
  cs-myproject \
  /path/to/codesurgeon/target/release/codesurgeon-mcp

This writes to ~/.claude.json (CLI v2.x). Restart Claude Code — the server indexes your workspace in the background on first start.

Multiple projects

Run claude mcp add once per project with a unique server name:

claude mcp add --scope user \
  -e CS_WORKSPACE=/projects/frontend \
  cs-frontend \
  /path/to/codesurgeon-mcp

claude mcp add --scope user \
  -e CS_WORKSPACE=/projects/backend \
  cs-backend \
  /path/to/codesurgeon-mcp

Tools are namespaced: cs-frontend__run_pipeline, cs-backend__run_pipeline, etc.

3. Use in Claude Code

Before editing: run_pipeline(task="add retry logic to the HTTP client")
Before refactoring: get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")
Navigating code: get_skeleton(file_path="src/http.rs")
After solving hard problem: save_observation(content="retry uses exponential backoff")

MCP tools

Quick reference

ToolWhen to use
run_pipelineBefore every edit — primary tool
get_context_capsuleLightweight search for a specific query
get_impact_graphBefore any refactor — see what breaks
get_skeletonUnderstand a file's shape without reading bodies
search_logic_flowTrace how A calls B
get_diff_capsuleContext for a PR or patch
index_statusHealth check / Xcode MCP availability
get_session_contextCatch up at the start of a session
save_observationPersist an insight across sessions
generate_module_docsWrite per-directory CLAUDE.md files

Tool reference

run_pipeline — your primary tool Call this before every edit. Give it a plain-English task description. It auto-detects intent (debug / refactor / add / explore / structural), runs BM25 + graph centrality + semantic search, and returns a token-budgeted capsule: full source for the 8 most relevant symbols, signatures-only for up to 20 adjacent ones, plus anything remembered from previous sessions.

run_pipeline(task="fix the retry logic in the HTTP client")

Optional context parameter — pass the raw verbatim source the task was derived from (full problem statement, bug report, error trace). Identifiers present in the raw source but paraphrased out of task are recovered via anchor extraction, which runs on task + context while BM25/semantic/intent detection stay on task alone.

run_pipeline(
  task="fix PolynomialError on subs with Piecewise",
  context="<full GitHub issue body with code snippet and traceback>"
)

get_context_capsule — lightweight search Same search engine as run_pipeline but without intent routing or session memory. Use it when you have a specific query and don't need the full pipeline.

get_context_capsule(query="token budget assembly")

get_impact_graph — blast radius before a refactor Call this before renaming or changing any function or type. Give it a fully-qualified symbol name and it returns all direct and transitive callers — everything that will break.

get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")

get_skeleton — file API surface Returns all signatures and docstrings from a file with bodies stripped out. Typically 70–90% fewer tokens than the full file. Use it when you need to understand what a file exports without reading everything.

get_skeleton(file_path="src/engine.rs")

search_logic_flow — trace a path between two functions Finds the shortest call-graph path from one symbol to another. Use it to understand how A eventually reaches B, or to debug unexpected call chains.

search_logic_flow(from_fqn="src/main.rs::handle_request", to_fqn="src/db.rs::query")

get_diff_capsule — context for a PR or patch Paste in a git diff and it returns the changed symbols, their callers, and related test files — all token-budgeted. Designed for code review.

get_diff_capsule(diff="<paste unified diff here>")

index_status — health check Returns symbol count, edge count, file count, session ID, and Xcode MCP availability. Call it to confirm the index is ready after startup, or to check whether re-indexing is still in progress.

index_status()

get_session_context — what was learned before Returns the last ~50 observations saved across all sessions for this workspace. Use it at the start of a session to catch up on what was discovered previously.

get_session_context()

save_observation — persist an insight Saves a note tied optionally to a specific symbol. Persists across sessions and is surfaced by run_pipeline in future sessions. Call it after solving something non-obvious.

save_observation(content="retry uses exponential backoff, max 3 attempts", symbol_fqn="src/http.rs::HttpClient::send")

generate_module_docs — write CLAUDE.md files per directory Generates per-directory CLAUDE.md summaries from the symbol graph — types, functions, and (for Swift directories) Xcode MCP guidance. Pass write_files=true to write them to disk.

generate_module_docs(write_files=true)

Decision guide

SituationTool
About to edit anythingrun_pipeline
About to rename / move / deleteget_impact_graph first
Unfamiliar file, need the shapeget_skeleton
Reviewing a PRget_diff_capsule
How does A call B?search_logic_flow
Is the index ready?index_status
Starting a new sessionget_session_context
Just solved something trickysave_observation
Setting up a new projectgenerate_module_docs

CLI

codesurgeon index                          # Index (or re-index) workspace
codesurgeon status                         # Symbol/edge/file counts
codesurgeon search "retry logic"           # BM25 search
codesurgeon skeleton src/http.rs           # File skeleton
codesurgeon impact src/http.rs::send       # Blast radius
codesurgeon flow src/http.rs::send src/retry.rs::with_retry  # Logic flow
codesurgeon diff - < my.patch             # Diff-aware capsule (stdin)
git diff | codesurgeon diff -             # Pipe from git diff
codesurgeon diff "$(git diff)"           # Inline diff text
codesurgeon context "fix auth bug"       # Full run_pipeline from CLI
codesurgeon config                       # Show current configuration
codesurgeon docs                           # Generate per-module CLAUDE.md files
codesurgeon memory                         # List saved observations (shows IDs)
codesurgeon memory --delete <id>           # Delete an observation by ID
codesurgeon observe "insight text"         # Save a manual observation
codesurgeon observe "insight" --symbol src/http.rs::send  # Attach to a symbol
codesurgeon submit-lsp-edges edges.json    # Push LSP-resolved type edges from a file
cat edges.json | codesurgeon submit-lsp-edges  # …or from stdin

Language support

LanguageParserNotes
Rusttree-sitterFull AST incl. impl/trait
Pythontree-sitterFull AST
TypeScript / TSXtree-sitterFull AST; optional resolved types via TS compiler shim
JavaScript / JSXtree-sitterFull AST; optional resolved types via TS compiler shim
Swifttree-sitter + Xcode MCP (optional)Full AST — class/struct/enum/extension/protocol/func/method; Xcode MCP adds resolved types
Shell (bash/zsh)tree-sitterFunction extraction
HTMLtree-sitterScript/style blocks
SQLtree-sitterCREATE TABLE/VIEW/FUNCTION/INDEX/TYPE

TypeScript / JavaScript enrichment — compiler shim

codesurgeon's tree-sitter pass gives you full TypeScript/JavaScript symbol structure. For resolved types (e.g. Promise<User> instead of Promise<any>), enable the optional compiler shim:

Requirements: node on PATH, tsconfig.json in your workspace root, and typescript in node_modules (or globally installed).

Enable by adding to .codesurgeon/config.toml:

[indexing]
ts_types = true

At index time codesurgeon invokes a bundled Node.js script (ts-enricher.js) that runs ts.createProgram() + TypeChecker over your workspace and annotates symbols with their resolved return/property types. The results are stored in the index as resolved_type and surfaced in context capsules.

Incremental: the shim only re-runs when tsconfig.json changes. Existing annotations are preserved across re-indexes.

Plain JS: the shim sets allowJs: true, so JSDoc-annotated JavaScript files are resolved correctly too.

VS Code users: if you have the codesurgeon VS Code extension installed, the submit_lsp_edges tool pushed from the running TypeScript language server is the faster alternative — no subprocess spawning required. ts_types is the right choice for CI, Codex, or non-VS Code editors.


Swift enrichment — Xcode MCP

codesurgeon's tree-sitter pass gives you full Swift symbol structure. For resolved types and live build diagnostics, pair it with Xcode MCP (Xcode 26+):

# Enable in Xcode: Settings → Intelligence → Enable Model Context Protocol
xcrun mcpbridge install --claude-code

When Xcode MCP is configured, run_pipeline on Swift files will note its availability and agents can call its tools for type-resolved details. When it's absent, run_pipeline says so explicitly — the tree-sitter graph remains fully usable for semantic search, impact analysis, and session memory. index_status always reports whether Xcode MCP was detected.

For Xcode < 26 or SPM-only projects: XcodeBuildMCP or xcode-mcp-server.

Privacy

codesurgeon is fully local-first. Your code never leaves your machine.

  • No network calls — zero outbound connections during indexing, search, or capsule assembly
  • No telemetry — no usage metrics are sent anywhere, ever
  • No cloud dependencies — no API keys, no external services, no subscriptions
  • Local index — the symbol graph lives in .codesurgeon/index.db alongside your project (gitignored by default)
  • On-device embeddings — semantic search uses a local model (nomic-embed-text-v1.5) running entirely on your CPU or Apple Silicon GPU

The only binary that runs is codesurgeon-mcp, started by your MCP client (Claude Code / Codex) as a subprocess over stdio. It reads your source files, builds a local index, and responds to tool calls — nothing else.

Troubleshooting

MCP server not connecting (Claude Code / Codex)

Symptom: Tools like run_pipeline are not available, or Claude reports the MCP server failed to start.

  1. Confirm CS_WORKSPACE points to an existing directory:
    echo $CS_WORKSPACE
    ls "$CS_WORKSPACE"
    
  2. Run the binary directly to see startup errors:
    echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' \
      | CS_WORKSPACE=/path/to/project timeout 5 ./target/release/codesurgeon-mcp
    
    A healthy server replies with an initialize response on stdout. Any error on stderr explains the failure.
  3. Re-check the server entry in ~/.claude.json (Claude Code CLI v2.x):
    claude mcp list
    

Index not ready / stale results

Symptom: index_status() returns 0 symbols, or results look stale after editing files.

  • The index builds in the background on first start. Give it a few seconds, then call index_status() again to confirm.
  • To force a full re-index:
    CS_WORKSPACE=/path/to/project codesurgeon index
    
  • Check how many files were indexed:
    CS_WORKSPACE=/path/to/project codesurgeon status
    

Second instance running in read-only mode

Symptom: A second Claude Code window or parallel Codex probe connects but sees no results, or logs show "serving read-only".

This is expected behaviour. Only one codesurgeon-mcp instance per workspace runs background indexing (the first one to acquire the PID lock). Subsequent instances serve the existing index read-only — they won't write new embeddings or trigger re-indexing. This is intentional to avoid concurrent index writes.

If you want the new instance to become the primary, stop the existing one first:

kill $(cat /path/to/project/.codesurgeon/mcp.pid)

Stale PID file after a crash

Symptom: After a hard kill or power loss, new instances unexpectedly enter read-only mode.

codesurgeon auto-detects this: on startup it reads the existing PID file and runs kill -0 <pid> to check whether that process is actually alive. If it's dead, the stale file is overwritten automatically and the new instance becomes primary. No manual cleanup is needed in normal cases.

If for some reason this fails (e.g. the PID was reused by a system process), delete the file manually:

rm /path/to/project/.codesurgeon/mcp.pid

Binary not found after cargo build

Symptom: codesurgeon or codesurgeon-mcp command not found.

The binaries are placed in target/release/, not on your PATH automatically. Either use the full path:

/path/to/codesurgeon/target/release/codesurgeon-mcp

Or add the release directory to your PATH, or symlink:

ln -s /path/to/codesurgeon/target/release/codesurgeon /usr/local/bin/codesurgeon

Enabling debug logging

Set CS_LOG (a tracing-subscriber env-filter expression) to see detailed output from the MCP server or CLI. Default: warn.

# Info-level (recommended for troubleshooting)
CS_LOG=info CS_WORKSPACE=/path/to/project codesurgeon query "my search"

# Debug-level (verbose — shows every file indexed, every query scored)
CS_LOG=debug CS_WORKSPACE=/path/to/project ./target/release/codesurgeon-mcp

# Trace a specific module
CS_LOG=cs_core::engine=debug codesurgeon query "my search"

Configuration

codesurgeon is configured via .codesurgeon/config.toml in your project root. A user-level fallback at ~/.config/codesurgeon/config.toml is also loaded (workspace settings take precedence). All settings are optional — sensible defaults apply when files are missing.

[context]
# Token budget per context capsule (default: 4000)
max_tokens = 4000

# How much body text to include for adjacent (skeleton) symbols:
#   "minimal"  — ~5% of body (signatures only, very tight)
#   "standard" — ~15% of body (default)
#   "detailed" — ~30% of body (for large-context models like claude-opus)
skeleton_detail = "standard"

[indexing]
# Enable TypeScript compiler enrichment (requires node + typescript in node_modules)
ts_types = false

# Enable Pyright type enrichment (requires pyright on PATH)
python_pyright = false

# Enable cargo-expand macro enrichment (requires cargo-expand)
rust_expand_macros = false

# Enable rustdoc JSON type enrichment (requires nightly Rust)
rust_rustdoc_types = false

[memory]
# Auto-observations expire after this many days (default: 7)
auto_ttl_days = 7

# Manual observations never expire by default; set to override
# manual_ttl_days = 90

[git]
# Write manifest.json for git-tracked index metadata
track_manifest = false

[observability]
# USD cost per token for savings display in `codesurgeon stats` (default: 0.000003)
token_rate_usd = 0.000003

Run codesurgeon config to see the effective merged settings and their sources.

Environment variables

Most settings live in config.toml (above). The following env vars control runtime concerns that don't belong in committed config:

VarRead byPurpose
CS_WORKSPACEcodesurgeon, codesurgeon-mcpWorkspace root for indexing and queries. Required when not running from inside the workspace.
CLAUDE_CODE_WORKSPACEcodesurgeon, codesurgeon-mcpAlias of CS_WORKSPACE, set automatically by Claude Code. CS_WORKSPACE wins if both are set.
CS_LOGcodesurgeon, codesurgeon-mcptracing-subscriber env-filter expression (e.g. info, debug, cs_core::engine=trace). Default: warn.
CS_TRACK_MANIFESTcodesurgeon, codesurgeon-mcpSet to 1 to overlay [git] track_manifest = true from the environment, omitting manifest.json from .codesurgeon/.gitignore so it can be shared across clones.
CS_BENCH_CENTRALITY_Kcargo run --example token_savingsPin the centrality smoothing constant k for the 20-query bench, e.g. CS_BENCH_CENTRALITY_K=15.0 reproduces pre-#82 behaviour. Unset → corpus-derived (default). Bench-only — has no effect on the binaries.

Contributing

Contributions are welcome! Before submitting a PR, run the pre-commit checklist:

cargo fmt --all          # Format
cargo clippy --workspace -- -D warnings  # Lint (warnings are errors in CI)
cargo test --workspace   # Tests

All three must pass. See .github/workflows/ci.yml for the exact CI checks.

License

MIT — see LICENSE for details.

Contributors

subsriram

190 commits

subsriram/codesurgeon

Local-first codebase context engine for AI coding agents

Rust

0

190 commits

updated May 7, 2026

See the code

README

codesurgeon

Local-first codebase context engine for AI coding agents.

codesurgeon parses your codebase into a symbol dependency graph, then serves token-budgeted context capsules to Claude (or any MCP-compatible agent) via the Model Context Protocol. Only the code that matters for your task is returned — full source for the most relevant symbols, signatures-only for adjacent ones.

Benchmark vs baseline

MetricBaseline (full context)codesurgeon
Tokens per query (30-file project)~30,000~3,000
Token reduction~90%
Relevant pivots surfacedall files8 symbols
Setupnonecargo install + 1 config line

Token figures are from the leading competitor's published results. codesurgeon reports your actual per-workspace savings via codesurgeon stats (or the get_stats MCP tool).

SWE-bench Verified

The leading competitor in this space benchmarked against SWE-bench Verified — 100 real GitHub issues, same model and cost cap across all agents:

AgentPass@1$/Task
Leading competitor + Claude Code73%$0.67
OpenHands70%$1.77
Sonar Foundation70%$1.98

Key insight from the per-repo breakdown: dependency-graph context (like codesurgeon's symbol graph) yields large gains on import-heavy, interconnected codebases (astropy: 80% vs 40% for alternatives) but smaller gains on rendering-heavy or procedural code (matplotlib: 43% vs 86%). codesurgeon is best suited for Rust, Python backend, and TypeScript projects with deep module graphs.

codesurgeon will run the same benchmark once Phase 8 (tool parity) and Phase 9 (session memory) are stable.

Compared to the leading alternative:

Leading alternativecodesurgeon
RuntimeTypeScript/Node.js wrapper + Rust corePure Rust, single binary
SearchFTS5 + TF-IDFBM25 (Tantivy) + graph centrality + optional embeddings
EmbeddingsNonenomic-embed-text-v1.5 (768-dim, Apple Silicon Metal)
Call edgescaller → calleecaller → callee + args snippet
Graph extrasimports, calls+ trait impls, type-flow references
Diff supportNoget_diff_capsule for PR review
Session memoryNoCross-session observations, stale detection
LanguagesPython, JS/TS, Rust+ Swift, Shell, HTML, SQL

How it works

Your codebase
     │
     ▼
tree-sitter AST parsing (parallel, rayon)
     │
     ▼
Symbol graph (petgraph DAG)
  Nodes: functions, classes, structs, enums, methods
  Edges: Calls, Imports, Implements, Inherits, References
     │
     ▼
Query: "fix the retry logic in the HTTP client"
     │
     ├─ Intent detection → Debug
     ├─ BM25 search (Tantivy) → top-50 candidates
     ├─ Graph centrality boost → re-rank
     ├─ Semantic similarity blend (embeddings, optional)
     └─ Token-budgeted capsule assembly
           ├─ Pivots (8): full source of most relevant symbols
           └─ Adjacents (20): signatures only (70–90% smaller)

Installation

Requirements

  • macOS or Linux (Windows is untested)
  • Rust 1.75+ — only required if building from source (rustup)
  • Optional: Node.js (for TypeScript enrichment), pyright (for Python enrichment)

Grab the latest release for your platform from the Releases page:

# Apple Silicon
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-aarch64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/

# Intel Mac
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-apple-darwin.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/

# Linux x86_64
curl -L https://github.com/subsriram/codesurgeon/releases/latest/download/codesurgeon-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv codesurgeon codesurgeon-mcp /usr/local/bin/

1b. Build from source

git clone https://github.com/subsriram/codesurgeon
cd codesurgeon

# Apple Silicon (Metal embeddings, recommended)
cargo build --release --features metal

# CPU-only embeddings
cargo build --release --features embeddings

# No embeddings (BM25 + graph only)
cargo build --release

This produces two binaries in target/release/:

  • codesurgeon — the CLI
  • codesurgeon-mcp — the MCP server (add to Claude Code / Codex)

To use the codesurgeon CLI from anywhere, either symlink them onto your PATH or add target/release to your shell's PATH:

sudo ln -sf "$(pwd)/target/release/codesurgeon" /usr/local/bin/codesurgeon
sudo ln -sf "$(pwd)/target/release/codesurgeon-mcp" /usr/local/bin/codesurgeon-mcp

2. Add to Claude Code

claude mcp add --scope user \
  -e CS_WORKSPACE=/path/to/your/project \
  cs-myproject \
  /path/to/codesurgeon/target/release/codesurgeon-mcp

This writes to ~/.claude.json (CLI v2.x). Restart Claude Code — the server indexes your workspace in the background on first start.

Multiple projects

Run claude mcp add once per project with a unique server name:

claude mcp add --scope user \
  -e CS_WORKSPACE=/projects/frontend \
  cs-frontend \
  /path/to/codesurgeon-mcp

claude mcp add --scope user \
  -e CS_WORKSPACE=/projects/backend \
  cs-backend \
  /path/to/codesurgeon-mcp

Tools are namespaced: cs-frontend__run_pipeline, cs-backend__run_pipeline, etc.

3. Use in Claude Code

Before editing: run_pipeline(task="add retry logic to the HTTP client")
Before refactoring: get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")
Navigating code: get_skeleton(file_path="src/http.rs")
After solving hard problem: save_observation(content="retry uses exponential backoff")

MCP tools

Quick reference

ToolWhen to use
run_pipelineBefore every edit — primary tool
get_context_capsuleLightweight search for a specific query
get_impact_graphBefore any refactor — see what breaks
get_skeletonUnderstand a file's shape without reading bodies
search_logic_flowTrace how A calls B
get_diff_capsuleContext for a PR or patch
index_statusHealth check / Xcode MCP availability
get_session_contextCatch up at the start of a session
save_observationPersist an insight across sessions
generate_module_docsWrite per-directory CLAUDE.md files

Tool reference

run_pipeline — your primary tool Call this before every edit. Give it a plain-English task description. It auto-detects intent (debug / refactor / add / explore / structural), runs BM25 + graph centrality + semantic search, and returns a token-budgeted capsule: full source for the 8 most relevant symbols, signatures-only for up to 20 adjacent ones, plus anything remembered from previous sessions.

run_pipeline(task="fix the retry logic in the HTTP client")

Optional context parameter — pass the raw verbatim source the task was derived from (full problem statement, bug report, error trace). Identifiers present in the raw source but paraphrased out of task are recovered via anchor extraction, which runs on task + context while BM25/semantic/intent detection stay on task alone.

run_pipeline(
  task="fix PolynomialError on subs with Piecewise",
  context="<full GitHub issue body with code snippet and traceback>"
)

get_context_capsule — lightweight search Same search engine as run_pipeline but without intent routing or session memory. Use it when you have a specific query and don't need the full pipeline.

get_context_capsule(query="token budget assembly")

get_impact_graph — blast radius before a refactor Call this before renaming or changing any function or type. Give it a fully-qualified symbol name and it returns all direct and transitive callers — everything that will break.

get_impact_graph(symbol_fqn="src/http.rs::HttpClient::send")

get_skeleton — file API surface Returns all signatures and docstrings from a file with bodies stripped out. Typically 70–90% fewer tokens than the full file. Use it when you need to understand what a file exports without reading everything.

get_skeleton(file_path="src/engine.rs")

search_logic_flow — trace a path between two functions Finds the shortest call-graph path from one symbol to another. Use it to understand how A eventually reaches B, or to debug unexpected call chains.

search_logic_flow(from_fqn="src/main.rs::handle_request", to_fqn="src/db.rs::query")

get_diff_capsule — context for a PR or patch Paste in a git diff and it returns the changed symbols, their callers, and related test files — all token-budgeted. Designed for code review.

get_diff_capsule(diff="<paste unified diff here>")

index_status — health check Returns symbol count, edge count, file count, session ID, and Xcode MCP availability. Call it to confirm the index is ready after startup, or to check whether re-indexing is still in progress.

index_status()

get_session_context — what was learned before Returns the last ~50 observations saved across all sessions for this workspace. Use it at the start of a session to catch up on what was discovered previously.

get_session_context()

save_observation — persist an insight Saves a note tied optionally to a specific symbol. Persists across sessions and is surfaced by run_pipeline in future sessions. Call it after solving something non-obvious.

save_observation(content="retry uses exponential backoff, max 3 attempts", symbol_fqn="src/http.rs::HttpClient::send")

generate_module_docs — write CLAUDE.md files per directory Generates per-directory CLAUDE.md summaries from the symbol graph — types, functions, and (for Swift directories) Xcode MCP guidance. Pass write_files=true to write them to disk.

generate_module_docs(write_files=true)

Decision guide

SituationTool
About to edit anythingrun_pipeline
About to rename / move / deleteget_impact_graph first
Unfamiliar file, need the shapeget_skeleton
Reviewing a PRget_diff_capsule
How does A call B?search_logic_flow
Is the index ready?index_status
Starting a new sessionget_session_context
Just solved something trickysave_observation
Setting up a new projectgenerate_module_docs

CLI

codesurgeon index                          # Index (or re-index) workspace
codesurgeon status                         # Symbol/edge/file counts
codesurgeon search "retry logic"           # BM25 search
codesurgeon skeleton src/http.rs           # File skeleton
codesurgeon impact src/http.rs::send       # Blast radius
codesurgeon flow src/http.rs::send src/retry.rs::with_retry  # Logic flow
codesurgeon diff - < my.patch             # Diff-aware capsule (stdin)
git diff | codesurgeon diff -             # Pipe from git diff
codesurgeon diff "$(git diff)"           # Inline diff text
codesurgeon context "fix auth bug"       # Full run_pipeline from CLI
codesurgeon config                       # Show current configuration
codesurgeon docs                           # Generate per-module CLAUDE.md files
codesurgeon memory                         # List saved observations (shows IDs)
codesurgeon memory --delete <id>           # Delete an observation by ID
codesurgeon observe "insight text"         # Save a manual observation
codesurgeon observe "insight" --symbol src/http.rs::send  # Attach to a symbol
codesurgeon submit-lsp-edges edges.json    # Push LSP-resolved type edges from a file
cat edges.json | codesurgeon submit-lsp-edges  # …or from stdin

Language support

LanguageParserNotes
Rusttree-sitterFull AST incl. impl/trait
Pythontree-sitterFull AST
TypeScript / TSXtree-sitterFull AST; optional resolved types via TS compiler shim
JavaScript / JSXtree-sitterFull AST; optional resolved types via TS compiler shim
Swifttree-sitter + Xcode MCP (optional)Full AST — class/struct/enum/extension/protocol/func/method; Xcode MCP adds resolved types
Shell (bash/zsh)tree-sitterFunction extraction
HTMLtree-sitterScript/style blocks
SQLtree-sitterCREATE TABLE/VIEW/FUNCTION/INDEX/TYPE

TypeScript / JavaScript enrichment — compiler shim

codesurgeon's tree-sitter pass gives you full TypeScript/JavaScript symbol structure. For resolved types (e.g. Promise<User> instead of Promise<any>), enable the optional compiler shim:

Requirements: node on PATH, tsconfig.json in your workspace root, and typescript in node_modules (or globally installed).

Enable by adding to .codesurgeon/config.toml:

[indexing]
ts_types = true

At index time codesurgeon invokes a bundled Node.js script (ts-enricher.js) that runs ts.createProgram() + TypeChecker over your workspace and annotates symbols with their resolved return/property types. The results are stored in the index as resolved_type and surfaced in context capsules.

Incremental: the shim only re-runs when tsconfig.json changes. Existing annotations are preserved across re-indexes.

Plain JS: the shim sets allowJs: true, so JSDoc-annotated JavaScript files are resolved correctly too.

VS Code users: if you have the codesurgeon VS Code extension installed, the submit_lsp_edges tool pushed from the running TypeScript language server is the faster alternative — no subprocess spawning required. ts_types is the right choice for CI, Codex, or non-VS Code editors.


Swift enrichment — Xcode MCP

codesurgeon's tree-sitter pass gives you full Swift symbol structure. For resolved types and live build diagnostics, pair it with Xcode MCP (Xcode 26+):

# Enable in Xcode: Settings → Intelligence → Enable Model Context Protocol
xcrun mcpbridge install --claude-code

When Xcode MCP is configured, run_pipeline on Swift files will note its availability and agents can call its tools for type-resolved details. When it's absent, run_pipeline says so explicitly — the tree-sitter graph remains fully usable for semantic search, impact analysis, and session memory. index_status always reports whether Xcode MCP was detected.

For Xcode < 26 or SPM-only projects: XcodeBuildMCP or xcode-mcp-server.

Privacy

codesurgeon is fully local-first. Your code never leaves your machine.

  • No network calls — zero outbound connections during indexing, search, or capsule assembly
  • No telemetry — no usage metrics are sent anywhere, ever
  • No cloud dependencies — no API keys, no external services, no subscriptions
  • Local index — the symbol graph lives in .codesurgeon/index.db alongside your project (gitignored by default)
  • On-device embeddings — semantic search uses a local model (nomic-embed-text-v1.5) running entirely on your CPU or Apple Silicon GPU

The only binary that runs is codesurgeon-mcp, started by your MCP client (Claude Code / Codex) as a subprocess over stdio. It reads your source files, builds a local index, and responds to tool calls — nothing else.

Troubleshooting

MCP server not connecting (Claude Code / Codex)

Symptom: Tools like run_pipeline are not available, or Claude reports the MCP server failed to start.

  1. Confirm CS_WORKSPACE points to an existing directory:
    echo $CS_WORKSPACE
    ls "$CS_WORKSPACE"
    
  2. Run the binary directly to see startup errors:
    echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' \
      | CS_WORKSPACE=/path/to/project timeout 5 ./target/release/codesurgeon-mcp
    
    A healthy server replies with an initialize response on stdout. Any error on stderr explains the failure.
  3. Re-check the server entry in ~/.claude.json (Claude Code CLI v2.x):
    claude mcp list
    

Index not ready / stale results

Symptom: index_status() returns 0 symbols, or results look stale after editing files.

  • The index builds in the background on first start. Give it a few seconds, then call index_status() again to confirm.
  • To force a full re-index:
    CS_WORKSPACE=/path/to/project codesurgeon index
    
  • Check how many files were indexed:
    CS_WORKSPACE=/path/to/project codesurgeon status
    

Second instance running in read-only mode

Symptom: A second Claude Code window or parallel Codex probe connects but sees no results, or logs show "serving read-only".

This is expected behaviour. Only one codesurgeon-mcp instance per workspace runs background indexing (the first one to acquire the PID lock). Subsequent instances serve the existing index read-only — they won't write new embeddings or trigger re-indexing. This is intentional to avoid concurrent index writes.

If you want the new instance to become the primary, stop the existing one first:

kill $(cat /path/to/project/.codesurgeon/mcp.pid)

Stale PID file after a crash

Symptom: After a hard kill or power loss, new instances unexpectedly enter read-only mode.

codesurgeon auto-detects this: on startup it reads the existing PID file and runs kill -0 <pid> to check whether that process is actually alive. If it's dead, the stale file is overwritten automatically and the new instance becomes primary. No manual cleanup is needed in normal cases.

If for some reason this fails (e.g. the PID was reused by a system process), delete the file manually:

rm /path/to/project/.codesurgeon/mcp.pid

Binary not found after cargo build

Symptom: codesurgeon or codesurgeon-mcp command not found.

The binaries are placed in target/release/, not on your PATH automatically. Either use the full path:

/path/to/codesurgeon/target/release/codesurgeon-mcp

Or add the release directory to your PATH, or symlink:

ln -s /path/to/codesurgeon/target/release/codesurgeon /usr/local/bin/codesurgeon

Enabling debug logging

Set CS_LOG (a tracing-subscriber env-filter expression) to see detailed output from the MCP server or CLI. Default: warn.

# Info-level (recommended for troubleshooting)
CS_LOG=info CS_WORKSPACE=/path/to/project codesurgeon query "my search"

# Debug-level (verbose — shows every file indexed, every query scored)
CS_LOG=debug CS_WORKSPACE=/path/to/project ./target/release/codesurgeon-mcp

# Trace a specific module
CS_LOG=cs_core::engine=debug codesurgeon query "my search"

Configuration

codesurgeon is configured via .codesurgeon/config.toml in your project root. A user-level fallback at ~/.config/codesurgeon/config.toml is also loaded (workspace settings take precedence). All settings are optional — sensible defaults apply when files are missing.

[context]
# Token budget per context capsule (default: 4000)
max_tokens = 4000

# How much body text to include for adjacent (skeleton) symbols:
#   "minimal"  — ~5% of body (signatures only, very tight)
#   "standard" — ~15% of body (default)
#   "detailed" — ~30% of body (for large-context models like claude-opus)
skeleton_detail = "standard"

[indexing]
# Enable TypeScript compiler enrichment (requires node + typescript in node_modules)
ts_types = false

# Enable Pyright type enrichment (requires pyright on PATH)
python_pyright = false

# Enable cargo-expand macro enrichment (requires cargo-expand)
rust_expand_macros = false

# Enable rustdoc JSON type enrichment (requires nightly Rust)
rust_rustdoc_types = false

[memory]
# Auto-observations expire after this many days (default: 7)
auto_ttl_days = 7

# Manual observations never expire by default; set to override
# manual_ttl_days = 90

[git]
# Write manifest.json for git-tracked index metadata
track_manifest = false

[observability]
# USD cost per token for savings display in `codesurgeon stats` (default: 0.000003)
token_rate_usd = 0.000003

Run codesurgeon config to see the effective merged settings and their sources.

Environment variables

Most settings live in config.toml (above). The following env vars control runtime concerns that don't belong in committed config:

VarRead byPurpose
CS_WORKSPACEcodesurgeon, codesurgeon-mcpWorkspace root for indexing and queries. Required when not running from inside the workspace.
CLAUDE_CODE_WORKSPACEcodesurgeon, codesurgeon-mcpAlias of CS_WORKSPACE, set automatically by Claude Code. CS_WORKSPACE wins if both are set.
CS_LOGcodesurgeon, codesurgeon-mcptracing-subscriber env-filter expression (e.g. info, debug, cs_core::engine=trace). Default: warn.
CS_TRACK_MANIFESTcodesurgeon, codesurgeon-mcpSet to 1 to overlay [git] track_manifest = true from the environment, omitting manifest.json from .codesurgeon/.gitignore so it can be shared across clones.
CS_BENCH_CENTRALITY_Kcargo run --example token_savingsPin the centrality smoothing constant k for the 20-query bench, e.g. CS_BENCH_CENTRALITY_K=15.0 reproduces pre-#82 behaviour. Unset → corpus-derived (default). Bench-only — has no effect on the binaries.

Contributing

Contributions are welcome! Before submitting a PR, run the pre-commit checklist:

cargo fmt --all          # Format
cargo clippy --workspace -- -D warnings  # Lint (warnings are errors in CI)
cargo test --workspace   # Tests

All three must pass. See .github/workflows/ci.yml for the exact CI checks.

License

MIT — see LICENSE for details.

Contributors

subsriram

190 commits

Languages

Rust

99.2%