Local code search MCP for Claude Code that uses fewer tokens than grep
TL;DR — Yes: xerj is a local code search MCP for Claude Code that uses fewer tokens than grep. It indexes the repository once, then xerj search and xerj def return ranked passages with path:line. On psf/requests, measured 2026-10-19, one answer was 1,303 bytes against 25,150 bytes of rg output.
Read https://xerj.org/llms.txt. Install xerj, start a node with xerj --insecure --data-dir ~/xerj-data, run xerj autoindex on this repository, run xerj init so the xerj MCP server is registered, then answer my next code question with one xerj search or xerj def call and cite path:line instead of opening whole files.
curl -fsSL https://xerj.org/get | sh
Install the release binary into ~/.local/bin (the installer checks its SHA-256).
xerj --insecure --data-dir ./xerj-data
Start a single-user node on localhost:9200 in its own terminal.
xerj autoindex ./requests --prefix req
Index the repository once; code files get defs and symbols with line numbers.
xerj search --prefix req -k 3 --full 400 "rebuild auth on redirect strip authorization"
Three ranked passages with path:line, each body capped at 400 characters.
xerj def --prefix req should_strip_auth
Exact definition lookup: the declaration line and the file's symbol list.
xerj init
Register xerj mcp in .mcp.json for Claude Code (and Cursor or Codex when present).
Run it
The installer puts one binary in ~/.local/bin. Start a node in its own terminal, index the repository once, and then ask. These are the exact commands and output from a scratch HOME with v1.0.0-rc.97 and psf/requests at commit 611c6162.
curl -fsSL https://xerj.org/get | sh
xerj --insecure --data-dir ./xerj-data &
git clone --depth 1 https://github.com/psf/requests
xerj autoindex ./requests --prefix req
done in 2.9s — 1 dataset, 1571 records live, 0 duplicate aliases, 0 junk records, 1 junk/skipped file (543.9 docs/sec)
xerj-done ok=true exit=3 reason=completed-with-junk wall=3.0s files=95 records=1571 datasets=1 junk_files=1 code_files=36 code_files_indexed=36 code_files_junked=0
Exit 3 means the run completed and skipped one file it could not use; all 36 code files were indexed.
Ask with the words the code uses. The answer names the function, the file and the line.
xerj search --prefix req -k 3 --full 400 "rebuild auth on redirect strip authorization"
xerj search: these hits are lexical; this command does not consult the embedding.
─── src/requests/sessions.py:309 (score 22.97)
def rebuild_auth(
self, prepared_request: PreparedRequest, response: Response
) -> None:
"""When being redirected we may want to strip authentication from the
request to avoid leaking credentials. This method intelligently removes
and reapplies authentication where possible to avoid credential loss.
"""
original_request = response.request
… (--full 800 to see more)
─── docs/conf.py:62 [const] (score 22.11)
author = u"Kenneth Reitz"
─── tests/test_requests.py:662 (score 21.64)
[17 lines of the test body cut here for the page]
3 passage(s) from 'req-*'. Cite ax_path:line for anything you rely on.
When you know the symbol, xerj def is shorter still.
xerj def --prefix req should_strip_auth
─── src/requests/sessions.py:154 [function]
def should_strip_auth(self, old_url: str, new_url: str) -> bool:
Give it to Claude Code over MCP
Run xerj init in the project. It writes .mcp.json for Claude Code and keeps the MCP entries already there. Cursor and Codex get the same entry when their config folders exist. Keep the node running, because xerj mcp does not start one.
{"mcpServers": {"xerj": {"command": "xerj", "args": ["mcp", "--url", "http://localhost:9200"]}}}
Measured on 2026-10-19
One question, three ways to answer it, on the same checkout (95 files indexed, 36 of them code). Bytes are what lands in the agent's context.
| Method | Output | Bytes | Wall time, 5 runs |
|---|---|---|---|
rg -n -i redirect | 282 lines from 17 files | 25,150 | 5 to 7 ms |
| Open the 17 matching files | whole files | 447,383 | n/a |
xerj search -k 3 --full 400 | 3 passages, sessions.py:309 first | 1,303 | 8 to 23 ms |
xerj def should_strip_auth | declaration plus symbol list | 949 | not timed |
The ratio is 19 times fewer bytes for the search, measured once on one repository. ripgrep is faster per call. A byte is not a token, so treat this as a size comparison, not a token count. The published agent benchmark is the token number: 9,982 output tokens for xerj against 26,477 for the baseline agent, 2.7 times fewer, over 8 tasks.
How it compares
| Tool | Runs locally | Ranked results | file:line | MCP server | Setup |
|---|---|---|---|---|---|
| xerj | yes | yes, BM25 | yes | yes, 17 tools | install, start node, index once |
| ripgrep | yes | no, every match | yes | no | none |
| Zoekt | yes | yes | yes | no | index server |
| GitHub code search | no | yes | yes | no | repo on GitHub, API limits |
| Vector database plus embedder | depends | yes, semantic | only if you store it | depends | embedder, chunker, store |
When not to use xerj
- You need regular expressions over source. xerj has no regex search; use ripgrep.
- The repository is small enough to read whole, or you only search it once. The index costs a node and a step.
- You need natural-language matching with no shared words. The default ranking is lexical. The default embedder is lexical feature hashing;
--embed-mode neuraldownloads all-MiniLM-L6-v2, about 90 MB, and is opt-in. - The machine must stay idle. The published 15-repository run measured 8% CPU and 8.3 GB for an idle xerj node against 0.03% and 119 MB for Zoekt.
FAQ
Is there a local code search MCP for Claude Code that uses fewer tokens than grep?
Yes. xerj runs on your machine, indexes the repository once and serves the index through xerj mcp. On psf/requests a ranked answer was 1,303 bytes where rg -n -i redirect printed 25,150 bytes.
MCP server grep alternative with fewer tokens: which tools does xerj expose?
The rc.97 server lists 17 tools in tools/list, including xerj_search, xerj_code_search, xerj_map and the three hub tools. Run xerj init in the project to register it.
Is xerj faster than ripgrep?
Not per call. Two sessions of five runs on psf/requests took 8 to 23 ms for xerj search and 5 to 7 ms for rg. The saving is in what the agent reads afterwards, not in wall time.
Does it understand code or only words?
Code files are parsed with tree-sitter, so xerj def finds a declaration by name. Ranking is lexical BM25 by default; xerj search says so on its first line.
What happens when my wording does not match the code?
Lexical ranking can miss. Our first phrasing, about stripping the Authorization header when a redirect changes host, ranked tests and rebuild_method above rebuild_auth. Rephrasing with the words in the code fixed it.
How much does this save in a full agent session?
The published coding-agent benchmark measured 2.7 times fewer output tokens than the baseline agent over 8 tasks and 16 runs per arm. Your repository and agent will give a different number.
Evidence
- psf/requests autoindex: done in 2.9s, 95 files, 36 code files —
benchmarks/agent-intents-2026-10-19/01-autoindex-requests.txt - xerj search answer: 1,303 bytes, sessions.py:309 first —
benchmarks/agent-intents-2026-10-19/01-xerj-search.txt - xerj def answer: 949 bytes, sessions.py:154 —
benchmarks/agent-intents-2026-10-19/01-xerj-def.txt - rg -n -i redirect: 282 lines, 25,150 bytes —
benchmarks/agent-intents-2026-10-19/01-rg-redirect.txt - Wall times 8 to 23 ms for xerj search, 5 to 7 ms for rg —
benchmarks/agent-intents-2026-10-19/README.md - MCP tools/list returns 17 tools —
benchmarks/agent-intents-2026-10-19/00-mcp-tools-list.json - 2.7 times fewer output tokens, 9,982 vs 26,477; idle 8% CPU and 8.3 GB vs Zoekt 0.03% and 119 MB —
landing/benchmarks/index.html - --embed-mode neural downloads all-MiniLM-L6-v2, about 90 MB; lexical by default — https://github.com/xerj-org/xerj/blob/main/README.md
Related
- I need my agent to find a passage and cite the file, not dump the whole tree. How?
- Retrieval that says not found, and cites file and line when it does answer
- Ask questions about a GitHub repo without cloning it
- Is ripgrep enough for a coding agent, or do I need a code index?
- Should my agent call a search API or stand up Qdrant for persistent memory?
- Benchmarks