local-pdf-rag-mcp

by arjun7965

Not rated
GitHub

About

A fully-local MCP server for question-answering over your PDFs. Ask in plain language; Claude retrieves only the relevant passages with page citations. On-device embeddings (sentence-transformers) + ChromaDB — no API keys, nothing leaves your machine.

Details

Author
arjun7965
Categories
Productivity, Other, AI

Setup

Install local-pdf-rag-mcp in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/arjun7965/local-pdf-rag-mcp

Follow the installation instructions in the repository README, then restart your MCP client.

A fully-localMCPserver that lets Claude (or any MCP client) answer questions over your PDFs. Point it at a PDF, ask questions in plain language, and the model fetches only the relevant passages — with page-level citations — instead of swallowing the whole document.

- Fully local by default.Embeddings run on-device (sentence-transformers) and vectors are stored on disk (ChromaDB). No API keys, nothing leaves your machine.
- Token-cheap.Only a handful of relevant chunks are sent to the model per question, not the entire document.
- Cited answers.Every retrieved chunk carries its source filename and page number.
- Any PDF, many PDFs.Index a single file or a whole folder, organized into named collections.

Ingestion (once per document) extracts the text page by page, splits it into overlapping ~250-token chunks that respect paragraph boundaries, embeds each chunk locally, and stores them in ChromaDB. At query time the server embeds your question, pulls the top ~20 chunks from vector search, then reranks them with a local cross-encoder so the most relevant ones surface first. The model reads those chunks and writes the answer — the server deliberately doesnotgenerate answers itself, which keeps it simple and model-agnostic.

- Python 3.10+
- ~170 MB disk for the two default models, downloaded automatically and cached: the embedding model (~80 MB, fetched on first ingest/search) and the cross-encoder reranker (~80 MB, fetched on first search). Reranking can be turned off withPDF_RAG_RERANK=0if you'd rather skip the second download.

git clone https://github.com/arjun7965/local-pdf-rag-mcp.git cd local-pdf-rag-mcp pip install -e .

The repository includes a uv2nix flake with a locked Python dependency set:

nix run github:arjun7965/local-pdf-rag-mcp

For local development, enter the editable environment withnix develop. It provides the application dependencies anduvwithout modifying the project environment; useuv lockwhen changing dependencies.

If you installed it withpip install -e ., register the console command:

codex mcp add pdf-rag -- local-pdf-rag-mcp

Or run it straight from GitHub without cloning, usinguv'suvx:

codex mcp add pdf-rag -- uvx --from git+https://github.com/arjun7965/local-pdf-rag-mcp.git local-pdf-rag-mcp

Codex CLI and the Codex IDE extension share MCP configuration. To configure the server manually, add this to~/.codex/config.toml, or to.codex/config.tomlfor a trusted project:

[mcp_servers.pdf-rag] command = "local-pdf-rag-mcp"

Start a new Codex session after registering the server. In the Codex terminal UI, use/mcpto check that it is active. See theCodex MCP documentation.

If you installed it (thepip install -e .above), point Claude Code at the console command:

claude mcp add pdf-rag -- local-pdf-rag-mcp

Or run it straight from GitHub without cloning, usinguv'suvx— it fetches and caches the package on first launch:

claude mcp add pdf-rag -- uvx --from git+https://github.com/arjun7965/local-pdf-rag-mcp.git local-pdf-rag-mcp

Or add it manually to your Claude MCP config:

{ "mcpServers": { "pdf-rag": { "command": "local-pdf-rag-mcp" } } }

Restart Claude Code so it picks up the new server.

The server exposes four tools. In practice you just talk to Claude and it calls them for you:

You:Ingest the spec at ~/docs/pcie-5.0.pdf into a collection called "pcie".

Claude callsingest_pdf→ "Ingested into collection 'pcie': pcie-5.0.pdf: 712 pages, 2{,}480 chunks"

You:How does link equalization work during training?

Claude callssearchwith your question, reads the returned passages, and answers — citing e.g.pcie-5.0.pdf, p.412.

