hybrid-recall
# hybrid-recall
[](LICENSE)
A local, self-hosted retrieval stack exposed over the Model Context Protocol
(MCP). It gives an LLM four tools:
- **`sqlite`** - hybrid search over a document corpus you ingest (FTS5 keyword +
semantic embeddings, fused with Reciprocal Rank Fusion).
- **`retrieve`** - one unified search across the knowledge graph, memory, and
docs, with KG-powered query expansion and RRF fusion.
- **`memory`** - a semantic key/value store for cross-session notes
(store / append / replace-section / search / get / list).
- **`kg`** - an entity-relationship knowledge graph with hybrid search.
Everything runs on your machine. The only external dependency is an
OpenAI-compatible embedding server (a small `llama-server` process), and an
optional reranker. Nothing is sent to a third party.
## How it fits together
```
MCP client (Claude Desktop, etc.)
| stdio (JSON-RPC)
v
server.py -> sqlite / retrieve / memory / kg tools
| | |
| | +--> memory daemon (TCP :8767)
| +--> knowledge_graph.jsonl
+--> docs.db (FTS5 + 2560-d embeddings) + embed_cache (mmap)
|
v
embedding server (llama-server :8000, Qwen3-Embedding-4B)
```
The docs corpus, memory, and knowledge graph all embed through the same model,
so a single `llama-server` covers the whole stack.
## Requirements
- Python 3.10+
- [llama.cpp](https://github.com/ggml-org/llama.cpp) (`llama-server` on your PATH)
- A GPU is recommended for the embedding model (it runs on CPU too, slower)
## Quickstart
```bash
# 1. Install Python deps
pip install -r requirements.txt
# 2. Download the embedding model into ./models (see models/README.md)
huggingface-cli download Qwen/Qwen3-Embedding-4B-GGUF \
Qwen3-Embedding-4B-Q8_0.gguf --local-dir ./models
# 3. Start the embedding server (leave running in its own terminal)
scripts/start_embeddings.sh # Windows: scripts\start_embeddings.bat
# 4. Start the memory daemon (needed for the memory + retrieve tools)
scripts/start_memory.sh # Windows: scripts\start_memory.bat
# 5. Create the empty docs database
python init_databases.py
# 6. Ingest your documents (markdown, html, json, text, code)
python scripts/ingest_docs.py --source ./corpus # ./corpus has sample docs
# 7. Embed the chunks (talks to the embedding server from step 3)
python scripts/embed_docs.py
# 8. (optional) Prebuild the mmap vector cache for instant search
python scripts/rebuild_mmap_cache.py
```
Then point your MCP client at `server.py` (see `example_config.json`):
```json
{
"mcpServers": {
"hybrid-recall": {
"command": "python",
"args": ["/absolute/path/to/hybrid-recall/server.py"]
}
}
}
```
## Configuration
All settings have sane localhost defaults; override them with environment
variables or a `.env` file (see `.env.example`). The important ones:
| Variable | Default | Purpose |
|----------|---------|---------|
| `EMBED_SERVER_URL` | `http://127.0.0.1:8000/v1/embeddings` | embedding endpoint |
| `RERANKER_URL` | `http://127.0.0.1:8001/v1/rerank` | reranker (optional) |
| `MEMORY_SERVICE_PORT` | `8767` | memory daemon port |
| `KNOWLEDGE_GRAPH_PATH` | `./data/knowledge_graph.jsonl` | KG storage |
| `DOCS_DB_PATH` | `./data/docs.db` | docs corpus DB |
To run the models on a different machine, point `EMBED_SERVER_URL` /
`RERANKER_URL` at that host. The tools do not care where the servers live.
## Reranking
Reranking is optional and off by default. Every search works without it and
falls back to bi-encoder order if the reranker is not running. To enable it,
start the reranker (`scripts/start_reranker`) and pass `rerank=true` on a call.
## Notes
- The docs corpus, memory store, and knowledge graph are all built from your own
data. A fresh clone starts empty.
- Index-time and query-time embeddings must come from the same model. If you
switch embedding models, re-embed the corpus.
- The memory tool is a small TCP daemon (`scripts/start_memory`); the docs and
KG tools run in-process inside the MCP server.
## Benchmarks
The design choices here (Qwen3-4B bi-encoder, cross-encoder reranking off by
default, RRF fusion, BGE-reranker-v2-m3) are backed by real measurements: recall
suites, a 10-strategy fusion A/B, reranker and embedding model bake-offs, and
latency profiles. See [`benchmark.md`](benchmark.md). Short version: real
embeddings + reranking moved retrieval MRR from 0.36 to 0.77 on a 32-query suite,
and plain reranking beat every fancy fusion scheme tried against it.
## License
MIT. See `LICENSE`.
TDQS
Scored across 4 tools
Each tool has a distinct primary domain (sqlite for SQLite and doc search, retrieve for unified cross-source retrieval, memory for persistent key-value store, kg for graph), but retrieval functions overlap—sqlite's docs_search and retrieve both cover docs, and memory/kg each have search. Descriptions help, but an agent might still be uncertain which search to use.
Tool names are all lowercase but mix verb (retrieve) and nouns (sqlite, memory, kg); no consistent verb_noun pattern. Within sqlite, multi-word subcommands use underscores, but tool-level naming is inconsistent.
Four tools is well-scoped for a hybrid recall server covering docs, unified retrieval, memory, and knowledge graph; each earns its place without feeling bloated or sparse.
Covers the main retrieval surfaces (docs, memory, KG, unified) with CRUD on memory and KG and doc search operations; minor gaps like missing bulk document management are present, but core workflows are covered.