- Rust 99.8%
- Shell 0.2%
| docs | ||
| src | ||
| .gitignore | ||
| build.sh | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
| rust-toolchain.toml | ||
| todo.md | ||
code-docs-mcp
Semantic code-and-documentation indexing exposed as an MCP server. Lets LLM coding agents search your project's docs, read-only repos, and code call graph via natural language.
Quick Start
1. Create a config
# ~/.config/code-docs-mcp/<project-name>/config.toml
[workspace]
name = "my-project"
[references]
[[references.sources]]
path = "~/src/my-project/docs"
tags = ["docs", "design-inspiration"]
description = "Shared docs source used as a design reference"
[[references.sources]]
path = "~/src/my-project/notes"
tags = ["notes", "product"]
description = "Working notes and decision log"
[[read.repos]]
url = "https://github.com/some-org/dependency.git"
tags = ["dependency", "design-inspiration"]
description = "Shared dependency used as a design reference"
[[read.repos]]
url = "https://github.com/some-org/another-repo.git"
tags = ["typescript", "lint-rules"]
description = "Reference implementation for TypeScript linting rules"
[write]
urls = ["git@github.com:me/my-project.git"]
Project auto-detection works by matching the current directory's git remote URLs against the [write] section.
Tagged reference sources and read-only repositories help the model understand why each corpus exists and which searches should target it. Tags are matched case-insensitively and with OR semantics: any matching tag includes the source in search_tagged.
If you do not have a config yet, run code-docs-mcp init to print a best-effort config generated from the git repos detected in the current workspace. You can copy that output directly into ~/.config/code-docs-mcp/<project>/config.toml.
If you want the file written for you, use code-docs-mcp init --write.
2. Build indexes
# Clone/pull read-only repos and build the AST call graph from write code
code-docs-mcp sync
# Chunk and embed reference docs and read repos into vector stores
# (run this after sync to re-index any new/changed content)
code-docs-mcp ingest
# Or do both in one pass:
code-docs-mcp refresh
# For OCR on images in docs:
code-docs-mcp ingest --ocr
# For CLIP visual embeddings (useful when searching images directly):
code-docs-mcp ingest --visual
synconly pulls/clones repos — it does not re-index them.
After pulling fresh content (or on any subsequent visit), runrefreshto keep both the cloned repos and the vector indexes up to date.refreshrunssyncfirst, theningest, and both steps reuse their existing caches so repeated runs stay cheap when nothing changed. If one of the index stores is already being updated by another process,refreshwill warn and continue with the remaining stores instead of aborting the whole run.
Pre-release Smoke Test
Before shipping a release, run the following from a configured workspace:
code-docs-mcp config-check
code-docs-mcp refresh --batch-size 4
code-docs-mcp search -q "project architecture" -k 5
Then modify or delete one indexed file and run code-docs-mcp refresh again. Confirm
that search still works, and manually verify that cancelling a background sync or
ingest task stops the child process without leaving a broken index. The ignored
model-backed concurrency test can be run with:
cargo test --all-targets --all-features real_ingestion_and_search_are_generation_consistent -- --ignored --nocapture
3. Start the MCP server
code-docs-mcp serve
The server speaks JSON-RPC 2.0 over stdio.
Server-side search limits are enforced to protect the process: queries are
limited to 16,384 characters, result pages to 100 items, offsets to 1,000,000,
token budgets to 16,384 tokens, and ingestion batches to 4,096 chunks. Invalid
arguments return JSON-RPC -32602; backend failures return -32603.
When running as an MCP server, stdout is reserved for JSON-RPC responses. Human
diagnostics and model-loading progress are written to stderr or the MCP log.
Malformed JSON returns -32700, invalid JSON-RPC requests and arguments return
-32600 or -32602, and unknown methods/tools return -32601. Search fails
when an index sidecar is unreadable or malformed rather than returning silently
partial corpus metadata. If some CLI stores fail to query, the CLI reports a
warning; if all candidate stores fail, the command exits unsuccessfully.
For MCP initialization, the server preserves the protocol version it recognizes
exactly when it can, and falls back to the current server capability set for
unknown future versions so new clients do not need exact version pinning.
MCP Tools
| Tool | Description |
|---|---|
search_references |
Semantic search across tagged reference sources |
search_read_repos |
Semantic search across cloned read-only repositories |
search_all |
Search tagged reference sources and all tagged read repos in one pass |
search_tagged |
Search any tagged source whose tags match the requested topics |
list_reference_sources |
List configured tagged reference sources with paths, tags, and storage locations |
list_read_repos |
List configured tagged read repos with tags, branch, and purpose |
get_reference_tree |
Show the directory tree for a configured tagged reference source |
get_repo_tree |
Show the checkout tree for a configured read repo |
find_callers |
Find callers of a function/method in the write code graph |
The MCP server also exposes a project://profile resource that returns the resolved workspace, tagged reference sources, write remotes, and read-repo metadata as JSON. Agents can use that resource to understand the configured corpus before choosing a search tool.
CLI Commands
| Command | Description |
|---|---|
sync |
Clone/pull read-only repos; scan write source and build AST call graph |
refresh |
Run sync then ingest in one command |
ingest |
Chunk and embed tagged reference sources and read repos into RVF vector stores |
search |
Query existing vector stores from the terminal (-q <query>) |
callers |
Look up callers of a symbol (-s <symbol>) |
init |
Print a best-effort config generated from the current workspace's detected git repos |
serve |
Run the MCP stdio server |
config-check |
Validate all discovered config files |
CLI commands print human-readable progress and results to stdout. serve is
the machine-readable mode: its stdout contains only JSON-RPC responses, while
diagnostics go to stderr or the MCP log. CLI search uses the same query,
pagination, token, and batch-size limits as the MCP tools.
How It Works
- Reference ingestion: Tagged local reference sources are chunked, embedded (fastembed/ONNX), and stored in per-source RVF vector stores for semantic search.
- Read-only repos: Configured Git repos are cloned to
~/.local/share/code-docs-mcp/<project>/read/under branch-aware checkout names, then indexed similarly. - Write code graph: Your project's source code is parsed with tree-sitter (Python, Rust, TypeScript) into a SQLite call graph at
~/.cache/code-docs-mcp/<project>/write_graph.db. - Config discovery: Config files live in
~/.config/code-docs-mcp/<name>/config.toml. The active project is resolved by matching the current Git repo's remote URL against[write]entries.
Data Layout
~/.config/code-docs-mcp/<project>/config.toml
~/.local/share/code-docs-mcp/<project>/
├── references_<source>.rvf
├── references_<source>.meta.json
├── references_<source>_state.db
├── read/<repo-target>/
├── read_<repo-target>.rvf
├── read_<repo-target>.meta.json
└── read_<repo-target>_state.db
~/.cache/code-docs-mcp/<project>/
├── write_graph.db
└── mcp.log