An MCP server that gives Claude Code real structural understanding of a codebase — via tree-sitter AST parsing — before it starts a task. The goal is to cut down on wasted tokens from re-reading/re-discovery, tighten task scope, and ground acceptance criteria in the code's actual structure instead of guesswork.
Handing an agent a task usually goes wrong for one of three reasons:
- Insufficient context — the agent greps and re-reads files it's already seen, burning tokens rediscovering things a proper index already knows.
- Ambiguous scope — "fix the auth bug" has no stated boundary, so the agent decides its own, and scope creep follows.
- Missing acceptance criteria — "make sure it works" isn't checkable, so there's no way to tell if the task actually finished.
Context-MCP addresses all three with structural, deterministic data — no LLM calls happen inside the server itself. It returns facts; Claude Code does the reasoning.
Similar tools (e.g. preflight-dev/preflight) mine session logs and use regex-based contract extraction — inference from past conversations. Context-MCP parses the actual source with tree-sitter and builds a real symbol index and reference graph, so what it returns is ground truth about the code as it exists right now, not a guess based on what happened before.
Two pieces working together:
-
The MCP server (this repo's actual product) — exposes
get_context_map,validate_brief,check_scope, andlist_symbols. Does all the real analysis. -
A companion PreToolUse hook (
hooks/pretooluse_gate.py, ~100 lines) — blocksEdit/Writetool calls unless the MCP server has already written a validbrief_idfor the session. The hook does no analysis of its own; it only enforces call order, which an MCP server alone cannot do, since nothing stops an agent from simply not calling a given tool. Most MCP-only tools skip this layer and rely on the agent choosing to cooperate.This enforcement is real but not absolute — see Known limitations.
Requires Python 3.11+.
git clone <this-repo-url> Context-MCP
cd Context-MCP
python -m venv .venv
# macOS/Linux
.venv/bin/pip install -r requirements.txt
# Windows
.venv\Scripts\pip install -r requirements.txtRegister it against any project you want structural context for — it doesn't need to live inside that project. Point it at wherever you cloned it:
# from inside the project you want to analyze
claude mcp add context-mcp --scope project -- \
/absolute/path/to/Context-MCP/.venv/bin/python \
/absolute/path/to/Context-MCP/src/server.py(On Windows, the interpreter is at
...\Context-MCP\.venv\Scripts\python.exe.)
Or copy .mcp.json.example to .mcp.json in the target
project and fill in the real paths yourself.
This alone gives you get_context_map, list_symbols, validate_brief, and
check_scope as callable tools — useful on their own, with no enforcement.
Registering the hook means every Edit/Write in that project gets
gated behind a validated brief — including edits unrelated to whatever task
you're consciously briefing. Only add it to a project where you actually want
that discipline enforced.
Copy .claude/settings.json.example to
.claude/settings.json in the target project, filling in your own absolute
paths. Use forward slashes and the args array form (not a single
backslash-joined command string — see
Known limitations for why that matters on Windows).
# 1. Before touching code, ask what's relevant
get_context_map("AuthService")
# 2. Submit a brief — required before any Edit/Write will be allowed
validate_brief({
"target": "AuthService",
"scope": {
"in_scope": ["src/auth/service.py", "src/auth/routes.py"],
"out_scope": ["src/db/"]
},
"acceptance_criteria": [
"login() returns a signed JWT with a 1-hour expiry",
"invalid credentials return 401, not 500"
]
})
# 3. Work normally — Edit/Write are checked against in_scope automatically
# 4. Optionally audit drift explicitly before finishing
check_scope(brief_id, files_touched)
validate_brief rejects the brief outright if acceptance criteria are empty
or vague (a keyword blocklist catches things like "it works", "should work"),
if scope has no in/out boundary, or if the target doesn't resolve against the
repo's symbol index — catching typos or hallucinated file/symbol names before
any work starts.
- The hook only covers
EditandWrite. ABashorPowerShellcall can write files directly and completely bypass the gate — this was found by direct testing, not theorized. It isn't fixable by widening the tool matcher alone: reliably classifying "is this shell command about to write a file" without running it isn't possible. Enforcement here is real for the tools it covers, not an unconditional guarantee. - Windows shell quoting is unforgiving. If Git Bash is present, hook
commands run through bash, which strips backslashes from a single joined
command string. Always use forward slashes and the
argsarray form in hook config, not acommandstring built from Windows-style paths. - Dynamic imports and reflection-like patterns (e.g.
require(computedPath), dynamicimportlibcalls) can't be resolved statically by tree-sitter and won't show up in the reference graph. - Language support is currently Python, JavaScript, and TypeScript/TSX only.
- No published before/after benchmark yet. The mechanism is verified working end-to-end; a real token-usage / scope-accuracy comparison against running tasks without this tool hasn't been run yet. Treat claims of "improves your workflow" as unproven until that data exists.
MIT — see LICENSE.