Skip to main content
Glama
README.md
# hybrid-recall

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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

A4.1/5.0

Scored across 4 tools

Disambiguation4/5

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.

Naming Consistency2/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivitySlowing
ResponsivenessNo issues