MCP server · RAG · TypeScript
Codebase Copilot
Gives Claude Code, Cursor and Claude Desktop real code search over any repository: syntax-aware chunking, local embeddings, hybrid retrieval — and a measured answer to “is it actually better than naive RAG?”
- Recall@5
- 80% → 88%
- Recall@1
- 44% → 62%
- MRR@10
- 0.60 → 0.73
- Query latency
- 5 ms
Naive windows + dense baseline → AST chunks + hybrid. 50 hand-verified questions over honojs/hono.
Try the retriever
The same engine the MCP tools call.
Measured, not assumed
50 questions a new contributor might ask, each mapped by hand to the exact function that answers it. 30 are phrased without any identifier from the target. A result only counts if it is in the right file and overlaps the right lines.
| Configuration | Recall@1 | Recall@5 | MRR@10 | Latency |
|---|---|---|---|---|
| Naive 50-line windows + dense (baseline) | 44% | 80% | 0.60 | 5 ms |
| Naive windows + hybrid | 54% | 84% | 0.67 | 5 ms |
| AST chunks + dense | 50% | 80% | 0.64 | 5 ms |
| AST chunks + BM25 | 60% | 86% | 0.69 | <1 ms |
| AST chunks + hybrid (RRF) | 62% | 88% | 0.73 | 5 ms |
| AST chunks + hybrid + cross-encoder rerank | 46% | 80% | 0.60 | 658 ms |
The surprise: a general-domain cross-encoder reranker (ms-marco-MiniLM) lowered Recall@5 from 88% to 80% and cost 658 ms per query. It was trained on web passages, not code, so it ships disabled. Toggle it above to see it reorder results.
How it works
01
Parse
tree-sitter (WASM) splits each file into functions, methods, classes and types — not arbitrary 50-line windows. Class fields holding arrow functions count as methods; runs of tiny type aliases are merged.
02
Embed
bge-small-en-v1.5 runs locally through ONNX Runtime — in the CLI and inside the Vercel function. No embedding API, no key, 10 ms per warm query.
03
Retrieve
Cosine search over a flat Float32 file plus BM25 with a code-aware tokenizer (getCookieValue → get, cookie, value), fused with reciprocal-rank fusion.
04
Serve
One tool registry, two transports: stdio for local repos, Streamable HTTP for this hosted demo. The host model does the reasoning; the server only retrieves.
Connect it to your editor
Hosted demo (searches honojs/hono), Streamable HTTP:
claude mcp add --transport http codebase-copilot https://codebase-copilot-omega.vercel.app/api/mcpYour own repository, fully local over stdio:
git clone https://github.com/yashharkawat/codebase-copilot && cd codebase-copilot && npm install
npm run cli -- index /path/to/your/repo --id myrepo
claude mcp add codebase-copilot -- npx tsx $PWD/cli/main.ts servecopilot_search_codeHybrid semantic + keyword search. Returns symbol-level chunks with file:line citations.copilot_get_symbolFull definition of a function, class, method or type by name.copilot_find_usagesEvery whole-word reference to an identifier, paginated.copilot_read_chunkA chunk plus its neighbours from the same file.copilot_list_reposWhat is indexed: commit, languages, chunk counts.
Security posture
- Every tool is read-only and answers from the index — no request value ever becomes a file path.
- Zod validation on every route and tool; identifier search uses indexOf, never a user-built RegExp.
- The indexer skips .env, keys and any file matching credential patterns.
- Retrieved code is treated as untrusted: fenced with a per-request random tag, and the answering model has no tools.
- Nonce-based CSP, code rendered as text nodes only, per-IP rate limits, no stack traces to clients.
- Only
:freemodel ids can be called — a paid slug throws before any request is made.