Install
$ agentstack add mcp-adamthuvesen-trace ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Trace
Local retrieval over a folder of files, for an agent or for you. Trace indexes documents on disk and serves search, document fetch, and diagnostics over a CLI or an MCP server. That lets an agent pull the right passages from a knowledge base without you pasting the whole thing into context.
The default search is adaptive and BM25-first. Trace trusts strong lexical matches, but skips them when the keyword evidence is weak and falls back to semantic or hybrid search. Retrieval runs entirely locally. Embeddings run on-device (ONNX int8 by default); nothing leaves the machine.
The CLI and MCP server wrap the same Python primitives (WikiIndexer, AdaptiveSearch, CollectionRegistry, and result formatters), so you can use the pieces directly from a script or library.
Formats: Markdown, PDF, Word, PowerPoint, CSV, SQL, Python, YAML, TypeScript, Jupyter notebooks.
Install
Trace needs Python 3.11+ and uv.
uv sync
Demo With A Committed Fixture
This command searches the committed fixture in tests/fixtures/eval_kb.
$ KB_PATH=tests/fixtures/eval_kb TOKENIZERS_PARALLELISM=false uv run trace search "BM25 ranking" --top-k 2
Found 2 results
## Strategy
- **Selected:** keyword
- **Fallback used:** no
- **Reason:** BM25 returned strong exact-match results
## Context
### 1. BM25
- **Path:** `glossary/bm25.md`
- **Folder:** glossary
- **Source:** keyword
**Snippet 1:** BM25
- **Match evidence:** title matches: bm25; path matches: bm25; breadcrumb matches: bm25
- **Matched terms:** `bm25`, `ranking`
- **Best quote:** Document: BM25 Folder: glossary # BM25 BM25 is a classic **keyword** ranking function for lexical retrieval...
## Suggested Follow-ups
- `get_document(path="glossary/bm25.md")`
CLI
Use uv run trace ... from the repo, or trace ... once installed.
# Single collection
KB_PATH=/path/to/docs uv run trace search "sample query"
# Named collections
KB_COLLECTIONS="docs:/path/to/docs,team:/path/to/second-kb" \
uv run trace search "sample query" --collection docs
# Check setup
KB_PATH=/path/to/docs uv run trace doctor
# Start the MCP server
KB_PATH=/path/to/docs uv run trace serve
With no subcommand, uv run trace starts the MCP server.
| Command | Description | | --- | --- | | trace search "query" | BM25-first search with semantic/hybrid fallback | | trace semantic-search "query" | Vector similarity search | | trace keyword-search "term" | Direct BM25 keyword search for exact terms | | trace hybrid-search "query" | Semantic + keyword combined | | trace get-document path/to/doc.md | Fetch a document by path | | trace list-documents | List documents, optionally by folder | | trace index-stats | Show index status | | trace doctor "sample query" | Diagnose config, visible docs, exclusions, indexes | | trace reindex | Update indexes incrementally; --force to rebuild | | trace serve | Start the MCP server |
Search commands take --top-k (keyword-search uses --max-results); list-documents takes --folder and --limit. Search commands and list-documents also take --path-prefix (repeatable), --extensions (.md,.py), and --since (ISO 8601) to scope results. Collection-aware commands take --collection.
MCP server
Trace speaks MCP over stdio. Point it at one collection with KB_PATH or several named ones with KB_COLLECTIONS. The server name is trace; tools are exposed as mcp__trace__.
Claude Code
claude mcp add trace \
--transport stdio \
--env KB_COLLECTIONS="docs:/path/to/docs,team:/path/to/second-kb" \
-- uv run --directory /path/to/trace trace serve
# Inspector
KB_COLLECTIONS="docs:/path/to/docs,team:/path/to/second-kb" \
uv run fastmcp dev src/trace_search/server/trace_server.py
The tools map one-to-one onto the CLI:
| Tool | Description | | --- | --- | | search | BM25-first search with semantic/hybrid fallback (default) | | semantic_search | Vector similarity search | | keyword_search | Direct BM25 keyword search for exact terms | | search_hybrid | Semantic + keyword combined | | get_document | Fetch a document by path | | list_documents | List documents, optionally by folder | | index_stats | Show index status | | doctor | Diagnose config, visible docs, exclusions, indexes | | reindex | Update indexes incrementally; force=true to rebuild |
In multi-collection mode, search and document tools take an optional collection. Search tools and list_documents take the same path_prefix / extensions / since filters as the CLI; filters combine with AND and show up in search output under Active filters, so an empty result explains itself.
Start with search. It reports which strategy won, groups context by document, includes match evidence, and suggests get_document(path=...) follow-ups. Reach for keyword_search / semantic_search / search_hybrid when you want one mode for debugging or deterministic comparison.
Configuration
| Variable | Description | Default | | --- | --- | --- | | KB_PATH | Path to a single collection (~ expanded) | unset | | KB_COLLECTIONS | Comma-separated name:path pairs (~ expanded) | unset | | INDEX_PATH | Root path for indexes (~ expanded) | unset | | LOG_LEVEL | DEBUG/INFO/WARNING/ERROR/CRITICAL/NOTSET | INFO | | EMBEDDING_MODEL | all-MiniLM-L6-v2 or BAAI/bge-base-en-v1.5 | all-MiniLM-L6-v2 | | EMBEDDING_BACKEND | onnx (int8, faster) or torch | onnx | | RERANKER_ENABLED | Enable reranking | false |
KB_PATH and KB_COLLECTIONS are mutually exclusive. Setting both fails at startup, as do invalid paths, collection names, and log levels.
Indexes live under each collection in .mcp-search/indexes/. Set INDEX_PATH to store them elsewhere: single-collection mode writes there directly, multi-collection mode uses one subdirectory per collection.
Reindexing
reindex is incremental: Trace fingerprints each file (SHA-256 + mtime + size) and reprocesses only what was added, changed, or removed. Run trace reindex --force (force=true over MCP) to drop both indexes and rebuild from scratch after a model change or to recover from corruption.
doctor reports the next-reindex plan and a change summary:
- Index status: stale
- 1 added, 2 changed, 1 removed since last index.
- Next `reindex` will run incrementally on changed files.
- Source changes since last index: unchanged=27, added=1, changed=2, removed=1
When given a sample query, doctor probes existing indexes only. It tells you to reindex rather than building as a side effect. If it reports unknown metadata (an older v1 schema), one reindex repopulates model and freshness metadata; that run is forced, later runs are incremental.
Retrieval quality
Trace includes a small eval harness (tools/eval/) for golden-query checks. The committed fixture is a deliberately tricky smoke test: 24 short Markdown docs and 17 queries with near-duplicate concepts, exact-token lookups, and paraphrases.
| Mode | Top-1 (P@1) | Top-5 (Success@5) | MRR | p50 | p95 | | --- | --- | --- | --- | --- | --- | | bm25 | 88% | 94% | 0.912 | 0.16 ms | 2.6 ms | | semantic | 88% | 100% | 0.941 | 6.71 ms | 7.1 ms | | hybrid | 88% | 100% | 0.941 | 7.10 ms | 10.9 ms | | adaptive | 88% | 100% | 0.941 | 7.20 ms | 10.6 ms |
The shared 88% Top-1 hides the real tradeoff. BM25 is fastest and strong on exact terms, but misses one paraphrase entirely. Semantic and hybrid recover all queries in the top 5. adaptive keeps BM25 for strong lexical hits and falls back to vector search when keyword evidence is weak, matching the best recall while keeping lexical queries cheap.
These are smoke-test numbers, not corpus-scale benchmark claims. Full reports live in [docs/benchmarks/](docs/benchmarks/). Reproduce the committed gate with:
KB_PATH=tests/fixtures/eval_kb EVAL_GOLDEN_QUERIES=tests/fixtures/eval_golden_queries.yaml \
uv run python -m tools.eval.cli --full --search adaptive --output-dir docs/benchmarks/
For the multi-KB retrieval battle suite, see [docs/retrieval-modes.md](docs/retrieval-modes.md). It compares BM25, semantic, hybrid, reranked, and adaptive retrieval across committed no-secret fixtures and documents when each mode wins.
Development
uv run python -m pytest -m "not slow" # skip embedding tests
uv run python scripts/check_module_sizes.py # no module > 1000 lines
uv run ruff check .
uv build
# Search evaluation against the committed fixture
KB_PATH=tests/fixtures/eval_kb EVAL_GOLDEN_QUERIES=tests/fixtures/eval_golden_queries.yaml \
uv run python -m tools.eval.cli --full --search adaptive
To evaluate against your own corpus, copy tools/eval/golden_queries.example.yaml to tools/eval/golden_queries.yaml, point KB_PATH at the matching docs, build the index, then run uv run python -m tools.eval.cli --quick.
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: adamthuvesen
- Source: adamthuvesen/trace
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.