{"_id":"yaktool-pdf-mcp","_rev":"7-904603fb773f59e49d0965ac24e360d7","name":"yaktool-pdf-mcp","dist-tags":{"latest":"0.7.0"},"versions":{"0.1.0":{"name":"yaktool-pdf-mcp","version":"0.1.0","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools"],"author":{"name":"yaktool.com"},"license":"MIT","_id":"yaktool-pdf-mcp@0.1.0","maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"homepage":"https://yaktool.com/mcp","bin":{"yaktool-pdf-mcp":"dist/index.js"},"dist":{"shasum":"5f24a6ec9ba67ac1ce81b10090141d2ce2bf127e","tarball":"https://registry.npmjs.org/yaktool-pdf-mcp/-/yaktool-pdf-mcp-0.1.0.tgz","fileCount":4,"integrity":"sha512-zccCvBVirfz2X4cts/dG/h6cB53+uaWJ156IZnQtERxPYmsWo+QGMfZseBEt3YYYjR0WTGfVnwohVjfYpcla5A==","signatures":[{"sig":"MEUCIBlbC019Gzuok3pTg6YPwDZGZOG9nQuXMLRzbqaU4QWRAiEAhh110FVQtBUy28xoekunhLRpKbcieGuVtXfdTm0o2/g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2167456},"type":"module","engines":{"node":">=20"},"gitHead":"d55db9c5a344db1e52d41fbe5913aed24b009328","mcpName":"com.yaktool/pdf","scripts":{"test":"pnpm build && vitest run","build":"rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --banner:js='#!/usr/bin/env node'","typecheck":"tsc -p tsconfig.json","prepublishOnly":"pnpm build"},"_npmUser":{"name":"marginchan","email":"marginbaxi@gmail.com"},"_npmVersion":"11.11.0","description":"PDF organisation as an MCP server: merge and split with a structure diagnosis first (truncation, encryption, missing header as numbered findings), page-range language with real errors, outputs verified against an independent parser during development. Sam","directories":{},"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","vitest":"^3.0.0","esbuild":"^0.28.0","typescript":"^5.7.0","@yaktool/core":"workspace:*","@cantoo/pdf-lib":"^2.9.1","@modelcontextprotocol/sdk":"^1.17.0"},"_npmOperationalInternal":{"tmp":"tmp/yaktool-pdf-mcp_0.1.0_1787660311381_0.9001140101940039","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"yaktool-pdf-mcp","version":"0.2.0","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools","compress-pdf","shrink-pdf","mozjpeg"],"author":{"name":"yaktool.com"},"license":"MIT","_id":"yaktool-pdf-mcp@0.2.0","maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"homepage":"https://yaktool.com/mcp","bin":{"yaktool-pdf-mcp":"dist/index.js"},"dist":{"shasum":"500e7ab3efae64d4aeee1585df65013f9b9c5b5f","tarball":"https://registry.npmjs.org/yaktool-pdf-mcp/-/yaktool-pdf-mcp-0.2.0.tgz","fileCount":6,"integrity":"sha512-0Dhz+HODYrZTyvR+G4SqfexUHuGQvALurQgbQ028XXvXwTW5GlDxuiAErcl2VxArhqMp0HBHqA5ZbVzZ/LmYmA==","signatures":[{"sig":"MEUCIQD6PZMHlpF7I8soshpGWKcCPF2tkZ7qMc6MEpe934opxQIgMclCb+7j0dxRi34XrUnUDlWHB/ZMnY58MLYCVRQabwg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2724402},"type":"module","engines":{"node":">=20"},"gitHead":"c23eefb100f68b7de1772c520a674726aa9b0914","mcpName":"com.yaktool/pdf","scripts":{"test":"pnpm build && vitest run","build":"rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --loader:.wasm=file --asset-names=[name]-[hash] --banner:js='#!/usr/bin/env node'","typecheck":"tsc -p tsconfig.json","prepublishOnly":"pnpm build"},"_npmUser":{"name":"marginchan","email":"marginbaxi@gmail.com"},"_npmVersion":"11.11.0","description":"PDF organisation and compression as an MCP server: merge, split and shrink image-heavy PDFs with a structure diagnosis first (truncation, encryption, missing header as numbered findings), a page-range language with real errors, and a per-image compression","directories":{},"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","vitest":"^3.0.0","esbuild":"^0.28.0","typescript":"^5.7.0","@jsquash/jpeg":"^1.6.0","@yaktool/core":"workspace:*","@cantoo/pdf-lib":"^2.9.1","@modelcontextprotocol/sdk":"^1.17.0"},"_npmOperationalInternal":{"tmp":"tmp/yaktool-pdf-mcp_0.2.0_1787665437111_0.4817473494263378","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"yaktool-pdf-mcp","version":"0.4.0","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools","compress-pdf","shrink-pdf","mozjpeg","unlock-pdf","decrypt-pdf","organize-pdf","rotate-pdf","reorder-pdf-pages"],"author":{"name":"yaktool.com"},"license":"MIT","_id":"yaktool-pdf-mcp@0.4.0","maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"homepage":"https://yaktool.com/mcp","bin":{"yaktool-pdf-mcp":"dist/index.js"},"dist":{"shasum":"561bcb303a3b337610154399248e3ae7cee10271","tarball":"https://registry.npmjs.org/yaktool-pdf-mcp/-/yaktool-pdf-mcp-0.4.0.tgz","fileCount":6,"integrity":"sha512-dumb1A4cBe4hcSte0XhPA9epl/94zr2tTgl5nzzXDqj0ZztyswyuatrzmkPqs5WbcKy7MLQdUw4YAaypRT7/Rw==","signatures":[{"sig":"MEUCIBi0u8m5vPToao/8ZmumItHxKtLQaA8izEAHxIH8hOk1AiEAkTc5f+SRFs6J4oIUBwbKzkvHyUAa/itWKAFVG8TW2ws=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2740046},"type":"module","engines":{"node":">=20"},"gitHead":"2deef7241a446992f8fd3e7ff0c68b7c2960a98d","mcpName":"com.yaktool/pdf","scripts":{"test":"pnpm build && vitest run","build":"rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --loader:.wasm=file --asset-names=[name]-[hash] --banner:js='#!/usr/bin/env node'","typecheck":"tsc -p tsconfig.json","prepublishOnly":"pnpm build"},"_npmUser":{"name":"marginchan","email":"marginbaxi@gmail.com"},"_npmVersion":"11.11.0","description":"PDF organisation as an MCP server: merge, split, compress image-heavy files, unlock password-protected ones with the password you supply, and rewrite the page order with relative rotation that does not un-rotate scans. Structure diagnosis first, numbered ","directories":{},"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","vitest":"^3.0.0","esbuild":"^0.28.0","typescript":"^5.7.0","@jsquash/jpeg":"^1.6.0","@yaktool/core":"workspace:*","@cantoo/pdf-lib":"^2.9.1","@modelcontextprotocol/sdk":"^1.17.0"},"_npmOperationalInternal":{"tmp":"tmp/yaktool-pdf-mcp_0.4.0_1787669052444_0.4200772135046822","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"yaktool-pdf-mcp","version":"0.4.1","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools","compress-pdf","shrink-pdf","mozjpeg","unlock-pdf","decrypt-pdf","organize-pdf","rotate-pdf","reorder-pdf-pages"],"author":{"name":"yaktool.com"},"license":"MIT","_id":"yaktool-pdf-mcp@0.4.1","maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"homepage":"https://yaktool.com/mcp","bin":{"yaktool-pdf-mcp":"dist/index.js"},"dist":{"shasum":"347432f2c4681fb7d3a59b6c4dadc23515cb61f1","tarball":"https://registry.npmjs.org/yaktool-pdf-mcp/-/yaktool-pdf-mcp-0.4.1.tgz","fileCount":6,"integrity":"sha512-B72SfBndo6Dlaxq2m0OQU72PQ/Y615NHyjDwmg1dbfWRvYtTJ3bNPaqcI/8wWBre/Sqy3AzAQfUHF/QmEeynCw==","signatures":[{"sig":"MEYCIQCUMPErhv7wCk8/1YhuexMMEv3Ata8qYuHh4Rj5eAUcAgIhAIsJwOvcZoE0tRT1PAi+ITfBeir6MdQtQ4IFPH6qyWle","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2740046},"type":"module","engines":{"node":">=20"},"gitHead":"f4fcf7a26d67c49222e1c57e372cced9346922dd","mcpName":"com.yaktool/pdf","scripts":{"test":"pnpm build && vitest run","build":"rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --loader:.wasm=file --asset-names=[name]-[hash] --banner:js='#!/usr/bin/env node'","typecheck":"tsc -p tsconfig.json","prepublishOnly":"pnpm build"},"_npmUser":{"name":"marginchan","email":"marginbaxi@gmail.com"},"_npmVersion":"11.11.0","description":"PDF organisation as an MCP server: merge, split, compress image-heavy files, unlock password-protected ones with the password you supply, and rewrite the page order with relative rotation that does not un-rotate scans. Structure diagnosis first, numbered ","directories":{},"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","vitest":"^3.0.0","esbuild":"^0.28.0","typescript":"^5.7.0","@jsquash/jpeg":"^1.6.0","@yaktool/core":"workspace:*","@cantoo/pdf-lib":"^2.9.1","@modelcontextprotocol/sdk":"^1.17.0"},"_npmOperationalInternal":{"tmp":"tmp/yaktool-pdf-mcp_0.4.1_1787716922210_0.6291856407503669","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"yaktool-pdf-mcp","version":"0.5.0","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools","compress-pdf","shrink-pdf","mozjpeg","unlock-pdf","decrypt-pdf","organize-pdf","rotate-pdf","reorder-pdf-pages"],"author":{"name":"yaktool.com"},"license":"MIT","_id":"yaktool-pdf-mcp@0.5.0","maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"homepage":"https://yaktool.com/mcp","bin":{"yaktool-pdf-mcp":"dist/index.js"},"dist":{"shasum":"76dacd6975b7c63fefe41c410098b269f47fb156","tarball":"https://registry.npmjs.org/yaktool-pdf-mcp/-/yaktool-pdf-mcp-0.5.0.tgz","fileCount":6,"integrity":"sha512-f9a16cy24Tt6kCwA2KEXRBhuoASDcrH5PVUO9yHmo7NSoTpQ9mZZBnjwFNM3hiAd5JSdoYblbav+uKRsf00m4g==","signatures":[{"sig":"MEYCIQCmSnMYMs42Z3jHte3Qqu9qHbaktRvly95L3o8nKKXysQIhAImAbrsOfoouDPmtyHdfLkAG09oXRsB3ahpnE1Fjzo0E","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2757629},"type":"module","engines":{"node":">=20"},"gitHead":"6828672bf383c3c5c95f8fb9687771924c71e16d","mcpName":"com.yaktool/pdf","scripts":{"test":"pnpm build && vitest run","build":"rm -rf dist && esbuild src/index.ts --bundle --external:pdfjs-dist --platform=node --format=esm --outfile=dist/index.js --loader:.wasm=file --asset-names=[name]-[hash] --banner:js='#!/usr/bin/env node'","typecheck":"tsc -p tsconfig.json","prepublishOnly":"pnpm build"},"_npmUser":{"name":"marginchan","email":"marginbaxi@gmail.com"},"_npmVersion":"11.11.0","description":"PDF organisation as an MCP server: merge, split, compress image-heavy files, unlock password-protected ones with the password you supply, rewrite the page order with relative rotation, and check whether a redacted PDF actually removed the text — recoverab","directories":{},"_nodeVersion":"24.14.1","dependencies":{"pdfjs-dist":"^6.2.108"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","vitest":"^3.0.0","esbuild":"^0.28.0","typescript":"^5.7.0","@jsquash/jpeg":"^1.6.0","@yaktool/core":"workspace:*","@cantoo/pdf-lib":"^2.9.1","@modelcontextprotocol/sdk":"^1.17.0"},"_npmOperationalInternal":{"tmp":"tmp/yaktool-pdf-mcp_0.5.0_1787742828397_0.4951442558861623","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"yaktool-pdf-mcp","version":"0.6.0","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools","compress-pdf","shrink-pdf","mozjpeg","unlock-pdf","decrypt-pdf","organize-pdf","rotate-pdf","reorder-pdf-pages"],"author":{"name":"yaktool.com"},"license":"MIT","_id":"yaktool-pdf-mcp@0.6.0","maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"homepage":"https://yaktool.com/mcp","bin":{"yaktool-pdf-mcp":"dist/index.js"},"dist":{"shasum":"65a2f17ab3fbd91b26dd3fbb78935968ae0ae607","tarball":"https://registry.npmjs.org/yaktool-pdf-mcp/-/yaktool-pdf-mcp-0.6.0.tgz","fileCount":6,"integrity":"sha512-Ao+g+9WpNPC1ENi/pFQehOWaEXAKZDMACCb2RTsND6omu/qhQq4jPPD1OkLap/PRBGTUgJbYUDsBy2/AImB7nQ==","signatures":[{"sig":"MEYCIQD89iCl4oSkE5OQat2iLQdeN0mBEGaNHEtHwDQ+tiWV0wIhAO4WLmu3P4AUyCK9xRGlVJZJWPWhGEvdFeNHSBbVBXiY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3580188},"type":"module","engines":{"node":">=20"},"gitHead":"dd38ccb05fb95be6bb90598ce686f5b7a15ae2b7","mcpName":"com.yaktool/pdf","scripts":{"test":"pnpm build && vitest run","build":"rm -rf dist && esbuild src/index.ts --bundle --external:pdfjs-dist --platform=node --format=esm --outfile=dist/index.js --loader:.wasm=file --asset-names=[name]-[hash] --banner:js='#!/usr/bin/env node'","typecheck":"tsc -p tsconfig.json","prepublishOnly":"pnpm build"},"_npmUser":{"name":"marginchan","email":"marginbaxi@gmail.com"},"_npmVersion":"11.11.0","description":"PDF organisation as an MCP server: merge, split, compress image-heavy files, unlock password-protected ones with the password you supply, rewrite the page order with relative rotation, and check whether a redacted PDF actually removed the text — recoverab","directories":{},"_nodeVersion":"24.14.1","dependencies":{"pdfjs-dist":"^6.2.108"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","vitest":"^3.0.0","esbuild":"^0.28.0","typescript":"^5.7.0","@jsquash/jpeg":"^1.6.0","@yaktool/core":"workspace:*","@cantoo/pdf-lib":"^2.9.1","@modelcontextprotocol/sdk":"^1.17.0"},"_npmOperationalInternal":{"tmp":"tmp/yaktool-pdf-mcp_0.6.0_1788252682471_0.5522391950786474","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"yaktool-pdf-mcp","version":"0.7.0","mcpName":"com.yaktool/pdf","description":"PDF work as an MCP server: merge with the bookmarks preserved, split, compress image-heavy files, unlock password-protected ones with the password you supply, rewrite the page order with relative rotation, read the text layer, extract embedded files and c","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools","compress-pdf","shrink-pdf","mozjpeg","unlock-pdf","decrypt-pdf","organize-pdf","rotate-pdf","reorder-pdf-pages"],"homepage":"https://yaktool.com/mcp","license":"MIT","author":{"name":"yaktool.com"},"type":"module","engines":{"node":">=20"},"bin":{"yaktool-pdf-mcp":"dist/index.js"},"scripts":{"build":"rm -rf dist && esbuild src/index.ts --bundle --external:pdfjs-dist --platform=node --format=esm --outfile=dist/index.js --loader:.wasm=file --asset-names=[name]-[hash] --banner:js='#!/usr/bin/env node'","test":"pnpm build && vitest run","typecheck":"tsc -p tsconfig.json","prepublishOnly":"pnpm build"},"devDependencies":{"@cantoo/pdf-lib":"^2.9.1","@jsquash/jpeg":"^1.6.0","@modelcontextprotocol/sdk":"^1.17.0","@yaktool/core":"workspace:*","esbuild":"^0.28.0","typescript":"^5.7.0","vitest":"^3.0.0","zod":"^3.24.0"},"dependencies":{"pdfjs-dist":"^6.2.108"},"gitHead":"3d45a549837b733464b6b3ac3f3ebb928c6dbf6a","_id":"yaktool-pdf-mcp@0.7.0","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-VgKcdID46uHQlzVvNDEQFSL68i+XdYsPuU//vk/24PwQusQJXPKKmftp96D1OV4ZJJm6yl06uPRl6vGhKSO+Jg==","shasum":"82102436416ef18d6ac8c2e692a68b34736e6bfe","tarball":"https://registry.npmjs.org/yaktool-pdf-mcp/-/yaktool-pdf-mcp-0.7.0.tgz","fileCount":6,"unpackedSize":3599521,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCSNzlY0W4qC151znaNcEQ7eHN6RPM3VGp7Y6kMyJWVWgIgZWboVbK5ERhk4267CQLupvZ/RCZcvJg8oFOZkB57cuM="}]},"_npmUser":{"name":"marginchan","email":"marginbaxi@gmail.com"},"directories":{},"maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/yaktool-pdf-mcp_0.7.0_1788256529038_0.2075214659753899"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-25T12:18:31.304Z","modified":"2026-09-01T09:55:29.387Z","0.1.0":"2026-08-25T12:18:31.554Z","0.2.0":"2026-08-25T13:43:57.306Z","0.4.0":"2026-08-25T14:44:12.602Z","0.4.1":"2026-08-26T04:02:02.444Z","0.5.0":"2026-08-26T11:13:48.539Z","0.6.0":"2026-09-01T08:51:22.649Z","0.7.0":"2026-09-01T09:55:29.207Z"},"author":{"name":"yaktool.com"},"license":"MIT","homepage":"https://yaktool.com/mcp","keywords":["mcp","model-context-protocol","mcp-server","pdf","merge-pdf","split-pdf","extract-pages","pdf-diagnosis","agent-tools","compress-pdf","shrink-pdf","mozjpeg","unlock-pdf","decrypt-pdf","organize-pdf","rotate-pdf","reorder-pdf-pages"],"description":"PDF work as an MCP server: merge with the bookmarks preserved, split, compress image-heavy files, unlock password-protected ones with the password you supply, rewrite the page order with relative rotation, read the text layer, extract embedded files and c","maintainers":[{"name":"marginchan","email":"marginbaxi@gmail.com"}],"readme":"# yaktool-pdf-mcp\n\nPDF organisation as an MCP server — the PDF-domain suite of [yaktool.com](https://yaktool.com/mcp).\n\nEvery tool **diagnoses the file first** (missing header, truncation, encryption, damaged\ncross-reference — as numbered PDFI-* findings), never overwrites an existing output, and\ndoes no network I/O.\n\n## Tools\n\n- **`merge_pdfs`** — merge PDF files in order. Bad files are skipped **with their diagnosis\n  attached** and the merge continues. Nothing is ever silently dropped. **Bookmarks come with\n  it**: each source's outline is remapped onto the pages' new positions and nested under one\n  entry per source file, and any bookmark whose destination cannot be resolved is reported by\n  name rather than quietly lost.\n- **`split_pdf`** — extract pages with a real range language (`1-3,5,9-`, `-4`, `last`)\n  whose errors name the actual problem (backwards range with a swap suggestion,\n  out-of-bounds with the document's true page count). One output file, or one per page.\n- **`organize_pdf`** — rewrite the page sequence: reorder, delete, duplicate and rotate in\n  one pass. **Rotation is relative to how the page currently displays** — a scan stored at\n  `/Rotate 270` turned by 90 comes out at 0, not 90, so pre-rotated scans are not silently\n  un-rotated. A page that does not exist, or an angle that is not a quarter turn, refuses\n  the whole plan rather than quietly dropping a page.\n- **`compress_pdf`** — shrink image-heavy and scanned PDFs by re-encoding their bitmaps\n  (JPEG and Flate). Reports every image's before/after size, resolution and PSNR, and\n  **never fakes a saving**: an image that would grow keeps its original bytes, and a file\n  that cannot be improved comes back untouched instead of re-saved.\n- **`unlock_pdf`** — remove a password **using the password the user supplies**. It does\n  not crack, guess or bypass anything: a permissions (\"owner\") password needs the password\n  too, unlike sites that silently strip it. The output is a genuinely clean, unencrypted\n  PDF the other tools here accept.\n- **`check_pdf_redaction`** — check whether a \"redacted\" PDF actually removed the text or\n  just covered it. Dark rectangles over extractable text are caught and the covered words\n  come back **verbatim** in `recovered[]`; also flags unapplied `/Redact` annotations,\n  annotation text, document metadata, incremental-save history, attachments and bookmark\n  titles. Honest about scanned pages: the text layer is judged, pixels are out of scope.\n  Published thresholds (dark = grey ≤ 0.25, covered = ≥ 60% of the word box).\n- **`extract_pdf_text`** — read the text layer out, reflowed into reading order. The part\n  worth calling it for: it says when the text cannot be trusted. Pages with **no text layer**\n  come back named (they are scans, and an empty string reads as \"blank page\"); a text layer\n  that decodes to **unmapped codepoints** is flagged instead of handed over as prose; and a\n  `maxChars` budget reports exactly what it dropped. Deliberately no table reconstruction and\n  no layout analysis — for those, a dedicated extraction server does more.\n- **`extract_pdf_attachments`** — list every file embedded in a PDF, and when it is a\n  Factur-X / ZUGFeRD hybrid invoice, check the **container**: prescribed filename, the\n  `/AFRelationship` value (`Alternative`, or `Source` in the case ZUGFeRD 2.1 names), and\n  registration in **both** `/AF` and `/EmbeddedFiles` — get those wrong and the XML is present\n  but unreachable. Then the invoice itself goes through the Article 226 engine, with totals\n  **computed per VAT rate** rather than copied from the file. The CII reader takes a bounded\n  set of paths and reports what it could not read rather than guessing.\n- **`check_pdf_form`** — list every AcroForm field (type, value, options, required, read-only,\n  MaxLen) and judge whether the form would come back rejected: a required field left empty, a\n  value outside the field's options, a value past MaxLen, and **fields that share a name** —\n  those are one field with several widgets, so typing in one changes the others. Pass `fill` to\n  check a planned fill **before** touching the file.\n- **`fill_pdf_form`** — write values and save to a new file, never overwriting. It **checks\n  before it writes** and refuses on an error, and it **regenerates the field appearances** —\n  the step that separates a filled form from a file that merely contains values, because\n  without it many readers and most printers show empty boxes. Signature fields are left alone.\n- **`images_to_pdf`** — build a PDF from JPEG and PNG files, one image per page, with the\n  layout decisions **stated rather than applied silently**: enlarging is off by default (it adds\n  pixels, not detail), `cover` reports how much it crops, and with a fixed paper size the\n  effective print resolution is computed and flagged below 150 DPI. Formats a PDF cannot carry\n  are refused by name instead of being converted behind your back.\n- **`check_pdf_hidden_content`** — show what a recipient can still recover. The headline is\n  **cropping**: it deletes nothing, and — this is the part that makes it dangerous — every\n  reader and text extractor clips to the crop box, so `extract_pdf_text` on a cropped file\n  returns the visible text and silently omits the rest. This tool re-opens the document with\n  each crop box pushed back out to the media box and reports the text outside the original crop\n  **verbatim**, not as a count of hidden objects. Also: layers that are off by default (by\n  name), document properties as values with local file paths flagged, incremental-save rounds,\n  and embedded files. Text layer only — images outside the crop are equally recoverable and are\n  reported as out of scope rather than passed off as \"nothing hidden\".\n\n## Install\n\n```bash\nclaude mcp add yaktool-pdf -- npx -y yaktool-pdf-mcp\n```\n\nSame engine as the browser tools at\n[yaktool.com/documents/pdf-merge](https://yaktool.com/documents/pdf-merge/).\n","readmeFilename":"README.md"}