RAG Notes Search MCP Server
by rohith0224
README.md
# RAG Notes Search — MCP Server
A semantic search system over personal study notes, exposed as an
MCP (Model Context Protocol) tool that Claude Desktop can call mid-conversation.
## What it does
Ask Claude Desktop anything about your notes and it automatically:
1. Decides whether to search your notes based on the question
2. Calls the `search_notes` tool with a semantic query
3. Retrieves the most relevant note content with similarity scores
4. Synthesizes an answer grounded in your actual notes
Example queries that work:
- "What have I written about machine learning pipelines?"
- "Search my notes for how vector databases work"
- "What do my notes say about GCP Cloud Run?"
## Architecture
Claude Desktop (MCP Client)
↓ stdio
MCP Server (mcp_server.py)
↓
search_notes() tool
↓
Chroma Vector DB (local)
↓
fastembed (all-MiniLM-L6-v2, ONNX)
## Tech stack
- **MCP** — Anthropic's Model Context Protocol (v1.28.1) for tool exposure
- **Chroma** — local vector database storing note embeddings
- **fastembed** — lightweight ONNX-based embedding model (no PyTorch dependency)
- **sentence-transformers/all-MiniLM-L6-v2** — embedding model, 384 dimensions
- **Docker** — containerized for reproducibility, built for linux/amd64
- **GCP** — Container Registry hosts the image, Cloud Run deployment planned
## Key technical decisions
**Why fastembed over sentence-transformers?**
sentence-transformers pulls in PyTorch (~2GB). fastembed uses ONNX runtime
(~200MB), making Docker builds 10x faster and the image significantly smaller.
**Why a similarity threshold?**
Without a threshold, vector search always returns something even when nothing
is relevant — this is how RAG systems silently hallucinate. A threshold of 0.25
means the system returns "no relevant notes found" rather than a low-confidence
garbage result.
**Why absolute paths in the MCP server?**
Claude Desktop spawns the MCP server as a subprocess with an unpredictable
working directory. Relative paths like `./chroma_db` break silently. Absolute
paths are required for reliable subprocess execution.
**Why stderr for all logging?**
MCP uses stdout as a JSON wire protocol. Any print() to stdout corrupts the
MCP message stream. All logging goes to stderr which Claude Desktop reads
separately via the log file.
## Setup
### Prerequisites
- Python 3.11
- Claude Desktop
- conda or venv
### Install
```bash
conda create -n rag_demo python=3.11
conda activate rag_demo
pip install chromadb==1.5.9 sentence-transformers mcp fastembed numpy==1.26.4
```
### Index your notes
Add `.txt` files to the `notes/` folder, then run the indexing notebook:
```bash
jupyter notebook demo.ipynb
```
Run all cells — this embeds your notes into Chroma.
### Connect to Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"notes-search": {
"command": "/opt/anaconda3/envs/rag_demo/bin/python",
"args": ["/absolute/path/to/rag_demo/mcp_server.py"],
"cwd": "/absolute/path/to/rag_demo"
}
}
}
```
Restart Claude Desktop. Look for the tools icon in the chat input.
### Docker
```bash
# Build for linux/amd64
docker buildx build --platform linux/amd64 -t rag-demo .
# Run with local chroma_db mounted
docker run --rm \
-v /absolute/path/to/chroma_db:/app/chroma_db \
rag-demo
```
## Bugs fixed during development
| Bug | Cause | Fix |
|-----|-------|-----|
| `Read-only file system` | Relative `./chroma_db` path breaks in subprocess | Use absolute path |
| `Unexpected token 'L' is not valid JSON` | `print()` polluting MCP stdout wire | Route all logs to `stderr` |
| `cached_download` ImportError | sentence-transformers version conflict | Switched to fastembed |
| `np.float_` AttributeError | NumPy 2.0 removed deprecated types | Pinned `numpy==1.26.4` |
| `no such column: collections.topic` | Chroma version mismatch between dev and Docker | Matched versions exactly |
## Planned improvements
- SSE/HTTP transport for Cloud Run deployment
- Second MCP tool: `search_web()` using a free news API
- Daily ingestion job via Cloud Scheduler
- Confidence score displayed in Claude's responseThis server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues