Semantic code search, like zilliztech's claude-context MCP server, indexes a codebase as hybrid BM25 plus dense vectors so a coding agent retrieves the few relevant functions instead of grepping and reading whole files, cutting token usage by roughly 40% at equivalent retrieval quality per the project's own controlled evaluation. It re-embeds only changed files using a Merkle-tree diff, so re-indexing after a commit stays cheap, and it ships first-class configs for 13-plus MCP clients including Claude Code and Cursor. Grep still wins on small repos, exact-string tasks, and one-off searches where an index never pays back its setup cost.
A coding agent dropped into an unfamiliar repository does the same thing a new engineer does: it searches. The default search is grep. The agent runs ripgrep for a symbol, gets forty hits scattered across thirty files, and then reads those files into its context window to work out which hit actually matters. On a small project that is fine. On a large monorepo it is exactly how an agent burns its entire context budget before it writes a single line of a fix. Semantic code search is the pattern teams are adopting to stop that, and the clearest signal of its momentum is zilliztech's claude-context: an MCP server that crossed 10,000 GitHub stars in April 2026 and kept climbing past 11,000 by mid-year.
Semantic code search is retrieval that matches on meaning and structure rather than exact text: the codebase is chunked, each chunk is embedded as a vector, and a query returns the closest chunks by similarity, so the agent gets the few relevant functions instead of every literal string match. The contrast with grep is stark. Grep answers "where does this exact text appear." Semantic search answers "where is the code that does this thing," which is usually the question the agent was really asking. The difference shows up directly on the token bill, because the agent stops reading whole files it never needed.
This post breaks down how semantic code search actually works, what the widely quoted ~40% token reduction did and did not measure, how incremental indexing keeps the index cheap to maintain, and, just as important, when grep is still the right call. The honest summary up front: indexing pays off on large repos and long agent sessions, and it is overkill on small ones. The engineering is in knowing which situation you are in.
01 · Why grep is the default for coding agents, and where it burns tokens
Grep is the default because it costs nothing to start: no index, no embedding API, no vector database, and it finds every literal or regex occurrence deterministically. That determinism is a genuine strength, and it is why grep will never fully go away. The problem is not the search. The problem is what the agent does next.
Grep returns line matches, not code. When an agent greps a function name and gets thirty file paths back, it cannot reason about a one-line snippet, so it reads the files. Each of those reads pushes the full text of a module into the context window, and most of that text is irrelevant to the task. Across the agent stacks we audit at Particula Tech, this whole-file-read pattern, not the model's reasoning, is what dominates the token bill on large repositories. The agent spends its budget loading code it will glance at once and never use.
The failure compounds with repo size. On a 5,000-line service the read-everything approach is cheap enough to ignore. On a monorepo with millions of lines, a single ambiguous symbol can pull dozens of large files into context, and the agent hits its window limit before it has assembled enough understanding to act. This is the same silent context bloat we described in agent tool selection at scale: the cost is invisible on a dashboard that tracks only completion tokens, and it quietly caps how large a codebase your agent can actually work in. Semantic code search attacks the read step directly by returning ranked, relevant chunks instead of file paths to open.
02 · How semantic code search works: hybrid BM25 plus dense retrieval
Semantic code search works by chunking the code along structural boundaries, embedding each chunk as a dense vector, and answering a query by combining lexical BM25 scoring with vector similarity, a design known as hybrid search. Each half covers the other's blind spot. BM25 is precise on exact identifiers and rare tokens, the things a function name or an error code depend on. Dense vectors capture meaning, so a query for "retry logic with backoff" can surface a function that never contains the word "retry." Fusing the two ranks results better than either alone.
The chunking step is where code search diverges from generic document RAG, and it matters more than teams expect. claude-context uses AST-based chunking: it parses the file into an Abstract Syntax Tree (a structural representation of the code's grammar) and cuts chunks at function and class boundaries, with a LangChain character-based splitter as an automatic fallback for anything it cannot parse. The result is that a chunk is a coherent unit of logic rather than an arbitrary 512-character window that slices a function in half. Retrieval quality on code lives or dies on this: a half-function chunk embeds to a muddy vector and retrieves badly.
Under the hood, claude-context stores those vectors in Milvus or the managed Zilliz Cloud, and it supports four embedding providers: OpenAI, VoyageAI, Ollama, and Gemini. The Ollama option matters for teams that cannot send source code to a third-party embedding API, because it keeps the whole pipeline local. If you are weighing which embedding model to point at your code, the tradeoffs mirror those in our broader work on reducing LLM token costs: a larger embedding model retrieves marginally better and costs more per index rebuild, and on code the marginal gain is usually small once chunking is done well.
03 · The ~40% token reduction, and what was actually measured
The headline figure is real but needs an honest caption. According to zilliztech's own controlled evaluation (2026), claude-context achieves roughly 40% token reduction under the condition of equivalent retrieval quality. Read every clause of that sentence. It is a self-reported number from the project's own evaluation, not an independent third-party benchmark, and the "equivalent retrieval quality" condition is the whole point: the claim is not "smaller and worse," it is "same answers, fewer tokens."
That framing is more defensible than the eye-catching two-figure percentages other tools cite, and it is worth understanding why the numbers differ so much. According to MinishLab's semble project (2026), the indexer uses about 98% fewer tokens than grep-plus-read. The gap between 40% and 98% is not one tool being wildly better than another; it is a different baseline. claude-context compares against a competent retrieval workflow, while the 98% figure compares against the naive grep-then-read-whole-files pattern, which loads far more text into context. Both can be true at once.
The more aggressive numbers come from tools that change the unit of retrieval entirely. According to the Codebase Memory MCP benchmarks (2026), a structural exploration that cost about 412,000 tokens when read file-by-file dropped to roughly 3,400 tokens through its knowledge graph, a 121x reduction, and its 31-repo controlled evaluation reported 83% answer quality with 10x fewer tokens and 2.1x fewer tool calls. When you see 98% or 121x, check the baseline before you budget against it. The practical takeaway is consistent across all of them: the savings scale with how many whole files grep would otherwise force into context, which is exactly why the effect is large on monorepos and negligible on a single service.
04 · Incremental indexing with a Merkle tree over file hashes
The maintenance cost of an index, not its build cost, is what usually kills these systems in practice, and claude-context's answer is incremental indexing via a Merkle tree over file hashes. A Merkle tree is a tree of hashes where each parent hash is derived from its children, so a single changed file changes the hashes along one path from leaf to root and nothing else. Comparing the current tree to the last indexed tree tells you precisely which files changed, and the indexer re-embeds only those.
This is the difference between an index that stays fresh and one that goes stale within a day. When we wire retrieval into enterprise coding agents, the freshness question is the one that actually decides whether an index earns its place: if every commit forced a full re-embed of the repository, nobody would keep the index current, and a stale index that points the agent at deleted or moved code is worse than grep, which is at least always correct about the current tree. The Merkle-tree diff makes the incremental update proportional to the size of the change rather than the size of the repo, so re-indexing after a normal commit touches only the files that commit changed.
The design consequence is a clean split in cost. The initial index is a one-time bulk embed of the whole codebase, which is the expensive part and scales with repo size. Every update after that is cheap and scales with churn. That asymmetry is what makes the pattern viable on a large, actively developed repository: you pay the big embedding bill once, then keep the index alive for the marginal cost of the files each commit touches.
05 · Wiring the MCP server into Claude Code and Cursor
You connect semantic code search to an agent through the Model Context Protocol, so wiring claude-context in means adding one MCP server and pointing it at your repo. MCP is an open standard that lets an agent discover and call external tools, such as a code-search index, over a uniform interface; our MCP developer guide covers the protocol end to end. claude-context ships first-class configs for 13-plus named MCP clients, including Claude Code, Cursor, Windsurf, Codex CLI, Gemini CLI, Cline, and Roo Code, plus a standalone VS Code extension.
For Claude Code, registration looks like a single command that supplies your embedding key and vector-store token as environment variables:
claude mcp add claude-context \ -e OPENAI_API_KEY=sk-... \ -e MILVUS_TOKEN=... \ -- npx @zilliz/claude-context-mcp@latest
For a client that reads a JSON config, such as Cursor, the same server goes into the mcpServers block:
{
"mcpServers": {
"claude-context": {
"command": "npx",
"args": ["@zilliz/claude-context-mcp@latest"],
"env": {
"EMBEDDING_PROVIDER": "OpenAI",
"OPENAI_API_KEY": "sk-...",
"MILVUS_TOKEN": "..."
}
}
}
}Once the server is registered, the first index build runs against the repo, and the agent gains a search tool it can call in natural language. The choice of client is less about capability here than about the rest of your workflow; if you are still picking among agents, our comparison of Cursor 3 vs Claude Code vs Codex CLI for parallel agents covers how each handles multi-agent work, and claude-context slots into all three. One operational note: the embedding provider and vector store are your data-egress decision, not just a config value. If source code cannot leave your network, use the Ollama provider and a self-hosted Milvus rather than a managed cloud and a hosted embedding API.
06 · When grep still wins: small repos and exact-match tasks
Grep still wins whenever you need every match, the repo is small, or the task is a one-off where the index never pays back its build cost. Semantic search optimizes for relevance, returning the top-ranked chunks, and relevance is the wrong objective for a class of tasks where completeness is non-negotiable.
The exact-match cases are the clearest. A rename that has to hit every call site, a security sweep for a hardcoded credential, a hunt for a specific error string in the logs, or a regex over a config format: all of these need every occurrence, and a ranked top-k can silently miss the one that mattered. Grep is deterministic and exhaustive; that is precisely the property these tasks require. Reaching for a vector index here trades a guarantee for a probability, which is a bad trade.
Size is the other axis. On a small repository the whole codebase may fit comfortably in a modern context window, in which case there is nothing to save: the agent can hold the relevant files and grep is instant. The setup cost of standing up an embedding provider and a vector database only earns back its investment when whole-file reads would otherwise dominate the token bill, which happens on large repos and long, multi-step agent sessions. For a quick fix in a 3,000-line service, indexing is pure overhead. The right mental model is not "semantic search replaces grep" but "semantic search replaces the read-thirty-files step that grep triggers on a big repo."
07 · The cost model: index storage and re-embedding versus context savings
The cost model is a straight trade: you pay for embeddings, vector storage, and index freshness up front, and you earn back tokens on every agent query that would otherwise have read whole files. Whether it nets out positive is a function of repo size and how often you query.
On the cost side there are three line items. The initial embed is a one-time bulk cost proportional to the codebase, paid to your embedding provider. Vector storage is an ongoing cost in Milvus or Zilliz Cloud, modest for most repos. Re-embedding on change is the recurring cost, and the Merkle-tree diff keeps it proportional to churn rather than repo size. On the savings side there is one dominant line: the whole-file reads you no longer perform, multiplied by how many times the agent searches. This is the same full-bill discipline we apply in code execution with MCP for token reduction: optimize against total cost, not the single metric that produces the best headline.
Here is how the leading options compare on the axes that decide the trade:
The pattern in that table is that the token efficiency and the operational weight move together only for claude-context, which buys managed hybrid retrieval and 13-plus client integrations at the price of running a vector database and paying an embedding provider. semble takes most of the token win with none of the infrastructure by staying CPU-only and self-contained, at the cost of the managed features. Codebase Memory MCP is a different tool for a different question: it is built for "trace this call chain," not "find code like this."
| Tool | Retrieval method | Infrastructure | Reported efficiency | Best for |
|---|---|---|---|---|
| grep / ripgrep | Literal and regex match | None | No index cost; whole-file reads | Small repos, exact-match, one-offs |
| claude-context (zilliztech) | Hybrid BM25 + dense vectors | Milvus / Zilliz Cloud + embedding API | ~40% tokens at equal quality (self-reported) | Managed hybrid retrieval, broad client support |
| semble (MinishLab) | tree-sitter + BM25 + static embeddings (RRF) | CPU-only, no API keys | ~98% fewer tokens than grep+read | Zero-infra, fast local indexing |
| Codebase Memory MCP | AST knowledge graph (functions, calls) | Single static binary | 10x fewer tokens, 83% answer quality (31 repos) | Structural and call-graph questions |
08 · The bottom line: when to index, and what to skip
If your agents work in a large, actively developed repository and run long multi-step sessions, index it, and reach for claude-context first because it has the broadest client support and the most defensible efficiency claim. If you want the token savings without running a vector database, use semble; its CPU-only, no-API-key design removes the entire infrastructure objection. According to MinishLab (2026), semble indexes an average repo in about 250 milliseconds and answers a query in roughly 1.5 milliseconds, which is fast enough to rebuild the index casually rather than maintaining it. Reach for Codebase Memory MCP specifically when your agents keep asking structural questions, "what calls this," "trace this path," that a similarity search answers poorly.
Skip indexing entirely for small repos, exact-match and rename tasks, security sweeps that need every occurrence, and any one-off where you would spend more time standing up the index than the search will ever save. Keep grep in the toolbox even after you index, because the two are complementary: semantic search for "where is the code that does this," grep for "where does this exact text appear." The mistake we see most often is treating this as a religious choice rather than a routing decision. The right architecture usually exposes both to the agent and lets the task pick.
This is exactly the retrieval-layer decision we pressure-test in Particula Tech's agent architecture audits: not "should we use semantic code search" in the abstract, but whether your specific repos and session patterns make an index earn its storage and re-embedding cost before you commit to a vector database. For a deeper map of where code search sits among the other tooling calls, the AI development tools pillar covers the adjacent decisions. Start by measuring one thing this week: what fraction of your agent's token bill on your largest repo goes to whole-file reads after a grep. If it is small, stay on grep. If it dominates, you already know what to index.
09 · FAQ
Quick answers to the questions this post tends to raise.




