{
  "markdown": "# PDF Card MCP\n\n<!-- mcp-name: io.github.velyan/pdf-card-mcp -->\n\n[![CI](https://github.com/velyan/pdf-card-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/velyan/pdf-card-mcp/actions/workflows/ci.yml)\n[![Source Install](https://img.shields.io/badge/package-source%20install-blue.svg)](#install)\n[![Python 3.11-3.13](https://img.shields.io/badge/python-3.11--3.13-blue.svg)](pyproject.toml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![MCP Registry](https://img.shields.io/badge/MCP-registry-blue)](https://registry.modelcontextprotocol.io)\n\nPDF Card MCP is a local-first MCP server and CLI for turning dense local PDFs into\nportable, source-linked HTML readers. An MCP host can ask it to convert a PDF path, validate\nnotes/highlights, or publish a static annotated reader bundle. The converter preserves source\ntext, renders source pages for verification, crops detected tables, figures, and display\nformulas as images, derives safe reader styling from the original PDF palette, and writes a\nstandalone HTML file that can be moved across devices without losing assets.\n\nDefault conversion runs locally and does not require a hosted service. Optional MCP sampling\nis deliberately bounded: the host model may choose validated style tokens or suggest\ncard-boundary polish operations, but raw CSS and source-text rewrites are rejected.\n\nThe default reader is designed for comfortable reading: large type, small cards, search,\nsection navigation, next/previous controls, keyboard navigation, a font-size slider, and\nsource-page previews.\n\nPDF Card MCP is meant for PDFs you actually need to read, cite, or inspect. It turns long\ndocuments into smaller source-linked cards, keeps tables/figures/formulas as faithful image\ncrops, and lets you export your own notes and highlights as Markdown.\n\n## Quick Install (one-click)\n\nPDF Card MCP is a Python server, so it needs a runtime. The one thing to install first is\n[`uv`](https://docs.astral.sh/uv/) — it manages Python for you, so you do not have to. This is\nthe only prerequisite for every install path below:\n\n```bash\n# macOS / Linux\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n```\n\n```powershell\n# Windows (PowerShell)\npowershell -ExecutionPolicy ByPass -c \"irm https://astral.sh/uv/install.ps1 | iex\"\n```\n\nThen add the server with one click. The buttons run the published\n[`pdf-card-mcp`](https://pypi.org/project/pdf-card-mcp/) package through `uv`:\n\n[![Add to Cursor](https://img.shields.io/badge/Add_to_Cursor-black?style=for-the-badge&logo=cursor&logoColor=white)](cursor://anysphere.cursor-deeplink/mcp/install?name=pdf-card&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJwZGYtY2FyZC1tY3AiLCJwZGYtY2FyZC1tY3Atc2VydmVyIl19)\n[![Add to VS Code](https://img.shields.io/badge/Add_to_VS_Code-007ACC?style=for-the-badge&logo=visual-studio-code&logoColor=white)](vscode:mcp/install?%7B%22name%22%3A%22pdf-card%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22pdf-card-mcp%22%2C%22pdf-card-mcp-server%22%5D%7D)\n\n**Claude Code** (terminal):\n\n```bash\nclaude mcp add pdf-card -- uvx --from pdf-card-mcp pdf-card-mcp-server\n```\n\n**Claude Desktop** (no terminal, no prerequisites): download `pdf-card-mcp-desktop.mcpb` from the\n[latest release](https://github.com/velyan/pdf-card-mcp/releases/latest) and double-click it to\ninstall as an extension. This bundle declares the `uv` runtime, so Claude Desktop installs Python\nand dependencies for you — you do not need the `uv` step above for this path.\n\nAfter installing, restart (or reload MCP servers in) your client so it picks up the new server.\n\n## Real Screenshots\n\nThese screenshots are from a generated reader for *Agents in Software Engineering* and the\nsame source PDF opened side by side for comparison.\n\n| Generated reader | Original PDF |\n| --- | --- |\n| <img src=\"https://raw.githubusercontent.com/velyan/pdf-card-mcp/main/docs/assets/reader-annotations-real.png\" alt=\"Generated PDF Card MCP reader showing annotations, highlighted text, typed notes, source buttons, and section navigation\" width=\"100%\"> | <img src=\"https://raw.githubusercontent.com/velyan/pdf-card-mcp/main/docs/assets/source-pdf-page-1-real.png\" alt=\"Original PDF page 1 in Preview for source comparison\" width=\"100%\"> |\n| <img src=\"https://raw.githubusercontent.com/velyan/pdf-card-mcp/main/docs/assets/reader-figure-real.png\" alt=\"Generated PDF Card MCP reader showing a preserved figure card and document navigation\" width=\"100%\"> | <img src=\"https://raw.githubusercontent.com/velyan/pdf-card-mcp/main/docs/assets/source-pdf-page-4-real.png\" alt=\"Original PDF page in Preview showing the same figure and surrounding paper text\" width=\"100%\"> |\n\n## Quick Examples\n\nConvert a local PDF into one portable HTML reader:\n\n```bash\npdf-card-mcp ./paper.pdf --output ./out/paper-reader.html\n```\n\nUse the explicit subcommand form with PDF-derived styling:\n\n```bash\npdf-card-mcp convert ./paper.pdf \\\n  --output ./out/paper-reader.html \\\n  --style-engine pdf\n```\n\nRun the MCP server so a compatible host can generate readers from local PDF paths:\n\n```bash\npython -m pdf_card_mcp.server\n```\n\nPublish a read-only static reader with selected public annotations:\n\n```bash\npdf-card-mcp publish ./out/paper-reader.html \\\n  --annotations ./paper.annotations.json \\\n  --output ./published/paper-reader.html\n```\n\n## Output At A Glance\n\n| Output | What it contains |\n| --- | --- |\n| `paper-reader.html` | Standalone reader with embedded CSS, JavaScript, page images, and detected crops. |\n| `paper.manifest.json` | Structured metadata for cards, pages, warnings, and source anchors. |\n| Markdown export | User-authored notes and highlights from the reader UI. |\n| Published bundle | Read-only static HTML or a directory bundle for sharing public annotations. |\n\n## Status\n\nThis is an early open-source implementation. It is useful for text-layer PDFs now, with\nbest-effort table detection via `pdfplumber`, permissive raster rendering via `pypdfium2`,\nand optional richer local table detection via `gmft`. Scanned PDFs need optional OCR support.\n\n## Install\n\nMost people should use the [one-click install](#quick-install-one-click) above. To install the\npackage directly instead, from PyPI:\n\n```bash\npython -m pip install pdf-card-mcp\n```\n\nOr install the latest unreleased changes directly from the repository:\n\n```bash\npython -m pip install \"pdf-card-mcp @ git+https://github.com/velyan/pdf-card-mcp.git\"\n```\n\nFor local development:\n\n```bash\ngit clone https://github.com/velyan/pdf-card-mcp.git\ncd pdf-card-mcp\npython3 -m venv .venv\n. .venv/bin/activate\npython3 -m pip install -e \".[dev]\"\n```\n\n`uv` is recommended for MCPB packaging:\n\n```bash\nuv sync\nuv run pdf-card-mcp path/to/document.pdf --output out/document.html\n```\n\nInstall the optional local ML table detector when you want stronger table crops:\n\n```bash\nuv sync --extra table-ml\nuv run --extra table-ml pdf-card-mcp path/to/document.pdf --table-engine gmft\n```\n\n## Use In An MCP Client\n\nAdd it to Claude Code or another CLI-compatible MCP client with `uvx` (requires\n[`uv`](https://docs.astral.sh/uv/)):\n\n```bash\nclaude mcp add pdf-card -- uvx --from pdf-card-mcp pdf-card-mcp-server\n```\n\nGeneric MCP host configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"pdf-card\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"pdf-card-mcp\", \"pdf-card-mcp-server\"]\n    }\n  }\n}\n```\n\nFor local development before the PyPI release, point the client at this checkout:\n\n```json\n{\n  \"mcpServers\": {\n    \"pdf-card-local\": {\n      \"command\": \"uv\",\n      \"args\": [\n        \"--directory\",\n        \"/path/to/pdf-card-mcp\",\n        \"run\",\n        \"python\",\n        \"-m\",\n        \"pdf_card_mcp.server\"\n      ]\n    }\n  }\n}\n```\n\nClaude Desktop can also install the `.mcpb` bundle from the latest GitHub release.\n\n### Docker / Registry Scanners\n\nThe repository includes a minimal `Dockerfile` so registries such as Glama can build the\nserver, start it over stdio, and inspect its MCP tool schemas. The server still works on local\nfile paths, so container users must mount any PDFs and output directories they want the tool to\nread or write:\n\n```bash\ndocker build -t pdf-card-mcp .\ndocker run --rm -i \\\n  -v \"$PWD/examples:/docs\" \\\n  pdf-card-mcp\n```\n\n## CLI Usage\n\n```bash\npdf-card-mcp path/to/document.pdf --output examples/out/document.html\n```\n\nThe command writes:\n\n- `document.html`: standalone reader with embedded CSS, JavaScript, table crops, figure crops,\n  formula crops, and source-page images.\n- `document.manifest.json`: structured metadata without embedded image payloads.\n\nThe explicit subcommand form is also supported:\n\n```bash\npdf-card-mcp convert path/to/document.pdf --output examples/out/document.html\n```\n\n## Notes, Highlights, And Static Publishing\n\nGenerated readers include a local annotation overlay:\n\n- A highlight is selected source text.\n- A note is selected source text plus your own typed note text.\n\nSelect text in a text card, choose `Highlight` or `Note`, and use `Export Markdown` to download\na readable `.annotations.md` file. Import is intentionally not exposed in the reader UI yet.\nNotes and highlights are user-authored data and are kept separate from the source-derived\n`document.manifest.json`.\n\nThe lower-level CLI and MCP publishing tools still accept a structured annotation bundle when\nyou need to build a read-only static reader with embedded annotations. Validate that bundle\nagainst a reader:\n\n```bash\npdf-card-mcp validate-annotations examples/out/document.html document.annotations.json\n```\n\nPublish a shareable static reader with public annotations:\n\n```bash\npdf-card-mcp publish examples/out/document.html \\\n  --annotations document.annotations.json \\\n  --output published/document-reader.html\n```\n\nIf `--output` is a directory instead of an `.html` file, the command writes a static bundle:\n\n- `index.html`\n- `reader.manifest.json`\n- `reader.annotations.json`\n- `bundle.json`\n\nPublishing includes only `visibility: public` annotations by default, redacts the local\n`source_pdf` path by default, and renders the published reader read-only by default. Use\n`--include-private` only when you intentionally want private local notes included in the\npublished output. Publishing fails if any included annotation cannot be anchored to the reader;\nrun `validate-annotations` to inspect mismatches before publishing.\n\n## MCP Tool\n\nThe MCP server is the automation layer around the same local converter. It accepts local\nfile paths from an MCP client and returns generated reader paths, manifest metadata,\nwarnings, and publishing/validation results.\n\nThe server exposes three tools:\n\n```text\nconvert_pdf_to_card_html\nvalidate_reader_annotations\npublish_reader_bundle\n```\n\nInputs:\n\n- `pdf_path`: local PDF path.\n- `output_path`: optional HTML output path.\n- `title`: optional title override.\n- `standalone`: defaults to `true`; asset-folder output is reserved for a later release.\n- `ocr`: optional OCR fallback if `pytesseract` is installed.\n- `max_pages`: optional processing limit.\n- `theme`: defaults to `soft`.\n- `style_engine`: `fixed`, `pdf`, or `sampling`; defaults to `pdf`. `fixed` preserves the\n  original soft palette, `pdf` derives bounded colors and typography hints locally from the\n  source PDF, and `sampling` asks the host LLM to choose validated style tokens from those\n  local hints.\n- `table_engine`: `auto`, `pdfplumber`, or `gmft`; `auto` uses `gmft` when installed.\n- `text_engine`: `char_geometry` or `pdfplumber_words`; defaults to `char_geometry` so\n  missing spaces are repaired from PDF character positions instead of trusting fused words.\n- `postprocess_engine`: `none` or `sampling`; defaults to `none`. When set to `sampling`,\n  the MCP server asks the host LLM for boundary-only card polish operations, validates exact\n  source-text preservation, and rewrites the generated reader. If the MCP client does not\n  support sampling, deterministic output is returned with a warning.\n- `model_cache_dir`: optional cache directory for local ML table model weights.\n- `offline`: use only already-cached optional ML models.\n\n`validate_reader_annotations` checks a notes/highlights sidecar against a generated reader.\n`publish_reader_bundle` writes a publish-ready static HTML file or directory bundle from an\nexisting generated reader and an optional annotation sidecar.\n\nSampling post-processing is intentionally narrow. For card boundaries, the host LLM may\nsuggest merges, heading extraction, or front-matter/footnote classification, but Python\nvalidation rejects any operation that rewrites, deletes, invents, or reorders source text.\nFor `style_engine=sampling`, the host LLM may only choose bounded style tokens and palette\ncandidate IDs; it cannot return raw CSS, JavaScript, or arbitrary colors. If sampling is\nunavailable, the reader keeps deterministic PDF-derived styling and returns a warning.\n\nRun the server locally:\n\n```bash\npython -m pdf_card_mcp.server\n```\n\n## MCPB Packaging\n\nThis repo is arranged so the root can be packed directly:\n\n```bash\npython scripts/build_mcpb.py --variant all\n```\n\nThis builds three bundles:\n\n- `dist/pdf-card-mcp-lite.mcpb` and `dist/pdf-card-mcp.mcpb` declare `server.type = \"python\"`\n  for MCP registry and Smithery directory compatibility. The full bundle additionally installs the\n  `table-ml` extra. These execute through `uv`, so the host (or user) must provide `uv`.\n- `dist/pdf-card-mcp-desktop.mcpb` declares `server.type = \"uv\"` (from `manifest.uv.json`). Claude\n  Desktop manages Python and dependencies itself, so end users can double-click to install with no\n  prerequisites. This is the bundle linked from the one-click install section above.\n\nNo bundle vendors ML model weights; `gmft` downloads and caches them locally on first use unless\n`offline=true` is set with a prewarmed cache.\n\n## Privacy\n\nDefault PDF processing is local. The deterministic converter does not upload document contents\nor call external APIs. Optional OCR runs locally when the user has installed OCR dependencies.\n\nWhen `style_engine=sampling` or `postprocess_engine=sampling` is enabled through MCP, the host\nLLM may receive bounded style hints or card text snippets so it can return validated style-token\nor boundary-operation plans. Use deterministic `fixed`/`pdf` style and `postprocess_engine=none`\nwhen no document-derived text should leave the local process.\n\nPublished readers may contain extracted PDF text, source-page images, table/figure/formula crops,\nand any included public notes or highlights. Only publish generated readers when you have the\nrights to share the source document content and your annotations.\n\n## How It Works\n\nSee [`docs/how-it-works.html`](docs/how-it-works.html) for a self-contained visual explainer\nof the conversion pipeline, including page rendering, table/figure crops, overlap suppression,\ntext-card merging, and standalone HTML output.\n\n## How Tables Are Handled\n\nAll detected tables are rendered as image cards. The converter uses `pdfplumber` to find table\nregions and can optionally use `gmft`/Table Transformer for stronger local detection. It then\nuses `pypdfium2` to rasterize only the source table region into PNG. Captions are preserved as\nreader text and alt text, but the table itself remains an image so layout and numeric alignment\nsurvive conversion.\n\nIf a document mentions tables but no reliable table regions are found, the manifest includes a\nwarning so callers can decide whether to inspect the source pages.\n\n## How Formulas Are Handled\n\nDisplay formulas are treated as image cards when the PDF exposes them as centered, formula-like\ntext blocks. The extracted formula string is retained for alt/search metadata, but the reader\nshows the source crop so subscripts, superscripts, arrows, and math spacing remain faithful.\n\n## License\n\nMIT\n",
  "bytes": 15765,
  "sha": "c93ffe439adb5e157b9aabd9c287b759a91dd100444db700f1847710c56f742b",
  "repo_slug": "velyan/pdf-card-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_velyan_pdf_card_mcp_ece151f6/readme"
}