Purpose
PDF Card MCP is for PDFs that you actually need to read, cite, or inspect. It breaks long documents into smaller cards linked to their source, keeps tables, charts, and formulas as faithful image crops, and lets you export notes and highlights as Markdown.
Main capabilities
- Local-first: by default conversion runs locally and requires no hosted service. The deterministic converter does not upload document content or call external APIs.
- Source preservation: preserves the source text, renders the source page for verification, and establishes source links for cards.
- Image cropping: performs image cropping on detected tables, charts, and display formulas, preserving layout and digit alignment, superscripts and subscripts, arrows, and mathematical spacing.
- Style derivation: derives safe reader styles from the original PDF color palette.
- Standalone output: writes standalone HTML files that can be moved across devices without losing resources.
- Reading experience: the default reader has large fonts, small cards, search, section navigation, previous/next page controls, keyboard navigation, a font size slider, and source page preview.
- Annotations: supports highlights (selecting source text) and notes (selecting source text plus your own note text), and can be exported as
.annotations.md. - Static publishing: can generate a read-only static reader with public annotations.
How to use
One-click installation
PDF Card MCP is a Python server and requires a runtime. The only thing that needs to be installed first is uv—it manages Python for you.
Claude Code (terminal) runs the published pdf-card-mcp package via uv.
Claude Desktop (no terminal, no prerequisites): download pdf-card-mcp-desktop.mcpb from the latest release and double-click to install it as an extension. The bundle declares the uv runtime, so Claude Desktop will install Python and dependencies for you.
After installation, restart (or reload the MCP server) your client so it recognizes the new server.
Command-line conversion
Convert a local PDF into a portable HTML reader; you can also use the explicit subcommand form combined with PDF-derived styles.
Run the MCP server
Let a compatible host generate a reader from a local PDF path.
Publish a static reader
Publish a read-only static reader with selected public annotations.
Other installation methods
Install from PyPI; or install the latest unreleased changes directly from the repository; local development; uv is recommended for MCPB packaging.
Install an optional local ML table detector for stronger table cropping.
Using in an MCP client
Add it to Claude Code or another compatible CLI MCP client via uvx (requires uv). A generic MCP host configuration can also be used. For local development before the PyPI release, you can point the client at this checkout. Claude Desktop can also install the .mcpb bundle from the latest GitHub release.
Docker / registry scanner
The repository includes a minimal Dockerfile so that registries such as Glama can build the server, start it via stdio, and inspect its MCP tool schema. The server still operates on local file paths, so container users must mount the PDF and output directories that they want the tools to read and write.
Output
document.html: a standalone reader with embedded CSS, JavaScrript, table cropping, chart cropping, formula cropping, and source page images. document.manifest.json: structured metadata without embedded image payloads.
Notes, Highlights, and Static Publishing
The generated reader includes a local annotation overlay: highlights are selected source text; notes are selected source text plus your own typed note text. Select text in a text card, choose Highlight or Note, and use Export Markdown to download a readable .annotations.md file. The reader UI currently intentionally does not expose import functionality. Notes and highlights are user-authored data, stored separately from the source-derived document.manifest.json.
The lower-level CLI and MCP publishing tools still accept structured annotation bundles, used to build read-only static readers with embedded annotations. The bundle can be validated against a given reader, and a shareable static reader can be published. If --output is a directory rather than an .html file, the command writes out a static bundle: reader.manifest.json and reader.annotations.json.
Publishing by default includes only visibility: public annotations, by default conceals local source_pdf paths, and by default renders the published reader as read-only. Use --include-private only when you intend to include private local notes in the published output. If any included annotation cannot be anchored to the reader, publishing fails; before publishing, you can run validate-annotations to check for mismatches.
MCP Tools
The MCP server is an automation layer around the same local converter, accepting local file paths from MCP clients and returning the generated reader path, manifest metadata, warnings, and publishing/validation results. The server exposes three tools:
- Conversion tool parameters include: pdf_path (local PDF path); output_path (optional HTML output path); title (optional title override); standalone (default true, resource folder output reserved for a later version); ocr (optional OCR fallback, requires pytesseract to be installed); max_pages (optional processing limit); theme (default soft); style_engine (fixed, pdf, or sampling, default pdf. fixed preserves the original soft palette, pdf derives bounded colors and typography hints locally from the source PDF, sampling lets the host LLM choose validated style tokens from these local hints); table_engine (auto, pdfplumber, or gmft, auto uses gmft when it is installed); text_engine (char_geometry or pdfplumber_words, default char_geometry, repairs missing spaces from PDF character positions rather than trusting glued words); postprocess_engine (none or sampling, default none. When set to sampling, the MCP server has the host LLM perform boundary-only card polishing operations, validates that the original text is preserved exactly, and rewrites the generated reader. If the MCP client does not support sampling, it returns deterministic output and gives a warning); model_cache_dir (optional, cache directory for local ML table model weights); offline (use only cached optional ML models).
- validate_reader_annotations: validates the notes/highlights sidecar against the generated reader.
- publish_reader_bundle: writes a publishable static HTML file or directory bundle from an existing generated reader and optional annotation sidecar.
Sampling post-processing is deliberately narrowed. For card boundaries, the host LLM may suggest merges, title extraction, or front matter/footnote classification, but Python validation rejects any operation that rewrites, deletes, fabricates, or reorders source text. For style_engine=sampling, the host LLM may only choose bounded style tokens and palette candidate IDs; it cannot return raw CSS, JavaScript, or arbitrary colors. If sampling is unavailable, the reader retains deterministic PDF-derived styling and returns a warning.
Packaging
The repository is arranged so that the root directory can be packaged directly. The build produces three bundles: dist/pdf-card-mcp-lite.mcpb and dist/pdf-card-mcp.mcpb declares server.type = "python" for compatibility with the MCP registry and the Smithery directory; the full bundle additionally installs the table-ml extra. They are executed via uv, so the host (or user) must provide uv. dist/pdf-card-mcp-desktop.mcpb declares server.type = "uv" (from manifest.uv.json). Claude Desktop manages Python and dependencies itself, so end users can double-click to install with no prerequisites.
No bundle includes ML model weights; unless offline=true is set and a warmed cache is used, gmft downloads and caches them locally on first use.
Privacy
By default, PDF processing happens locally. The deterministic converter does not upload document content or call external APIs. Optional OCR runs locally after the user installs the OCR dependencies. When style_engine=sampling or postprocess_engine=sampling is enabled through MCP, the host LLM may receive bounded style hints or card text fragments in order to return validated style tokens or a boundary operation plan. If no document-derived text should leave the local process, use the deterministic fixed / pdf styling and postprocess_engine=none.
Published readers may contain extracted PDF text, source page images, table/chart/formula crops, and any included public notes or highlights. Publish generated readers only when you have the right to share the source document content and annotations.
For a self-contained visual explanation of the conversion pipeline (including page rendering, table/chart cropping, overlap suppression, text card merging, and standalone HTML output), see docs/how-it-works.html.
Table handling approach
All detected tables are rendered as image cards. The converter uses pdfplumber to find table regions, and optionally uses gmft / Table Transformer for stronger local detection. It then uses pypdfium2 to rasterize only the source table regions to PNG. Titles are preserved as reader text and alt text, but the tables themselves remain as images so that layout and numeric alignment arepreserved after conversion.
If the document mentions a table but no reliable table region is found, the manifest will include a warning so the caller can decide whether to inspect the source page.
How formulas are handled
When a PDF exposes display formulas as centered, formula-like text blocks, display formulas are treated as image cards. The extracted formula string is retained for alt/search metadata, but the reader displays the source crop to keep subscripts, superscripts, arrows, and mathematical spacing faithful.
Current limitations
This is an early open-source implementation. It currently works for PDFs with a text layer, performing best-effort table detection via pdfplumber, lenient raster rendering via pypdfium2, and optionally richer local table detection via gmft. Scanned PDFs require optional OCR support.