reference-mcp
# reference-mcp
An [MCP](https://modelcontextprotocol.io) server whose tools help an AI agent **comprehend a
codebase** — get oriented, navigate by meaning rather than text, trace relationships, and
understand *why* code is shaped the way it is.
It builds its own [tree-sitter](https://tree-sitter.github.io/) index of a Python project (no
language servers required) and exposes a small set of consolidated, high-leverage tools designed
around current agent tool-design best practices: human-readable returns, built-in token
budgeting and pagination, and actionable errors.
## Tools
| Tool | What it answers |
|------|-----------------|
| `repo_overview` | "What is this project?" — languages, layout, entry points, tests, configs. |
| `get_file_outline` | "What's in this file?" — symbol skeleton without reading bodies. |
| `find_symbol` | "Where is X defined?" — locate a function/class/method/var, optionally with body. |
| `find_references` | "Where is X used?" — call sites and usages with context. |
| `search_code` | "Where is the code that …?" — lexical/regex search, or natural-language **semantic** search (optional). |
| `get_dependencies` | "What does this import / what depends on it?" — forward and reverse deps. |
| `code_history` | "Why is this code here?" — git blame/log/churn for a symbol or region. |
| `find_tests` | "What tests cover this?" — symbol ⇄ test mapping. |
| `trace_call_graph` | "What calls this / what does it call?" — callers/callees to N levels. |
| `get_type_hierarchy` | "What's the class tree?" — subclasses, superclasses, implementations. |
## Quickstart
```bash
uv sync --extra dev
# Point the server at a codebase and run it over stdio:
REFERENCE_MCP_REPO=/path/to/your/project uv run reference-mcp
# Or inspect interactively:
npx @modelcontextprotocol/inspector uv run reference-mcp
```
### Semantic search (optional)
Lexical search works out of the box. To also enable natural-language search
("where is auth handled?"), install the local-embeddings extra — no API key, no
network at query time once the model is cached:
```bash
uv sync --extra semantic
```
Then call `search_code` with `mode="semantic"`. It embeds each symbol
(name + signature + docstring) with [fastembed](https://github.com/qdrant/fastembed)
(ONNX, model `BAAI/bge-small-en-v1.5` by default, override via
`REFERENCE_MCP_EMBED_MODEL`), caches the vectors in the index cache dir, and ranks
by cosine similarity. Without the extra, `mode="semantic"` returns install guidance
instead of failing.
### Register with an MCP client
```json
{
"mcpServers": {
"reference": {
"command": "uv",
"args": ["run", "reference-mcp"],
"env": { "REFERENCE_MCP_REPO": "/path/to/your/project" }
}
}
}
```
## Configuration
| Env var | Default | Purpose |
|---------|---------|---------|
| `REFERENCE_MCP_REPO` | cwd | Absolute path to the codebase to analyze. |
| `REFERENCE_MCP_CACHE_DIR` | `~/.cache/reference-mcp` | Where the SQLite index is stored (never inside your repo). |
| `REFERENCE_MCP_TOKEN_BUDGET` | `25000` | Soft per-response token cap. |
## Design notes
- **Read-only.** The server never edits your code; it only reads and indexes it.
- **Incremental index.** Files are re-parsed only when their content hash changes.
- **Precision tradeoff.** Reference/call-graph resolution is scope- and import-aware
name matching, not full type inference. Accurate for most Python; a future LSP backend can
slot in behind the same tool surface for dynamic-dispatch-heavy code. To curb false
positives, `find_references` ignores matches inside strings/comments (tree-sitter span
masking), and `trace_call_graph` drops an `obj.method()` call when its name matches several
methods. The residual case it cannot resolve: an `obj.method()` call whose name matches
exactly one project method of an unrelated type (e.g. a `dict.get()` call when the project
defines a single `get` method) — undecidable without type inference.
## Development
```bash
uv run ruff check . # lint
uv run ruff format . # format
uv run mypy # type-check (src/)
uv run pytest # unit + integration tests
uv run python evals/run_evals.py # eval harness (must be 100%)
```
CI runs all of the above on every push and PR (see [.github/workflows/ci.yml](.github/workflows/ci.yml)).
TDQS
Scored across 10 tools
Each tool targets a distinct aspect of code analysis (e.g., symbol definition vs. references vs. call graph), with no overlap in purpose. Descriptions clearly differentiate them.
Most tools follow a verb_noun pattern (find_symbol, search_code, get_file_outline, trace_call_graph), with a few exceptions like repo_overview and code_history that are still clear and not confusing.
10 tools is well-scoped for a code reference server, covering all major analysis needs without bloat. Each tool serves a clear, non-redundant purpose.
The tool surface is comprehensive, covering repo overview, file outline, symbol definition, references, call graph, dependencies, tests, type hierarchy, search, and git history. No obvious gaps for understanding a codebase.