{
  "markdown": "# pdf-mcp\n\n[![PyPI version](https://img.shields.io/pypi/v/pdf-mcp)](https://pypi.org/project/pdf-mcp/)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![GitHub Issues](https://img.shields.io/github/issues/jztan/pdf-mcp)](https://github.com/jztan/pdf-mcp/issues)\n[![CI](https://github.com/jztan/pdf-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/jztan/pdf-mcp/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/jztan/pdf-mcp/graph/badge.svg)](https://codecov.io/gh/jztan/pdf-mcp)\n[![Downloads](https://pepy.tech/badge/pdf-mcp)](https://pepy.tech/project/pdf-mcp)\n\n**Agentic RAG over your PDFs, one file or a whole folder, as a single MCP tool.**\n\nThe agent decides when to search; pdf-mcp does the retrieval and hands back excerpts. It is an [MCP](https://modelcontextprotocol.io/) server that lets Claude Code and other AI agents search one PDF or a whole folder by meaning or keyword, read only the pages that matter, and cleanly pull out tables, images, and scanned text, even from multi-column and Japanese layouts, with optional CUDA acceleration for warming large corpora.\n\n**mcp-name: io.github.jztan/pdf-mcp**\n\n## Try it in your browser\n\n**[See what your AI agent sees →](https://pdf-mcp.jztan.com/)**\n\nDrop in any PDF, or a whole folder of them, and watch an agent triage the corpus, search across every document at once, and read only the pages that matter, using a fraction of the tokens. 100% client-side, no install required.\n\n<p align=\"center\">\n  <a href=\"https://pdf-mcp.jztan.com/\"><img src=\"https://raw.githubusercontent.com/jztan/pdf-mcp/develop/docs/images/demo.gif\" alt=\"pdf-mcp browser demo: an AI agent warms a 6-PDF corpus, triages it, searches across all six documents, and reads only the matching page, with 97.3% of the corpus never entering the context window\" width=\"760\"></a>\n</p>\n\n## Why pdf-mcp?\n\n| | Without pdf-mcp | With pdf-mcp |\n|---|---|---|\n| Large PDFs | Context overflow | Read only the pages you need |\n| Finding content | Load everything | Hybrid search: BM25 keyword + semantic |\n| Folders of PDFs | One document at a time | Warm, triage, and search a whole folder |\n| Warming a big folder | Minutes of CPU embedding | Length-sorted small-batch CPU encode; optional CUDA embedding, one to two orders of magnitude faster on an NVIDIA card |\n| Tables and charts | Lost in raw text | Structured rows, and `(x, y)` data from vector charts |\n| Multi-column and vertical layouts | Columns interleaved | Correct reading order, including Japanese tategaki |\n| Scanned PDFs | No text at all | OCR via Tesseract, parallel across pages |\n| Repeated access | Re-parse every time | SQLite cache that survives restarts |\n| Hidden or injected text | Silently ingested | Flagged as untrusted, nothing stripped |\n\n## Installation\n\n```bash\npip install pdf-mcp\n```\n\nThat is the whole install: hybrid search, corpus tools, multi-column and\nCJK reading order all work out of the box.\n\nOCR on scanned PDFs additionally needs system Tesseract:\n\n```bash\nbrew install tesseract        # macOS\napt install tesseract-ocr     # Ubuntu/Debian\nwinget install Tesseract-OCR  # Windows\n```\n\nGPU embedding is optional and off by default. On an NVIDIA card it makes the\nembedding pass one to two orders of magnitude faster; set `PDF_MCP_CUDA=1`\nafter installing the CUDA build of onnxruntime. Setup per CUDA series is in\n[docs/configuration.md](docs/configuration.md#gpu-embedding-nvidia-cuda).\n\n## Quick Start\n\n```bash\nclaude mcp add pdf-mcp -- pdf-mcp\n```\n\nThen ask Claude to read a PDF. For Claude Desktop, VS Code, Codex CLI,\nKiro, or any other MCP client, see **[docs/clients.md](docs/clients.md)**.\n\npdf-mcp's tools are also plain Python functions, so you can import them\nand hand a PDF to the Anthropic SDK without running a server. Two\nrunnable scripts, for a question and for a whole document:\n**[examples/](examples/)**.\n\nWhy this exists, and what broke along the way: [Claude's 100-page PDF limit and how I got around it](https://blog.jztan.com/how-i-built-pdf-mcp-solving-claude-large-pdf-limitations/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=quickstart-how-i-built-pdf-mcp-solving-claude-large-pdf-limitations)\n\n## Tools\n\n13 specialized tools rather than one monolithic one. Typical pattern:\n`pdf_info` to plan, `pdf_search` to locate (its paragraph excerpts often\nanswer the question outright), `pdf_read_pages` when you need more. For a\nfolder, `pdf_corpus_overview` to triage, then `pdf_corpus_search`.\n\n| Tool | What it does |\n|------|--------------|\n| `pdf_info` | Page count, metadata, TOC summary, scanned-page detection. **Call first.** |\n| `pdf_search` | Hybrid search (keyword + semantic), page or section granularity, paragraph or context-window excerpts with source coordinates |\n| `pdf_read_pages` | Read specific pages or ranges, with OCR on demand, tables, and embedded images |\n| `pdf_read_all` | Read a whole document in one call, byte-capped |\n| `pdf_get_toc` | Full table of contents for documents with many bookmarks |\n| `pdf_render_pages` | Render pages as PNG for vision models: diagrams, handwriting, scans |\n| `pdf_extract_chart` | Chart data as exact `(x, y)` tables, read from plot geometry |\n| `pdf_corpus_warm` | Warm a folder of PDFs into the cache within a time budget |\n| `pdf_corpus_overview` | Per-document triage cards for a folder |\n| `pdf_corpus_search` | Search across a folder, with document and page provenance; `excerpt_style=\"auto\"` picks the excerpt unit per query |\n| `pdf_cache_stats` | Per-document cache breakdown and total size |\n| `pdf_cache_clear` | Clear expired or all cache entries |\n| `server_info` | Which optional features and config are active |\n\nText returned by any of these is untrusted content extracted from a PDF.\n`pdf_info(content_trust=True)` reports hidden text a human reader cannot\nsee, and the read tools flag it per page.\n\nExample prompts:\n\n```\n\"Read the PDF at /path/to/document.pdf\"\n\"Which pages discuss supply chain risks?\"\n\"Find sections about the training process\"\n\"Show me what page 5 looks like\"\n\"OCR pages 3-5 of the scanned PDF\"\n```\n\nFull reference, every parameter and response shape:\n**[docs/tool-reference.md](docs/tool-reference.md)**. Embedding model\nselection: **[docs/embedding-models.md](docs/embedding-models.md)**.\n\n## Example Workflow\n\nFor a large document (e.g., a 200-page annual report):\n\n```\nUser: \"Summarize the risk factors in this annual report\"\n\nAgent workflow:\n1. pdf_info(\"report.pdf\")\n   → 200 pages, TOC shows \"Risk Factors\" on page 89\n\n2. pdf_search(\"report.pdf\", \"risk factors\")\n   → Matches with structural paragraph excerpts: each excerpt\n     is the bullet, paragraph, or heading that matched, not a\n     fixed-width window. Often enough to answer directly.\n\n3. If excerpts are sufficient → synthesize answer\n\n4. If more context needed:\n   pdf_read_pages(\"report.pdf\", \"89-95\")\n   → Full page text for deeper reading\n```\n\n## Remote / HTTP transport\n\nSTDIO is the default and is what every example above uses. `pdf-mcp-http`\nserves the same tools over HTTP, for clients that cannot spawn a process\n(the Anthropic API MCP connector, claude.ai custom connectors) and for a\nwarm corpus shared by several clients.\n\n```bash\nexport PDF_MCP_AUTH_TOKEN=\"$(openssl rand -hex 32)\"\npdf-mcp-http\n```\n\nPaths resolve on the server, so an HTTP agent reads what is already there:\nfiles under an allow-listed root, or a URL the server fetches. It cannot\nhand over a file from its own machine. It is single-tenant and fails\nclosed: with no auth token and no `[paths]` allow list, the process exits\nrather than serving an open endpoint.\n\nDocker images are published to GHCR for amd64 and arm64, with everything\nbaked in, so every tool works on the first request:\n\n```bash\n./deploy.sh              # token, image, start, health-check\ncp your.pdf documents/   # this folder is the server's /data/pdfs\n```\n\nRead **[docs/remote-access.md](docs/remote-access.md)** for the trust\nboundary and threat model before deploying, and\n**[docs/configuration.md](docs/configuration.md#http-transport-setup)**\nfor setup, client config, and token rotation.\n\n## Configuration\n\npdf-mcp works out of the box. To restrict which paths and URL hosts the\nserver may touch, tune cache and worker settings, or add your own\ncontent-trust phrases, see **[docs/configuration.md](docs/configuration.md)**.\n\n## Roadmap\n\nSee [ROADMAP.md](docs/ROADMAP.md) for planned features and release history.\n\n## Contributing\n\nContributions are welcome. See **[docs/contributing.md](docs/contributing.md)** for setup, checks, the coherence eval harness, and quality-loop guidelines.\n\n## Contributors\n\nThank you to everyone who has helped improve this project through code, reviews, testing, and feature requests:\n\n<!-- contributors:start -->\n[@Summer907](https://github.com/Summer907) · [@ebbsanchez](https://github.com/ebbsanchez) · [@VooDisss](https://github.com/VooDisss) · [@DerDennisOP](https://github.com/DerDennisOP) · [@deepdmk](https://github.com/deepdmk) · [@TheSOV](https://github.com/TheSOV)\n<!-- contributors:end -->\n\n<a href=\"https://github.com/jztan/pdf-mcp/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=jztan/pdf-mcp\" alt=\"Contributors\" />\n</a>\n\nPer-release contributor credits are listed in the [Changelog](./CHANGELOG.md).\n\n## Security\n\nFound a vulnerability? See [SECURITY.md](SECURITY.md) for the threat model, reporting channel, and expected response timeline. Please do not open a public GitHub issue for unpatched security reports.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n\n## Links\n\n- [pdf-mcp on PyPI](https://pypi.org/project/pdf-mcp/)\n- [pdf-mcp on GitHub](https://github.com/jztan/pdf-mcp)\n\n## Blog posts\n\n**The story behind the releases.** Building pdf-mcp keeps surprising me: benchmarks that go the wrong way, formats that break everything, features I had to remove. I write about that thinking in [The Dispatch](https://blog.jztan.com/newsletter/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-newsletter). Come along if that's your kind of thing.\n\nBackground, benchmarks, and design notes from building pdf-mcp:\n\n**Getting started**\n\n- [How I Built pdf-mcp](https://blog.jztan.com/how-i-built-pdf-mcp-solving-claude-large-pdf-limitations/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-how-i-built-pdf-mcp-solving-claude-large-pdf-limitations): The problem with large PDFs in AI agents and a working solution\n- [How to Send PDFs Over 100 Pages to Claude's API](https://blog.jztan.com/llm-api-pdf-page-limits/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-llm-api-pdf-page-limits): Measuring the real page and token ceilings on the Claude API, and the two ways around them: search the PDF on disk for questions, window the text and render only the picture pages for whole-document tasks\n- [How Claude Code Actually Reads PDFs](https://blog.jztan.com/how-claude-code-actually-reads-pdfs-lessons-from-building-an-mcp-server/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-how-claude-code-actually-reads-pdfs-lessons-from-building-an-mcp-server): How AI agents use pdf-mcp tools to read and navigate PDF documents\n- [How AI Agents Should Read PDFs: 5 Patterns That Survived Production](https://blog.jztan.com/ai-agent-pdf-reading-patterns/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-ai-agent-pdf-reading-patterns): Five production-tested patterns for how agents should navigate PDFs at scale\n\n**Corpus & multi-document search**\n\n- [A Knowledge Base Is Just a Folder](https://blog.jztan.com/ai-agent-pdf-knowledge-base/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-ai-agent-pdf-knowledge-base): Turning a folder of PDFs into an agent knowledge base with the corpus tools, no ingestion pipeline or vector store\n- [Cross-Document Retrieval for AI Agents Without a Vector Database](https://blog.jztan.com/rag-without-vector-database/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-rag-without-vector-database): Why BM25 scores don't merge across per-document indexes but ranks do, and how two-stage RRF puts a gold document in the top 3 on 84.8% of 184 graded queries over a 100-PDF corpus\n\n**Search & retrieval**\n\n- [Semantic vs Keyword Search for AI Agents](https://blog.jztan.com/semantic-vs-keyword-search-ai-agents/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-semantic-vs-keyword-search-ai-agents): Benchmarks and a dual-search routing pattern: FTS5 for exact identifiers, embeddings for natural language\n- [Hybrid Search vs Query Routing for AI Agents](https://blog.jztan.com/hybrid-search-vs-query-routing-ai-agents/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-hybrid-search-vs-query-routing-ai-agents): Why pdf-mcp uses hybrid RRF instead of query routing: benchmarks showing RRF wins across query types\n- [Section Chunking vs Page Chunking for AI Agents](https://blog.jztan.com/section-chunking-vs-page-chunking-ai-agents/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-section-chunking-vs-page-chunking-ai-agents): Why section-aware search delivers full section content in one call while page-mode costs 2–6 extra tool calls per query\n- [Section-Level RAG: Why BM25 Beat Hybrid Search in My Benchmark](https://blog.jztan.com/bm25-vs-hybrid-search-section-rag/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-bm25-vs-hybrid-search-section-rag): Why pdf-mcp's section-grain search is BM25-only: hybrid RRF caused a 33% lexical regression at section grain, so granularity decides the search technique\n- [How One Search Change Eliminated an Entire Agent Step](https://blog.jztan.com/how-paragraph-excerpts-changed-agent-behavior/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-how-paragraph-excerpts-changed-agent-behavior): Switching pdf_search from fixed-width snippets to paragraph excerpts turned it from a pivot tool into a terminal tool: 97% vs 80% answer containment across a 30-query benchmark\n\n**Engineering & security**\n\n- [MCP Server Security: 8 Vulnerabilities](https://blog.jztan.com/mcp-server-security-8-vulnerabilities/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-mcp-server-security-8-vulnerabilities): What we found when we audited an MCP server for security holes\n- [Your LLM Is Free QA for Your MCP Server](https://blog.jztan.com/llm-free-qa-mcp-server/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-llm-free-qa-mcp-server): Four Payload UX bugs in pdf-mcp that schema tests missed but Claude Desktop surfaced during real use\n- [Why Multi-Column PDFs Scramble Reading Order in RAG](https://blog.jztan.com/multi-column-pdf-reading-order/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-multi-column-pdf-reading-order): Fixing two-column extraction (0.564 → 0.816 fidelity), the title-page author-grid regression it caused, and the aggregate metric that stayed blind to both\n- [How I Fixed Vertical Japanese PDF Extraction](https://blog.jztan.com/vertical-japanese-pdf-reading-order/?utm_source=github&utm_medium=referral&utm_campaign=pdf-mcp&utm_content=list-vertical-japanese-pdf-reading-order): Tategaki pages extract scrambled because reading order is geometric, not stored; rebuilding it from glyph positions (columns right to left, characters top to bottom), with no OCR and no new dependency\n",
  "bytes": 15701,
  "sha": "ca74ff9f3f23ae4861a7d85935a2ad91a9d4ff665fe36dd540feb29bc04d80c6",
  "repo_slug": "jztan/pdf-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_jztan_pdf_mcp_54b7d791/readme"
}