By default, text is extracted linearly — tables get flattened into prose, which scatters a row's cells and hurts retrieval on dense technical docs. SetPDF_RAG_TABLES=1to detect ruled tables and serialize them one record per row (Field: Foo; Bits: 0-3; Description: ...), so a query about a single row matches that row's record directly. Detection is conservative (it relies on ruling lines, so whitespace-aligned prose isn't misread as a table), and any page with no detected table falls back to the normal prose path. Re-ingest after enabling, since the change only affects future ingests.

Only ruled tables are detected.Because detection requires visible grid lines,borderlesstables — columns aligned by whitespace with no ruling lines — are not recognized and fall back to the prose path, where their cells get flattened into linear text. This is a deliberate tradeoff: alignment-based detection would catch borderless tables but also misreads ordinary prose layouts as tables, shredding them into junk cells. If your documents rely on borderless tables,PDF_RAG_TABLESwon't help with them.

The default isall-MiniLM-L6-v2and the rest of the project is tuned around it:

- Why this model.Small (~80 MB), fast on CPU, no GPU required, decent general-English retrieval quality, Apache-2.0 licensed. Standard default in the sentence-transformers ecosystem.
- Input limit: 256 tokens.sentence-transformers silently truncates inputs above the model'smax_seq_length. Chunks are sized to stay within this window so the embedding reflects the whole chunk, not just its head. If you swap in a model with a different limit (e.g.BAAI/bge-large-en-v1.5at 512), consider raisingtarget_tokensinchunk_pagesto match — otherwise you're paying for capacity you don't use.
- Output: a 384-dim vector.Each chunk embeds to a fixed 384-dimensional vector regardless of its length (the model produces a vector, not text, so there's no output-token limit). ChromaDB infers this dimensionality automatically; a different model with a different size just works, but mixing vectors of different sizes in one collection does not — re-ingest after switching models.
- Swapping.Any sentence-transformers model from HuggingFace works:

PDF_RAG_EMBED_MODEL=BAAI/bge-large-en-v1.5 local-pdf-rag-mcp

- No OCR.Scanned or image-only PDFs have no extractable text; the server detects this and returns a clear error rather than indexing nothing.
- Encrypted PDFsopen only if they use an empty password.
- Borderless tables.Even withPDF_RAG_TABLES=1, only tables with visible grid/border lines are detected. Whitespace-aligned tables are flattened into prose like any other text (see Configuration → Table-aware extraction).
- Embedding input cap.Chunks longer than the embedding model'smax_seq_length(256 tokens for the default MiniLM) are silently truncated by sentence-transformers — the full text is still stored and returned, but the vector reflects only the head. Keeptarget_tokensaligned with whatever model you use.
- Tuned for a single-machine, single-user workflow. For multi-user or very-large-scale deployments you'd swap ChromaDB for a hosted vector store.

MCP server for Prompt Builder — search, retrieve, and compile prompt components from a community vault using semantic search (pgvector) and slug-based lookup. Works with Claude Desktop and Cursor.

Private persistent memory for Claude, ChatGPT & Gemini via MCP — semantic search, zero-code setup.

An MCP server for web and similarity search, designed for Claude Desktop. It integrates with various external embedding and API services.

A server providing web and similarity search functionalities, designed for Claude Desktop. It requires external embedding and API services.

Offline MCP server that ranks & summarizes code using BM25, TF-IDF, embeddings & git signals; integrates with Cursor, Claude Desktop and Windsurf; privacy preserving.

Persistent visual cache for LLM-driven software development. Caches screenshots using perceptual hashing, vector search, and AX trees to prevent token overhead and visual hallucination loops.

Persistent memory for any AI assistant. Zero token cost until recall. Stores memories in local SQLite, ranks by 6-factor scoring, returns results 79% smaller than JSON. Works with Claude, ChatGPT, Grok, Cursor, Windsurf, and any MCP client.

Transform your scattered documentation into AI-ready knowledge that works seamlessly with Claude, Cursor, VS Code, and other AI tools.

Plug your AI agent into OpenCharts—build spreadsheets, boards, music, and automations from Claude Code, Codex, or Cursor without leaving your terminal.

An AI-powered bridge connecting assistants like Claude and ChatGPT to RADAAR for managing posts, inboxes, analytics, and social listening across 20+ channels using natural language.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.