Skip to main content
Glama
Divyanshedunext

Document Q&A MCP Server

README.md
# Document Q&A MCP Server

A medium-complexity MCP server that lets an MCP client (like Claude Desktop)
ingest documents (PDF / DOCX / TXT / MD) and answer questions about them using
retrieval-augmented generation (RAG).

**How it works:**
1. `add_document` extracts text, splits it into overlapping chunks, embeds
   each chunk locally with `sentence-transformers`, and stores it in a
   ChromaDB collection persisted to disk.
2. `ask_question` embeds your question, retrieves the most similar chunks
   from Chroma, and sends them + your question to a Groq-hosted LLM, which
   answers grounded only in that context.

## 1. Install

```bash
cd mcp-doc-qa
python -m venv venv
source venv/bin/activate      # Windows: venv\Scripts\activate
pip install -r requirements.txt
```

The first run will download the small local embedding model
(`all-MiniLM-L6-v2`, ~80MB) from HuggingFace — needs internet once, then it's
cached locally.

## 2. Configure

```bash
cp .env.example .env
```

Edit `.env` and set `GROQ_API_KEY` (free key at
https://console.groq.com/keys). Defaults for everything else are sensible.

## 3. Test it standalone (optional but recommended)

```bash
python server.py
```

This starts the server on stdio and will just sit there waiting for an MCP
client — that's expected, it's not a web server. Press Ctrl+C to stop.
If you'd rather sanity-check the pieces without an MCP client, open a Python
shell and call `store.add_document(...)` / `generate_answer(...)` directly.

## 4a. Run it as a REST API (FastAPI)

Instead of (or alongside) the MCP server, you can run the same logic as a
regular web backend:

```bash
uvicorn api:app --reload --port 8000
```

Then open **http://127.0.0.1:8000/docs** for interactive Swagger UI, or hit
it directly:

```bash
# Upload a document
curl -X POST http://127.0.0.1:8000/documents/upload \
  -F "file=@/path/to/report.pdf"

# Ask a question
curl -X POST http://127.0.0.1:8000/ask \
  -H "Content-Type: application/json" \
  -d '{"question": "What was the Q3 revenue?"}'

# List documents
curl http://127.0.0.1:8000/documents

# Delete one document
curl -X DELETE http://127.0.0.1:8000/documents/<doc_id>
```

| Endpoint | Method | Description |
|---|---|---|
| `/documents/upload` | POST | Upload + ingest a file (multipart form) |
| `/ask` | POST | `{"question": "...", "top_k": 4}` → grounded answer + sources |
| `/documents` | GET | List ingested documents |
| `/documents/{doc_id}` | DELETE | Delete one document |
| `/documents` | DELETE | Wipe everything |
| `/health` | GET | Health check |

Both `server.py` (MCP) and `api.py` (FastAPI) call into the same
`qa_service.py` module, so ingestion/retrieval/answer logic lives in one
place — pick whichever interface fits your use case, or run both.

## 4b. Connect it to Claude Desktop

Add this to your Claude Desktop config
(`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS,
`%APPDATA%\Claude\claude_desktop_config.json` on Windows):

```json
{
  "mcpServers": {
    "document-qa": {
      "command": "/absolute/path/to/mcp-doc-qa/venv/bin/python",
      "args": ["/absolute/path/to/mcp-doc-qa/server.py"]
    }
  }
}
```

Restart Claude Desktop. You should see the `document-qa` server's five tools
available in a new chat.

## Tools exposed

| Tool | Description |
|---|---|
| `add_document(file_path)` | Ingest a PDF/DOCX/TXT/MD file |
| `ask_question(question, top_k=4)` | Get a grounded answer from ingested docs |
| `list_documents()` | See what's stored |
| `delete_document(doc_id)` | Remove one document |
| `clear_all_documents()` | Wipe everything |

(The FastAPI app exposes the equivalent operations as REST endpoints — see
section 4a above.)

## Notes & things to tune later

- **Chunking**: character-based with paragraph/sentence-aware breaks
  (`document_loader.py`). Swap in a smarter splitter (e.g. token-based) if
  you hit weird cuts.
- **Embedding model**: `all-MiniLM-L6-v2` is small and fast. For better
  recall, try `all-mpnet-base-v2` (slower, bigger) via `.env`.
- **Groq model**: defaults to `llama-3.3-70b-versatile`. Check
  https://console.groq.com/docs/models for current options.
- **Persistence**: the Chroma DB lives in `./chroma_db` — delete that folder
  to fully reset, or just call `clear_all_documents`.
- **Scanned PDFs**: this uses `pypdf` text extraction, which won't work on
  image-only/scanned PDFs. Add OCR (e.g. `pytesseract`) if you need that.

Maintenance

ActivitySlowing
ResponsivenessNo issues