context-retrieval
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@context-retrieval Index /docs/report.pdf and tell me what it says about retention policy"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Context Retrieval System Powered by RAG and MCP Server
A hybrid context-retrieval system built on the Model Context Protocol (MCP) and Retrieval-Augmented Generation (RAG). It exposes multimodal PDF parsing and a fully local vector-search pipeline as MCP tools, so AI agents (Claude Desktop, Cursor, or any MCP-compatible client) can fetch real-time document context on demand instead of relying on pre-loaded, static knowledge.
Highlights
MCP-native — 7 JSON-in/JSON-out tools served over stdio (local) or streamable-HTTP (network), built on the official
mcpPython SDK.Multimodal parsing — PyMuPDF extracts structured text and base64-encoded images; Camelot (lattice/stream, with a PyMuPDF fallback) extracts complex tables straight into LLM context windows.
Local RAG pipeline — LangChain
RecursiveCharacterTextSplitterchunking, on-device fastembed embeddings (BGE-small, ONNX), and a FAISS vector store. No external embeddings API, no per-query cost, no data leaving the machine.Sub-linear search — cosine similarity over L2-normalised vectors; above a configurable threshold the store switches to an IVF (inverted-file) index, keeping query latency approximately O(log N) as the corpus grows.
Persistent & re-entrant — the FAISS index, raw vectors and chunk metadata persist to disk; re-indexing a changed document replaces its chunks (content-hash doc IDs).
Safe by default — every tool path is validated (null bytes, existence, extension, optional allow-list roots) and returns structured JSON errors instead of crashing the server.
Containerized + CI — Dockerfile (with the embedding model pre-baked) and GitHub Actions running lint, the full test suite including end-to-end MCP protocol tests, and a containerized smoke test.
Related MCP server: MinerU Document Explorer
Setup
git clone https://github.com/ESPChong/context-retrieval-system-RAG-MCP.git
cd context-retrieval-system-RAG-MCP
python3.12 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install -e . --no-deps # optional: `python -m context_retrieval` from anywhere
# stdio mode is what Claude Desktop / Cursor launch:
.venv/bin/python -m context_retrievalThe embedding model (~35 MB) downloads from Hugging Face once and is cached locally; after that the system runs fully offline.
Try the pipeline without any MCP client:
.venv/bin/python scripts/demo.pyTool reference
Tool | Purpose | Key parameters |
| Per-page structured text + PDF metadata |
|
| Embedded images as base64 PNG + geometry |
|
| Tables via Camelot lattice/stream, PyMuPDF fallback; |
|
| Chunk → embed (local) → FAISS, persists the store |
|
| Top-k semantic search with scores + source/page provenance |
|
| Store status: docs, chunks, dimension, index type | — |
| Drop all indexed documents | — |
Connect an MCP client
{
"mcpServers": {
"context-retrieval": {
"command": "/absolute/path/to/context-retrieval-system-RAG-MCP/.venv/bin/python",
"args": ["-m", "context_retrieval"],
"env": {
"CONTEXT_RETRIEVAL_DATA_DIR": "/absolute/path/to/context-retrieval-system-RAG-MCP/data",
"CONTEXT_RETRIEVAL_ALLOWED_ROOTS": "/absolute/path/to/your/pdfs"
}
}
}
}(ready-to-edit copy in docs/claude-desktop-config.json)
Same mcpServers object; copy in docs/cursor-mcp.json.
# stdio mode (pipe JSON-RPC, e.g. from an MCP host):
docker build -t context-retrieval .
docker run -i --rm -v "$PWD/docs:/docs" context-retrieval
# network mode (streamable-http on http://localhost:8000/mcp):
docker compose up --buildOnce connected, just ask: "Index /docs/report.pdf and tell me what it says about retention policy." — the client will chain index_document → search_context (or the extraction tools) automatically.
Configuration (env vars)
Variable | Default | Meaning |
|
| Where |
|
| Local fastembed model (384-dim) |
|
| LangChain splitter parameters |
|
| Vectors above this switch Flat → IVF index |
|
| IVF clusters probed per query |
| (unrestricted) | Comma-separated directory allow-list for tool paths |
| images 10 / 400 KB / tables 30 / rows 200 / pages 500 | Context-window guard rails |
Testing
.venv/bin/python -m pytest -v19 tests, including end-to-end MCP protocol tests that spawn the real server over stdio and exercise the full handshake → tool-call → RAG-roundtrip path. A deterministic 3-page sample PDF (prose / ruled table / embedded image) is generated by the suite itself.
.venv/bin/python scripts/make_sample_pdf.py my-sample.pdf # inspect it yourselfDesign notes
Why local embeddings? Removing the external embeddings API eliminates per-query cost and network latency, and keeps document content on the machine. fastembed runs quantized-ready ONNX models — a 384-dim BGE-small that embeds ~2,600 chunks/sec on a laptop CPU.
What "≈ O(log N)" means here. Flat exact search scans all N vectors. The IVF index partitions the space into
nlist ≈ 4·√Nclusters and compares the query against onlynprobeof them plus their members — sub-linear, logarithmic-style growth in practice, at the cost of a small recall trade-off tunable vianprobe.Chunk provenance. Chunking runs per page, so every retrieved fragment carries
page+source, letting the host model cite where an answer came from — the antidote to hallucinated citations.Graceful degradation. Camelot's lattice mode needs Ghostscript; when it is missing (thin environments),
autosilently falls back to stream, then to PyMuPDF's detector, and table extraction still succeeds.
Available Tools
7 toolsextract_document_imagesA
Extract embedded images from a PDF as base64 PNG (PyMuPDF). Each image carries page, width, height and byte size. Set include_data=false to inventory images without transferring payloads; oversized images return metadata only.
Inputs: pdf_path (required), pages, max_images, include_data. Returns: result
extract_document_tablesA
Extract tabular data from a PDF (Camelot lattice/stream with a PyMuPDF fallback; flavor='auto' picks the first strategy that finds tables). Returns JSON with rows, columns and CSV per table.
Inputs: pdf_path (required), pages, flavor. Returns: result
extract_document_textA
Extract structured text from a PDF, page by page (PyMuPDF). Returns JSON: page count, document metadata, and each page's text with 1-based page numbers — use pages='1-3' or '1,5' to limit output.
Inputs: pdf_path (required), pages. Returns: result
index_documentA
Index a PDF into the local RAG store: PyMuPDF text -> LangChain chunking -> local fastembed embeddings -> FAISS. Call once per document, then use search_context for queries. Re-indexing a changed file replaces its chunks (set replace=false to append).
Inputs: pdf_path (required), replace, chunk_size, chunk_overlap. Returns: result
index_infoA
Report vector store status: documents, chunk count, dimension, FAISS index type.
Inputs: no named parameters. Returns: result
reset_indexA
Drop every indexed document and clear the persisted vector store.
Inputs: no named parameters. Returns: result
search_contextA
Semantic search over indexed documents (FAISS + local embeddings). Returns the top-k chunks ranked by cosine similarity with source file and page provenance — feed these to your answer generation. Optional source_filter narrows hits to one document.
Inputs: query (required), k, source_filter. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 7 tools
Each tool targets a distinct operation: reset/index/status/retrieval are clearly separated from the three extraction tools, which differ by output type (text/images/tables). Even though extract_document_text and index_document both process PDFs, one returns extracted text while the other persists chunks into the vector store, so an agent can choose unambiguously.
Most tools follow a verb_noun pattern (reset_index, index_document, search_context), and the extract_document_* family is perfectly consistent. index_info is slightly off-pattern because it reads as a noun phrase rather than verb + object, but this is a minor deviation.
Seven tools is a well-scoped size for a PDF extraction and RAG retrieval server. Each tool earns its place and there is no redundant duplication.
The core workflow is covered: documents can be extracted, indexed, searched, and the entire index can be reset. The main gap is the lack of a way to delete a single document from the index, with only reset_index for the whole store, and no explicit list of indexed file names.
Related MCP Connectors
Query your own PDFs and documents from any MCP client. Every answer cites the page it came from.
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Generate and read PDFs for AI agents: a generate_pdf and a read_pdf tool, priced per document.
Convert PDF documents to Markdown for AI agents through an authenticated remote MCP server.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to download, index, and semantically search PDF research papers using 8 MCP tools.4GPL 3.0
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to search, deep-read, and build knowledge bases from Markdown, PDF, DOCX, and PPTX documents via MCP tools for retrieval, document navigation, and ingestion.23 npm652MIT
- FlicenseNot gradedqualityDmaintenanceIndexes PDF documents into Qdrant and exposes semantic search as MCP tools, enabling RAG-based interactions with your documents.-
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to extract structured data from PDFs with confidence scores and provenance, and to search, review, and correct documents via MCP tools, resources, and prompts.-