A structural codebase indexer with an MCP server for AI-assisted development. Zero runtime dependencies — uses Python's ast module for Python analysis and regex-based parsing for TypeScript/JS, Go, and Rust. Requires Python 3.11+. Indexes codebases by parsing source files into structural metadata -- functions, classes, imports, dependency graphs, and cross-file call chains -- then exposes 18 query
Add this skill
npx mdskills install MikeRecognex/mcp-codebase-indexExceptionally well-documented structural codebase indexer with 18 MCP tools, benchmarks, and persistent caching
1<!-- mcp-name: io.github.MikeRecognex/mcp-codebase-index -->2# mcp-codebase-index34[](https://pypi.org/project/mcp-codebase-index/)5[](https://github.com/MikeRecognex/mcp-codebase-index/actions/workflows/ci.yml)6[](https://www.python.org/downloads/)7[](https://www.gnu.org/licenses/agpl-3.0)8[](https://modelcontextprotocol.io)9[]()1011A structural codebase indexer with an [MCP](https://modelcontextprotocol.io) server for AI-assisted development. Zero runtime dependencies — uses Python's `ast` module for Python analysis and regex-based parsing for TypeScript/JS, Go, and Rust. Requires Python 3.11+.1213## What It Does1415Indexes codebases by parsing source files into structural metadata -- functions, classes, imports, dependency graphs, and cross-file call chains -- then exposes 18 query tools via the Model Context Protocol, enabling Claude Code and other MCP clients to navigate codebases efficiently without reading entire files.1617**Automatic incremental re-indexing:** In git repositories, the index stays up to date automatically. Before every query, the server checks `git diff` and `git status` (~1-2ms). If files changed, only those files are re-parsed and the dependency graph is rebuilt. No need to manually call `reindex` after edits, branch switches, or pulls.1819**Persistent disk cache:** The index is saved to a pickle cache file (`.codebase-index-cache.pkl`) after every build. On subsequent server starts, the cache is loaded and validated against the current git HEAD — if the ref matches, startup is instant. If a small number of files changed (≤20), the cached index is loaded and incrementally updated instead of rebuilt from scratch. This eliminates the cold-start penalty when restarting Claude Code sessions, restarting the MCP server, or resuming work after context compaction.2021## Language Support2223| Language | Method | Extracts |24|----------|--------|----------|25| Python (`.py`) | AST parsing | Functions, classes, methods, imports, dependency graph |26| TypeScript/JS (`.ts`, `.tsx`, `.js`, `.jsx`) | Regex-based | Functions, arrow functions, classes, interfaces, type aliases, imports |27| Go (`.go`) | Regex-based | Functions, methods (receiver-based), structs, interfaces, type aliases, imports, doc comments |28| Rust (`.rs`) | Regex-based | Functions (`pub`/`async`/`const`/`unsafe`), structs, enums, traits, impl blocks, use statements, attributes, doc comments, macro_rules |29| Markdown/Text (`.md`, `.txt`, `.rst`) | Heading detection | Sections (# headings, underlines, numbered, ALL-CAPS) |30| Other | Generic | Line counts only |3132## Installation3334```bash35pip install "mcp-codebase-index[mcp]"36```3738The `[mcp]` extra includes the MCP server dependency. Omit it if you only need the programmatic API.3940For development (from a local clone):4142```bash43pip install -e ".[dev,mcp]"44```4546## MCP Server4748### Running4950```bash51# As a console script52PROJECT_ROOT=/path/to/project mcp-codebase-index5354# As a Python module55PROJECT_ROOT=/path/to/project python -m mcp_codebase_index.server56```5758`PROJECT_ROOT` specifies which directory to index. Defaults to the current working directory.5960### Persistent Cache6162In git repositories, the server automatically caches the index to `.codebase-index-cache.pkl` in the project root. On startup:63641. **Cache hit (exact match):** If the cached git ref matches the current HEAD, the index loads instantly from disk — no parsing, no file walking.652. **Cache hit (small changeset):** If ≤20 files changed since the cached ref, the cached index is loaded and incrementally updated on the first query.663. **Cache miss:** If the changeset is large or no cache exists, a full rebuild runs and saves a new cache.6768Add `.codebase-index-cache.pkl` to your `.gitignore` — it's a local-only build artifact.6970### Configuring with OpenClaw7172Install the package on the machine where OpenClaw is running:7374```bash75# Local install76pip install "mcp-codebase-index[mcp]"7778# Or inside a Docker container / remote VPS79docker exec -it openclaw bash80pip install "mcp-codebase-index[mcp]"81```8283Add the MCP server to your OpenClaw agent config (`openclaw.json`):8485```json86{87 "agents": {88 "list": [{89 "id": "main",90 "mcp": {91 "servers": [92 {93 "name": "codebase-index",94 "command": "mcp-codebase-index",95 "env": {96 "PROJECT_ROOT": "/path/to/project"97 }98 }99 ]100 }101 }]102 }103}104```105106Restart OpenClaw and verify the connection:107108```bash109openclaw mcp list110```111112All 18 tools will be available to your agent.113114**Performance note:** The server automatically detects file changes via `git diff` before every query (~1-2ms) and incrementally re-indexes only what changed. However, OpenClaw's default MCP integration via mcporter spawns a fresh server process per tool call, which discards the in-memory index and forces a full rebuild each time (~1-2s for small projects, longer for large ones). With persistent caching, these cold starts are now significantly faster — the server loads from the disk cache instead of re-parsing the entire codebase. For persistent connections (avoiding even the cache load overhead), use the [openclaw-mcp-adapter](https://github.com/androidStern-personal/openclaw-mcp-adapter) plugin, which connects once at startup and keeps the server running:115116```bash117pip install openclaw-mcp-adapter118```119120### Configuring with Claude Code121122Add to your project's `.mcp.json`:123124```json125{126 "mcpServers": {127 "codebase-index": {128 "command": "mcp-codebase-index",129 "env": {130 "PROJECT_ROOT": "/path/to/project"131 }132 }133 }134}135```136137Or using the Python module directly (useful if installed in a virtualenv):138139```json140{141 "mcpServers": {142 "codebase-index": {143 "command": "/path/to/.venv/bin/python3",144 "args": ["-m", "mcp_codebase_index.server"],145 "env": {146 "PROJECT_ROOT": "/path/to/project"147 }148 }149 }150}151```152153#### Reinforcing Tool Usage with Hooks154155Claude Code tends to default to built-in Glob/Grep/Read tools even when codebase-index is available. In addition to CLAUDE.md instructions (see below), you can add hooks that fire on every prompt to reinforce the behavior. Add this to `.claude/settings.local.json`:156157```json158{159 "hooks": {160 "SessionStart": [161 {162 "hooks": [163 {164 "type": "command",165 "command": "echo 'CRITICAL REMINDER: Use codebase-index MCP tools FIRST for ALL code navigation (find_symbol, get_function_source, search_codebase, get_dependencies, etc). Only fall back to Glob/Grep/Read for non-code files.'"166 }167 ]168 }169 ],170 "UserPromptSubmit": [171 {172 "hooks": [173 {174 "type": "command",175 "command": "echo 'Use codebase-index MCP tools first for code navigation.'"176 }177 ]178 }179 ]180 }181}182```183184Hook stdout is injected as context Claude sees before responding. `SessionStart` fires on startup, resume, and context compaction. `UserPromptSubmit` fires on every turn.185186### Important: Make the AI Actually Use Indexed Tools187188By default, AI assistants will ignore the indexed tools and fall back to reading entire files with Glob/Grep/Read. Soft language like "prefer" gets rationalized away. Add this to your project's `CLAUDE.md` (or equivalent instructions file) with **mandatory** language:189190```191## Codebase Navigation — MANDATORY192193You MUST use codebase-index MCP tools FIRST when exploring or navigating the codebase. This is not optional.194195- ALWAYS start with: get_project_summary, find_symbol, get_function_source, get_class_source,196 get_structure_summary, get_dependencies, get_dependents, get_change_impact, get_call_chain, search_codebase197- Only fall back to Read/Glob/Grep when codebase-index tools genuinely don't have what you need198 (e.g. reading non-code files, config, frontmatter)199- If you catch yourself reaching for Glob/Grep/Read to find or understand code, STOP and use200 codebase-index instead201```202203The word "prefer" is too weak — models treat it as a suggestion and default to familiar tools. Mandatory language with explicit fallback criteria is what actually changes behavior.204205### Available Tools (18)206207| Tool | Description |208|------|-------------|209| `get_project_summary` | File count, packages, top classes/functions |210| `list_files` | List indexed files with optional glob filter |211| `get_structure_summary` | Structure of a file or the whole project |212| `get_functions` | List functions with name, lines, params |213| `get_classes` | List classes with name, lines, methods, bases |214| `get_imports` | List imports with module, names, line |215| `get_function_source` | Full source of a function/method |216| `get_class_source` | Full source of a class |217| `find_symbol` | Find where a symbol is defined (file, line, type) |218| `get_dependencies` | What a symbol calls/uses |219| `get_dependents` | What calls/uses a symbol |220| `get_change_impact` | Direct + transitive dependents |221| `get_call_chain` | Shortest dependency path (BFS) |222| `get_file_dependencies` | Files imported by a given file |223| `get_file_dependents` | Files that import from a given file |224| `search_codebase` | Regex search across all files (max 100 results) |225| `reindex` | Force full re-index (rarely needed — incremental updates happen automatically in git repos) |226| `get_usage_stats` | Session efficiency stats: tool calls, characters returned vs total source, estimated token savings |227228## Benchmarks229230Tested across four real-world projects on an M-series MacBook Pro, from a small project to CPython itself (1.1 million lines):231232### Index Build Performance233234| Project | Files | Lines | Functions | Classes | Index Time | Peak Memory |235|---------|------:|------:|----------:|--------:|-----------:|------------:|236| RMLPlus | 36 | 7,762 | 237 | 55 | 0.9s | 2.4 MB |237| FastAPI | 2,556 | 332,160 | 4,139 | 617 | 5.7s | 55 MB |238| Django | 3,714 | 707,493 | 29,995 | 7,371 | 36.2s | 126 MB |239| **CPython** | **2,464** | **1,115,334** | **59,620** | **9,037** | **55.9s** | **197 MB** |240241With persistent caching, subsequent startups bypass the full build entirely. Cache load time is negligible compared to parsing — a cache hit on CPython restores the full index in under a second instead of 56s.242243### Query Response Size vs Total Source244245Querying CPython — 41 million characters of source code:246247| Query | Response | Total Source | Reduction |248|-------|-------:|------------:|----------:|249| `find_symbol("TestCase")` | 67 chars | 41,077,561 chars | **99.9998%** |250| `get_dependencies("compile")` | 115 chars | 41,077,561 chars | **99.9997%** |251| `get_change_impact("TestCase")` | 16,812 chars | 41,077,561 chars | **99.96%** |252| `get_function_source("compile")` | 4,531 chars | 41,077,561 chars | **99.99%** |253| `get_function_source("run_unittest")` | 439 chars | 41,077,561 chars | **99.999%** |254255`find_symbol` returns 54-67 characters regardless of whether the project is 7K lines or 1.1M lines. Response size scales with the answer, not the codebase.256257`get_change_impact("TestCase")` on CPython found **154 direct dependents and 492 transitive dependents** in 0.45ms — the kind of query that's impossible without a dependency graph. Use `max_direct` and `max_transitive` to cap output to your token budget.258259### Query Response Time260261All targeted queries return in sub-millisecond time, even on CPython's 1.1M lines:262263| Query | RMLPlus | FastAPI | Django | CPython |264|-------|--------:|--------:|-------:|--------:|265| `find_symbol` | 0.01ms | 0.01ms | 0.03ms | 0.08ms |266| `get_dependencies` | 0.00ms | 0.00ms | 0.00ms | 0.01ms |267| `get_change_impact` | 0.02ms | 0.00ms | 2.81ms | 0.45ms |268| `get_function_source` | 0.01ms | 0.02ms | 0.03ms | 0.10ms |269270Run the benchmarks yourself: `python benchmarks/benchmark.py`271272## How Is This Different from LSP?273274LSP answers "where is this function?" — mcp-codebase-index answers "what happens if I change it?" LSP is point queries: one symbol, one file, one position. It can tell you where `LLMClient` is defined and who references it. But ask "what breaks transitively if I refactor `LLMClient`?" and LSP has nothing. This tool returns 11 direct dependents and 31 transitive impacts in a single call — 204 characters. To get the same answer from LSP, the AI would need to chain dozens of find-reference calls recursively, reading files at every step, burning thousands of tokens to reconstruct what the dependency graph already knows.275276LSP also requires you to install a separate language server for every language in your project — pyright for Python, vtsls for TypeScript, gopls for Go. Each one is a heavyweight binary with its own dependencies and configuration. mcp-codebase-index is zero dependencies, handles Python + TypeScript/JS + Go + Rust + Markdown out of the box, and every response has built-in token budget controls (`max_results`, `max_lines`). LSP was built for IDEs. This was built for AI.277278## Programmatic Usage279280```python281from mcp_codebase_index.project_indexer import ProjectIndexer282from mcp_codebase_index.query_api import create_project_query_functions283284indexer = ProjectIndexer("/path/to/project", include_patterns=["**/*.py"])285index = indexer.index()286query_funcs = create_project_query_functions(index)287288# Use query functions289print(query_funcs["get_project_summary"]())290print(query_funcs["find_symbol"]("MyClass"))291print(query_funcs["get_change_impact"]("some_function"))292```293294## Development295296```bash297pip install -e ".[dev,mcp]"298pytest tests/ -v299ruff check src/ tests/300```301302## References303304The structural indexer was originally developed as part of the [RMLPlus](https://github.com/MikeRecognex/RMLPlus) project, an implementation of the [Recursive Language Models](https://arxiv.org/abs/2512.24601) framework.305306## License307308This project is dual-licensed:309310- **AGPL-3.0** for open-source use — see [LICENSE](LICENSE)311- **Commercial License** for proprietary use — see [COMMERCIAL-LICENSE.md](COMMERCIAL-LICENSE.md)312313If you're using mcp-codebase-index as a standalone MCP server for development, the AGPL-3.0 license applies at no cost. If you're embedding it in a proprietary product or offering it as part of a hosted service, you'll need a commercial license. See [COMMERCIAL-LICENSE.md](COMMERCIAL-LICENSE.md) for details.314
Full transparency — inspect the skill content before installing.