Context-MCP
by V1Adait
README.md
# Context-MCP
An MCP server that gives Claude Code real structural understanding of a
codebase — via [tree-sitter](https://tree-sitter.github.io/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.
## The problem
Handing an agent a task usually goes wrong for one of three reasons:
1. **Insufficient context** — the agent greps and re-reads files it's already
seen, burning tokens rediscovering things a proper index already knows.
2. **Ambiguous scope** — "fix the auth bug" has no stated boundary, so the
agent decides its own, and scope creep follows.
3. **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.
## How it's different
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.
## Architecture
Two pieces working together:
- **The MCP server** (this repo's actual product) — exposes `get_context_map`,
`validate_brief`, `check_scope`, and `list_symbols`. Does all the real
analysis.
- **A companion PreToolUse hook** (`hooks/pretooluse_gate.py`, ~100 lines) —
blocks `Edit`/`Write` tool calls unless the MCP server has already written a
valid `brief_id` for 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](#known-limitations).
## Install
Requires Python 3.11+.
```bash
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.txt
```
## Register the server
Register 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:
```bash
# 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`](.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.
## Adding the enforcement gate (optional)
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`](.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](#known-limitations) for why that matters on Windows).
## Usage
```
# 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.
## Known limitations
- **The hook only covers `Edit` and `Write`.** A `Bash` or `PowerShell` call
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 `args` array form in
hook config, not a `command` string built from Windows-style paths.
- **Dynamic imports and reflection-like patterns** (e.g. `require(computedPath)`,
dynamic `importlib` calls) 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.
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues