Skip to main content
Glama
mark-burg

reference-mcp

by mark-burg
README.md
# 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

A4.4/5.0

Scored across 10 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness5/5

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.

Maintenance

ActivityInactive
ResponsivenessNo issues