Skip to main content
Glama
README.md
# RAG Document Search — MCP Server

![CI](https://github.com/weitingyen168/rag-mcp-server/actions/workflows/ci.yml/badge.svg)

A retrieval-augmented-generation backend that lets AI assistants search a
document set and answer questions grounded in real sources. It's exposed as a
**Model Context Protocol (MCP)** server, so any MCP-compatible client can call
its `search` tool.

Two interchangeable backends:
- **SQLite FTS5** keyword search — the default, **zero heavy dependencies**.
- **Chroma** vector database — semantic search (`RAG_BACKEND=chroma`).

> Clean-room implementation written from scratch to demonstrate RAG + MCP
> engineering. **Ships with no documents or data** — you add your own.

## How it works
```
documents/ ──▶ chunker ──▶ index (FTS5 or Chroma)
                                  │
      MCP client ──(search)──▶ server.py ──▶ ranked passages
                                  ▲
        ingest.py --incremental ──┘  only re-indexes changed files
```

## Quick start
```bash
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -r requirements.txt

# 1) add your own .md/.txt files to ./documents  (none are included)
# 2) build the index
python ingest.py --rebuild
# 3) run the MCP server (stdio transport)
python server.py
```

Semantic mode instead of keyword:
```bash
pip install chromadb
RAG_BACKEND=chroma python ingest.py --rebuild
RAG_BACKEND=chroma python server.py
```

## Register with an MCP client
```json
{
  "mcpServers": {
    "rag-search": {
      "command": "/absolute/path/.venv/bin/python",
      "args": ["/absolute/path/server.py"]
    }
  }
}
```

## Configuration
All tunables are in `config.py`: `DOCS_DIR`, `BACKEND`, `CHUNK_SIZE`,
`CHUNK_OVERLAP`, `DEFAULT_TOP_K`. The document directory can also be set with the
`RAG_DOCS_DIR` environment variable.

## Design notes
- **Incremental ingestion:** a manifest of file hashes means only new/edited
  files are re-processed — cheap to keep the index current (e.g. from CI or a timer).
- **Pluggable backends** behind one `get_store()` factory: swap keyword ↔ vector
  search without touching the server or ingester.
- **Word-aligned overlapping chunks** so passages stay readable and answers
  aren't split across a boundary.

## Tests
```bash
python tests/test_chunker.py
python tests/test_store.py
# or: pytest -q
```
Tests use synthetic, generated text only — no datasets are bundled.

## License
MIT © 2026 Wei-Ting Yen