Skip to main content
Glama
README.md
# mcp-rag: Semantic RAG served over the Model Context Protocol

A **semantic Retrieval-Augmented Generation** engine, exposed as an **MCP
server** so any MCP client (Claude Desktop, an IDE agent, …) can search and
question a knowledge base as a native tool.

```
 documents ─▶ chunk ─▶ embed ─▶ index ─┐
                                        ├─▶ hybrid retrieval ─▶ grounded answer
 query ─────────────────────────────────┘   (semantic + BM25,     with citations
                                              fused by RRF)              │
                                                                         ▼
                                                    MCP server ─▶ any MCP client
```

The whole thing **runs offline out of the box**, local LSA embeddings + an
extractive, citation-grounded answerer, with **zero API keys or model
downloads**. Production backends (Voyage / OpenAI / sentence-transformers for
embeddings, Anthropic / OpenAI for generation) are a one-line config switch.

**Demo corpus:** a self-contained fictional SaaS knowledge base ("Nimbus", a
cloud data platform): authentication, billing, rate limits, data retention,
security, incident runbook, webhooks, SDK. Nothing copyrighted; every answer is
traceable to a source.

---

## What it does

Ask a question phrased in your own words and get an answer grounded in the docs:

```
$ python scripts/demo_query.py "what happens if I go over my included usage?"

A: When you exceed your included quota, Nimbus does not cut off your service;
   instead, additional usage is billed as overage at the metered rate
   ($0.50 per extra 10k calls, $0.10 per extra GB). [1]
Sources:
   [1] billing.md, Billing and quotas
```

Note there's **no keyword overlap** between "go over my included usage" and
"exceed your quota / overage", that match is *semantic*, which is the point.

---

## MCP tools exposed

| Tool | Purpose |
|------|---------|
| `search_documents(query, top_k, method)` | Return the most relevant passages (`semantic` / `lexical` / `hybrid`). |
| `answer_question(question, top_k)` | A grounded answer with citations. |
| `list_sources()` | Documents currently indexed. |
| `get_stats()` | Index size + active backends. |

Verified end-to-end over the real MCP stdio protocol (see `tests/`). Register it
in a client with [`mcp.json`](mcp.json).

---

## Retrieval ablation (computed by `make eval`)

17 gold questions, deliberately paraphrased away from the documents' wording.
`hit@k` = correct document in the top-k; `MRR` = how highly it's ranked.

| Method | hit@4 | MRR |
|--------|:-----:|:---:|
| Lexical (BM25) | 0.941 | 0.873 |
| Semantic (LSA) | 0.941 | 0.912 |
| **Hybrid (RRF fusion)** | 0.941 | **0.941** |

All three usually *find* the right document on this clean corpus, but **hybrid
ranks it highest most consistently**, fusing dense (semantic) and sparse
(keyword) retrieval is a tuning-free win, and the paraphrased questions are
exactly where pure keyword search ranks worse.

> With a neural embedding backend (Voyage/OpenAI/ST) on a larger, noisier corpus
> the gap between lexical and semantic widens further; the local LSA backend
> keeps the demo runnable anywhere while preserving the same ranking behaviour.

---

## Quickstart

```bash
pip install -r requirements.txt && pip install -e .

make demo     # ask a question from the CLI
make eval     # retrieval ablation → reports/eval_results.json
make server   # run the MCP server (stdio)
make test     # 10 tests, incl. an end-to-end MCP protocol check
```

### Use it from Claude Desktop
Copy `mcp.json` into your client config (set the absolute `cwd`), restart the
client, and the four tools appear. Ask *"search the Nimbus docs for how failover
works"* and the model calls `search_documents` / `answer_question`.

### Switch to production backends
```bash
pip install -r requirements-prod.txt
export MCPRAG_EMBEDDING_BACKEND=voyage   VOYAGE_API_KEY=...
export MCPRAG_GENERATOR_BACKEND=anthropic ANTHROPIC_API_KEY=...
```
No code changes, the retriever and server are backend-agnostic.

---

## Layout

```
src/mcprag/
  ingest.py            markdown loading + section-aware chunking w/ overlap
  embeddings/          Embedder protocol · local LSA (offline) · neural backends
  index/vector_store.py  cosine + BM25 + hybrid RRF retrieval
  generator/           extractive (offline, cited) · LLM backends
  rag.py               RAGEngine (ingest→embed→index→retrieve→generate)
  evaluation.py        hit@k / MRR
  server.py            FastMCP server exposing the tools
data/corpus/           the Nimbus knowledge base (8 markdown docs)
eval/qa_gold.json      paraphrased gold questions
scripts/               demo_query · run_eval
tests/                 retrieval, answers, evaluation, MCP protocol
```

## Design notes
- **Grounded by construction.** The offline generator only emits sentences taken
  verbatim from retrieved chunks, each with a citation, it cannot hallucinate.
- **Hybrid retrieval.** Reciprocal Rank Fusion of dense + sparse rankings needs
  no weight tuning and is robust across query types.
- **Backend-agnostic.** Embeddings and generation are pluggable Protocols;
  offline and production share identical retrieval/serving code.

See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md),
[`docs/RESULTS.md`](docs/RESULTS.md), and
[`docs/IMPROVEMENTS.md`](docs/IMPROVEMENTS.md).

## Tech stack
Python · MCP SDK (FastMCP) · scikit-learn (TF-IDF + LSA) · rank_bm25 · numpy ·
pydantic. Optional: Voyage / OpenAI / sentence-transformers / Anthropic.

## License
MIT. The demo corpus is fictional.

TDQS

A4/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: answer_question for generating answers, search_documents for retrieving passages, list_sources for enumerating documents, and get_stats for server metadata. No functional overlap.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (answer_question, get_stats, list_sources, search_documents), making the API predictable.

Tool Count5/5

With 4 tools, the server is well-scoped for its RAG purpose. Each tool covers a core operation (search, answer, list sources, stats) without unnecessary bloat.

Completeness5/5

The tool surface covers all essential tasks for a knowledge base query system: searching, answering with citations, listing available documents, and retrieving system stats. No obvious gaps for the stated purpose.

Maintenance

ActivityStale
ResponsivenessNo issues