get_architecture_map
Call at session start to orient without Glob/Grep. Returns God Nodes (central hubs), subsystem clusters, Godot autoloads, and top event channels.
top_nproject_path
io.github.erayerturkPublished by GitHub account erayerturkv0.1.0Updated Nov 1, 2026
Local Tree-sitter code graph: surgical edit context for AI agents instead of full-file reads.
Local Tree-sitter code graph server that gives coding agents surgical edit context, impact analysis and rename/delete checks instead of full-file reads.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Follow the launch instructions in the repository.
surgical-context-mcp — Surgical AST Code Context & Knowledge Graph for AI Coding Agents[PyPI] [Total downloads] [Monthly downloads] [MCP Registry] [CI] [License: MIT] [Python 3.10+] [Claude Code] [GitHub stars]
Stop feeding 3,000-line files into your LLM context window.
surgical-context-mcpis a zero-LLM-cost, embedded SQLite + Tree-sitter Code Knowledge Graph and MCP Server that gives AI coding agents (Claude Code, Cursor, Windsurf, Cline, Claude Desktop) the exact surgical context they need to edit, refactor, and navigate codebases safely — cutting token consumption by 70–95% without sacrificing code quality.
[surgical-context-mcp demo: get_edit_context returns ~3.6k tokens instead of a 13k-token full file read]
Real run on this repo: editing a function in a 1,264-line file costs ~3.7k tokens instead of ~13.3k (−72%) — and you still get the skeleton, callers and helpers.
That's it — your agent now calls get_edit_context instead of reading whole files. Using Cursor, Windsurf, Cline or Claude Desktop? See Step 1. Also listed on the official MCP Registry as io.github.erayerturk/surgical-context-mcp.
surgical-context-mcp?CLAUDE.md / .cursorrules Configurationsurgical-context-mcp?Grep and then Read entire 1,500–3,000 line files into the context window. Because every subsequent tool call re-sends the entire conversation history (cache reads), a single large file read early in a session compounds into 100k–300k wasted tokens.lines 240–260 of a file to save tokens, the agent becomes blind to:
self.x fields, @onready / @export variables, constants, and struct / interface definitions at the top of the file.±5 lines around call sites).foo() calls. If a function is invoked via getattr(obj, "foo") in Python, call("foo") or a .tscn signal connection in Godot, SendMessage("foo") in Unity/C#, or referenced in a .vue/.html/.proto file, a naive graph reports "0 callers — safe to delete", breaking production code.surgical-context-mcp Solves All Threeget_edit_context(symbol) — One Call Before Any Edit:
Instead of reading a 2,500-line file, the agent makes one MCP call (get_edit_context) and receives a strictly budgeted (≤ 4,000 tokens) surgical package containing:
Edit)interface/struct/enum blocks, class fields, constants — without other function bodies)≤ 25 lines)d=1, ±5 Line Windows) (exact call-site context without dumping 200-line caller functions).tscn connections, templates, and protocol references)check_rename_or_delete(symbol) — One Call Before Any Refactor:
Checks AST callers (exact/scoped), inheritance overrides across parent/child classes, .tscn/template connections, signal emit/connect sites, and workspace-wide dynamic string references.shares_contract) — Server ↔ Client ↔ Config in One Call:
contract::opcode::0xCC): Automatically links hex opcode constants across languages (e.g., Go OpSGMOnline = 0xCC and GDScript/TypeScript const S_GM_ONLINE = 0xCC), so querying either constant shows both server senders and client packet handlers together.contract::config::<key>): Automatically links Go struct json:"max_chars_per_ip" field tags, frontend/panel schema strings ('multi_guard.max_chars_per_ip'), and seed/*.json config entries ("max_chars_per_ip": 2) into a single shared contract node.i18n) Graph (check_translations):
Indexes seed/*.json, shared/maps/*.json, locales/*.json, and .po files alongside code. Links tr("...") and noticeT(..., "n.x") calls to locale definitions and audits missing keys, accidental raw non-key literals, %d/%s/{} placeholder count mismatches, and unused locale keys.tests_for) & Git Diff Blast Radius (get_diff_impact):
tests_for(symbol) identifies every test exercising a symbol and returns the exact runnable CLI command (go test ./pkg -run '^TestFoo$', godot --headless --path client -s tests/..., pytest ... -k ...).get_diff_impact(base_ref="HEAD") parses git diff hunks, maps changed lines to modified AST symbols, and reports their callers, affected cross-language contracts, and runnable test commands in one call — built for code-review subagents (final-reviewer).doc_comment) so searching by concept (e.g. "attack stat") finds KOAP (// attack power stat bonus)._ready, _draw, _process, _physics_process, _input, Awake, Update) and suppresses false text-match noise warnings when AST upstream is empty.get_token_savings):
Every MCP/CLI query records its returned token count vs. the raw token size of touched files in SQLite (usage_telemetry), answering "How many tokens did code-graph save?" with direct measurements instead of estimates.WAL mode). Indexes ~600 files in < 0.6 seconds using 0 API tokens, and automatically refreshes modified files (mtime + SHA-1) on every query.PreToolUse Hook:
Includes a built-in hook guard (code-graph install-hooks) that blocks unbounded Read calls on files > 300 lines and returns the file's AST symbol table (Lstart-end: signature), ensuring both main agents and subagents stay on the surgical path.In agentic coding tools (Claude Code, Cursor, Cline), every tool call re-sends the entire conversation history up to that point. When an agent reads a 2,500-line file (~22,000 tokens) on Turn 2 of a 12-turn coding task, those 22,000 tokens are billed on Turn 2, Turn 3, Turn 4 ... all the way to Turn 12 (22,000 × 10 = 220,000 cumulative context tokens).
By replacing full-file reads with get_edit_context (~2,500–3,500 tokens), surgical-context-mcp prevents context bloat from compounding across turns.
(Measured on a 593-file multi-language repository: 2,607-line Godot client controller + Go backend + JS web dashboard)
surgical-context-mcp Provide the Biggest Gains?300 to 5,000+ lines):
Game controllers (main.gd, PlayerController.cs), large backend services (server.go, views.py), or complex React/TypeScript modules where you only need to edit 1–2 functions without losing sight of class fields, types, and existing helpers.check_rename_or_delete and get_edit_context show every caller's exact ±5 line call window without loading entire caller files into memory..tscn connections, Node/JS EventEmitter / bus.on, Python @on_event decorators, or C# events — where standard Grep cannot trace execution flow from emitter to listener.connect, refresh, update, send) across languages.< 300 lines):
If a file is only 150 lines long, slicing it into a skeleton + body is unnecessary overhead. surgical-context-mcp detects this automatically: for files < 300 lines, get_edit_context returns the full numbered file directly.go test ./... or pytest in a loop and reading 5,000 lines of stack traces from terminal stdout, those tokens come from bash test output rather than source-file reads.surgical-context-mcp strictly isolates language families (so a method in JavaScript or Go never collides with a method of the same name in Python or GDScript) and parses real ecosystem configuration files to resolve cross-file imports with exact confidence:
Every relationship in .code_graph.sqlite is tagged with one of three confidence levels:
exact: Resolved within the same file/class, via an explicit file import (tsconfig.json @/ alias, go.mod package, Python relative import, Godot project.godot Autoload, .tscn script), or direct super/inheritance chain.scoped: Unambiguous symbol resolved via imported modules or unique within the same language family.name_only: Ambiguous name match with multiple candidates. Excluded from primary output and summarized separately under ### Uncertain (name_only, max 5) so it never pollutes context.Published on PyPI and the official MCP Registry.
This puts two commands on your PATH: code-graph (CLI + MCP server) and surgical-context-mcp (MCP server shortcut).
Prefer a persistent install (
uv tool/pipx/pip) over one-offuvxruns:install-hookswrites the absolute path of thecode-graphbinary into your Claude Code settings, so it must not live in a temporary cache.
Run this once to register code-graph globally in Claude Code:
.mcp.json or claude_desktop_config.json)Add the following to your .mcp.json (project root) or global MCP settings file (if your editor doesn't inherit your shell PATH, use the absolute path from which code-graph):
Run install-hooks on any project repository you want to work on:
What this command does automatically:
.code_graph.sqlite in /path/to/your/project/.code_graph.sqlite (respecting .gitignore, nested .gitignore, .codegraphignore, and skipping node_modules, .venv, .git worktrees, build artifacts, etc.).GRAPH_REPORT.md in your project root — a compact architectural summary (~60 lines) listing your Subsystem Clusters, God Nodes (most connected production classes/functions), Autoloads, and Top Event/Signal Bus Channels.PreToolUse Hook into /path/to/your/project/.claude/settings.local.json:
Read on a code file larger than 300 lines, the hook intercepts the call, blocks the 3,000-line read, and returns a compact list of all functions/classes and their line numbers (Lstart-end: signature) in that file, instructing the agent to call get_edit_context or Read(offset, limit).Grep for a symbol name, the hook appends the exact AST definition coordinates from .code_graph.sqlite.Tip: Add
.code_graph.sqlite*to your project's.gitignoreso the local SQLite database is not committed to git.
CLAUDE.md or .cursorrulesCopy the Recommended CLAUDE.md Configuration below into your project's CLAUDE.md (or .cursorrules).
Once configured, you don't need to run manual commands — your AI agent will automatically follow this workflow:
GRAPH_REPORT.md or calls get_architecture_map() to immediately see the project's directory clusters and hub classes.interface/struct/var declarations), used members, short helper bodies, and caller windows in one shot, and immediately applies Edit without reading the whole file.get_edit_context on a Large FileCommand:
Output (abbreviated):
src/code_graph/context_builder.py — imports, signals, vars, consts)Referenced File Members:
22: SMALL_EDIT_FILE_LINES = 300 23: SHORT_CALLEE_MAX_LINES = 25
Same-File Callees:_read_file_lines [exact] (src/code_graph/context_builder.py:26-30):External Callees:
CodeGraphDB.find_symbol_nodes [scoped] (src/code_graph/db.py:694-781) — def find_symbol_nodes(self, symbol: str) -> list[GraphNode]:_cmd_edit_context [scoped, calls @ src/code_graph/cli.py:130] (window src/code_graph/cli.py:125-135):src/code_graph/context_builder.pydef format_coverage_warnings_section(def format_edit_context_markdown(ctx: dict[str, Any]) -> str:def build_rename_or_delete_check(CLAUDE.md / .cursorrules ConfigurationPaste this section into your project's CLAUDE.md, AGENTS.md, or .cursorrules so main agents and subagents follow the surgical workflow automatically:
.codegraphignore)By default, surgical-context-mcp automatically respects:
.gitignore files.git).git, .claude, .aider*, .venv, venv, node_modules, dist, build, target, vendor, .next, .godot, Library, Temp, Binaries, etc.)If you want to exclude additional directories or generated files from the graph without adding them to .gitignore, create a .codegraphignore file in your project root using standard .gitignore syntax:
The GRAPH_REPORT.md / "God Nodes" architecture-summary idea was inspired by graphify. surgical-context-mcp is an independent implementation with a different focus: per-edit surgical context (get_edit_context), refactor safety checks (check_rename_or_delete), and a PreToolUse hook that keeps agents off full-file reads.
Issues and PRs are welcome — especially new language resolvers and real-world token benchmarks. If surgical-context-mcp saves you tokens, a ⭐ helps others find it.
MIT © Eray Erturk. Free for personal and commercial use.
Source: README.md at commit 08769ca
Call at session start to orient without Glob/Grep. Returns God Nodes (central hubs), subsystem clusters, Godot autoloads, and top event channels.
top_nproject_pathCall before modifying a symbol. Returns file skeleton, full target body, used members/callees, caller ±5L windows, other signatures, and coverage warnings within `budget_tokens`.
symbolrequiredproject_pathbudget_tokensCall before deleting, renaming, or changing a signature. Returns all call sites, overrides, `.tscn` connections, signal emit/connect sites, and string/dynamic text references.
symbolrequiredproject_pathGet callers, callees, events, coverage warnings, and exact file:line ranges for `symbol` (`name`, `Class.method`, or `file::symbol`).
depthsymbolrequiredmax_linesmax_tokensproject_pathoutput_formatFind shortest high-confidence call/signal/event path between `from_symbol` and `to_symbol`.
max_depthto_symbolrequiredfrom_symbolrequiredproject_pathoutput_formatSearch indexed symbols by substring and optional `kind` (`class`, `function`, `method`, `event`).
kindlimitqueryproject_pathIncrementally update `.code_graph.sqlite` and return index diagnostics.
forceproject_path90% 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.
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
# 1. Install (or: pipx install / pip install surgical-context-mcp)uv tool install surgical-context-mcp
# 2. Register with Claude Codeclaude mcp add code-graph -- code-graph serve
# 3. Index your project + install the token-saving guard hookcode-graph install-hooks /path/to/your/projectflowchart LR subgraph Workspace["Project Workspace"] Code["Source Files\n(.py, .ts, .tsx, .go, .rs, .cs, .java, .gd, .tscn)"] Configs["Ecosystem Configs\n(tsconfig.json, go.mod, project.godot)"] end
subgraph Engine["surgical-context-mcp (Local, Zero-LLM)"] Scanner["Incremental Scanner\n(mtime + SHA-1 + .gitignore)"] Parser["Tree-sitter Polyglot AST\n+ Config Resolver"] DB[(".code_graph.sqlite\nNodes & Scoped Edges")] Scanner --> Parser --> DB Configs --> Parser end
subgraph AgentTools["MCP Tools & Claude Hooks"] Map["get_architecture_map\n(God Nodes & Clusters)"] EditCtx["get_edit_context\n(Skeleton + Body + Callers)"] Safety["check_rename_or_delete\n(Callers + Overrides + Dynamic Refs)"] Hook["PreToolUse Hook Guard\n(Blocks >300L Read)"] end
Code --> Scanner DB --> Map DB --> EditCtx DB --> Safety DB --> Hook# with uv (fastest)uv tool install surgical-context-mcp
# or with pipxpipx install surgical-context-mcp
# or plain pippip install surgical-context-mcpcode-graph --helpgit clone https://github.com/erayerturk/surgical-context-mcp.gitcd surgical-context-mcppython3.12 -m venv .venvsource .venv/bin/activatepip install -e .claude mcp add code-graph -- code-graph serve{ "mcpServers": { "code-graph": { "command": "code-graph", "args": ["serve"] } }}code-graph install-hooks /path/to/your/projectget_edit_context(symbol="computeFinalScore", project_path="/path/to/project")check_rename_or_delete(symbol="computeFinalScore", project_path="/path/to/project")code-graph edit-context build_edit_context -p /path/to/surgical-context-mcpindex: fresh## Edit Context: `build_edit_context` (`src/code_graph/context_builder.py:462-649`, 188L / file 1264L)
### Style Hint- indent: 4 spaces- conventions: type annotations (`-> ReturnType`); `_private` helpers
### 1. Target Function Body (`src/code_graph/context_builder.py:462-649`, exact)```python 462: def build_edit_context( 463: db: CodeGraphDB, 464: symbol: str, 465: budget_tokens: int = 4000, 466: refreshed_files: int = 0, 467: ) -> dict[str, Any]: ... 3: from __future__ import annotations 5: import os 6: import re 7: from pathlib import Path 10: from .db import CodeGraphDB 12: from .models import GraphNode 22: SMALL_EDIT_FILE_LINES = 300 23: SHORT_CALLEE_MAX_LINES = 25 26: def _read_file_lines(full_path: Path) -> list[str]: 27: try: 28: return full_path.read_text(encoding="utf-8", errors="replace").splitlines() 29: except OSError: 30: return [] 128: stats = indexer.index(force=False) 129: refreshed = stats.files_indexed + stats.files_removed 130: ctx = build_edit_context( 131: db=indexer.db, 132: symbol=args.symbol,
---
## MCP Tools Reference
All MCP tools have concise `≤ 2`-sentence docstrings to minimize system-prompt overhead in every session, and all tools auto-refresh modified files before running.
| MCP Tool | Parameters | Description || :--- | :--- | :--- || **`get_edit_context`** | `symbol`, `budget_tokens=4000`, `project_path=None` | **Call before editing any symbol.** Returns file skeleton, full target body, used members, short same-file callees, `±5L` caller windows, other function signatures, style hints, and coverage warnings within `budget_tokens` (or full file if `<300` lines). || **`get_architecture_map`** | `top_n=15`, `project_path=None` | **Call to understand repo structure.** Returns Subsystem Clusters (directories), God Nodes (highest-centrality production classes/functions), Godot Autoloads, and Top Event/Signal Hubs. || **`check_rename_or_delete`** | `symbol`, `project_path=None` | **Call before deleting, renaming, or changing a signature.** Returns all `exact`/`scoped` call sites, inheritance overrides, `.tscn`/template connections, signal `emit`/`connect` sites, and dynamic string matches. || **`get_symbol_impact`** | `symbol`, `depth=2`, `max_lines=300`, `max_tokens=800`, `include_uncertain=False`, `project_path=None` | Returns upstream callers, downstream callees, event bus connections, cross-language contracts (`contract::opcode::*`, `contract::config::*`), and surgical `±5L` read windows up to `depth` hops. || **`find_flow`** | `from_symbol`, `to_symbol`, `max_depth=8`, `project_path=None` | Finds the shortest call/event path between two symbols across functions, methods, and signals/events. || **`search_symbols`** | `query=""`, `kind=None`, `limit=30`, `project_path=None` | Searches AST nodes, data/i18n entries, and inline comments/docstrings (`doc_comment`) by name, substring, or multi-word concept query (`function`, `method`, `class`, `event`, `constant`, `field`, `data`, `i18n`). || **`tests_for`** | `symbol`, `project_path=None` | **Call to find tests for a symbol.** Traverses call/contract graphs and test naming conventions to return all tests exercising `symbol` along with exact runnable CLI commands (`go test -run ...`, `godot --headless -s ...`, `pytest -k ...`). || **`get_diff_impact`** | `base_ref="HEAD"`, `project_path=None` | **Call during code review (`final-reviewer`) or pre-commit.** Parses `git diff` hunks, identifies modified AST symbols, and returns their upstream callers, affected cross-language contracts, and runnable test commands in one report. || **`check_translations`** | `project_path=None` | **Call to audit `i18n` / translation keys.** Links `tr("...")` and `noticeT(..., "n.x")` calls with `.json`/`.po` locale files and reports missing keys (flagging suspicious raw non-key words), `%d`/`%s`/`{}` placeholder count mismatches, and unused keys. || **`get_token_savings`** | `project_path=None`, `reset=False` | **Call to measure exact MCP token savings.** Returns cumulative telemetry comparing returned tokens against raw touched file token sizes across all recorded tool calls. || **`reindex_project`** | `project_path=None`, `force=False` | Runs incremental `mtime` + `SHA-1` indexing (or full re-index if `force=True`) and updates `.code_graph.sqlite`. |
---
## CLI Reference
You can also use `code-graph` directly from your terminal:
```bash# 1. Index a project (fast incremental mtime + SHA-1 scan)code-graph index /path/to/project
# 2. Force a full re-index from scratchcode-graph index /path/to/project --force
# 3. Generate GRAPH_REPORT.md + install Claude Code PreToolUse guard hookscode-graph install-hooks /path/to/project
# 4. Get surgical edit context for a symbol (<= 4000 tokens)code-graph edit-context MyClass.my_method -p /path/to/project --budget 4000
# 5. Check if a symbol is safe to rename, change signature, or deletecode-graph check my_method -p /path/to/project
# 6. Inspect upstream callers, downstream callees & cross-language contracts (depth 1..5)code-graph impact OpSGMOnline --depth 2 -p /path/to/project
# 7. Find tests exercising a symbol and get exact runnable commandscode-graph tests-for BroadcastGMOnline -p /path/to/project
# 8. Analyze git diff blast radius (modified symbols, callers, contracts, runnable tests)code-graph diff-impact --base HEAD -p /path/to/project
# 9. Audit translation keys (missing keys, raw non-key literals, %d/%s mismatches, unused keys)code-graph i18n -p /path/to/project
# 10. Search symbols, data entries, or concepts (comments/docstrings)code-graph search "attack stat" -p /path/to/project
# 11. View measured token savings telemetrycode-graph savings -p /path/to/project
# 12. Find shortest call/event path between two symbolscode-graph flow handle_request send_notification -p /path/to/project
# 13. Print or write the Architecture Map (GRAPH_REPORT.md)code-graph report /path/to/project --write
# 14. Run diagnostics (DB size, language breakdown, confidence breakdown, token savings)code-graph doctor /path/to/project
# 15. Watch directory for live changes and auto-update .code_graph.sqlitecode-graph watch /path/to/project
# 16. Start the MCP server over stdiocode-graph serve## Code Graph (`code-graph` MCP) — Mandatory Token-Saving Workflow
1. **Architecture First (`GRAPH_REPORT.md` / `get_architecture_map`):** - At the start of a task, check `GRAPH_REPORT.md` (or call `get_architecture_map`) to identify subsystem clusters, God Nodes, and event channels before browsing directories.2. **Before Editing Any Symbol (`get_edit_context`):** - Always call `get_edit_context(symbol="<name>", budget_tokens=4000)` BEFORE modifying a function, method, or class. - It provides: (1) File skeleton (imports, types, structs/interfaces, class vars, constants), (2) Full target function body with line numbers, (3) Used member definitions & short same-file callee bodies, (4) Direct caller `±5L` windows, (5) Other function signatures in the file, (6) Style hints, and (7) `Coverage Warnings`. - Do **NOT** read the full file after calling `get_edit_context`; apply your `Edit` directly using the returned line numbers.3. **Before Deleting, Renaming, or Changing Signatures (`check_rename_or_delete`):** - Always call `check_rename_or_delete(symbol="<name>")` before removing a symbol or changing its signature to verify all `exact`/`scoped` callers, inheritance overrides, scene/template connections, and dynamic string references (`getattr`, `call("x")`).4. **Targeted Impact, Cross-Language Contracts & Flow Queries:** - Use `get_symbol_impact(symbol="<name>", depth=2)` to inspect upstream/downstream call chains and cross-language contracts (`OpSGMOnline` <-> `S_GM_ONLINE = 0xCC`, `json:"max_chars_per_ip"` <-> `'multi_guard.max_chars_per_ip'` <-> `seed/*.json`). - Use `find_flow(from_symbol="<A>", to_symbol="<B>")` to trace execution or event paths between two symbols. - Use `search_symbols(query="<concept or name>")` to search code symbols, comments/docstrings (`"attack stat"` -> `KOAP`), `seed/*.json` records, and `locales/*.json` keys together.5. **Testing, Translation Audits & Code Review (`tests_for`, `check_translations`, `get_diff_impact`):** - Call `tests_for(symbol="<name>")` instead of guessing test commands (`go test -run ...`, `godot --headless -s ...`). - Call `check_translations()` after touching `tr("...")`, `noticeT(...)`, or `locales/` files to catch missing keys, accidental raw non-key strings, and `%d`/`%s` placeholder mismatches. - For code review (`final-reviewer`), call `get_diff_impact(base_ref="HEAD")` to get modified symbols, affected callers, cross-language contracts, and runnable tests in a single call.6. **No Unbounded Reads on Large Files (>300 Lines):** - Never call `Read` on a source file >300 lines without `offset` and `limit` (enforced by the `code-graph` `PreToolUse` hook).# .codegraphignore*.pb.go*.generated.tsthird_party/fixtures/large_dumps/.venv/bin/python tests/test_end_to_end.py