Most PDF work a freelancer does is small: join three files into one, pull five pages out of a scan, turn a contract the right way up, put PAID across an invoice before it goes in the archive folder. None of that needs a desktop PDF editor, and none of it should mean uploading a client's invoice to a web tool you do not run. MCP PDF Tools does the job in the chat, on your machine, in pure JavaScript with no native dependency.
claude mcp add pdf -- npx -y @theluckystrike/mcp-pdf
Cursor's .cursor/mcp.json and Claude Desktop's claude_desktop_config.json take the
same block:
{
"mcpServers": {
"pdf": {
"command": "npx",
"args": ["-y", "@theluckystrike/mcp-pdf"]
}
}
}
Nothing is uploaded. The server reads and writes files where you point it and makes no network request of any kind, not even to check a licence key, which is verified offline.
pdf_merge joins files in the order given. pdf_split cuts a file into ranges, so
"1-3,5,7-" gives pages 1 to 3, page 5, and page 7 to the end. pdf_pages extracts a
specific set into a new file, and can repeat a page or reorder as it goes: "5,1,1" puts page 5
first and page 1 twice. pdf_rotate turns a sideways scan by a multiple of 90 degrees, added to
whatever rotation the page already carried. pdf_stamp draws text on the page, PAID and DRAFT as
presets in Free, any text, colour, position and size in Pro; a centred stamp goes on the 45-degree diagonal,
and it is drawn text, not a flattened image, so it can still be selected and searched afterward.
pdf_watermark_business reads the business name and VAT id that business_set in
mcp-invoice or mcp-docx already stored, and puts it in the footer of every page.
You: Stamp PAID on ~/invoices/INV-2026-0007.pdf and save a copy.
pdf_stamp {
path: "~/invoices/INV-2026-0007.pdf",
text: "PAID",
position: "center",
out_path: "~/invoices/INV-2026-0007-paid.pdf"
}
-> Stamped "PAID" on 1 page
-> ~/invoices/INV-2026-0007-paid.pdf, 0.9 MB
The original file is byte-for-byte unchanged; every tool that writes refuses an out_path
that already exists unless you pass overwrite: true, and reserves every output path before it
writes any of them, so a multi-file pdf_split that fails on part 3 does not leave parts 1 and
2 behind as a half-finished job.
A PDF does not store text the way a Word document does. It stores drawing operators that place glyphs on
a page, and what those glyphs mean depends on the font's own encoding table. pdf_text
decompresses each page's content stream and reads the operators that show text, with no external PDF
library and no OCR. For a PDF written by a normal word processor or invoicing tool, with a standard or fully
embedded font, that gives back clean, readable text.
It breaks in one specific and common case: a subset-embedded font. A PDF that embeds only the glyphs it
actually uses, which is most PDFs a modern tool produces, often renumbers those glyphs into a private table
that has nothing to do with any standard character set, and some fonts go further and encode by a raw
glyph index (CID) rather than by character at all. The bytes the content stream hands to
pdf_text in that case are glyph numbers, not letters: extracting them without decoding that
table gives back digits or symbols that look like text extraction succeeded but read as nonsense, which is
worse than an empty result because nothing about it looks like an error.
The server does not pretend this case is a success. It does not carry a font-encoding decoder, so instead of returning a string of glyph numbers as if it were the page's text, it checks whether what it extracted comes back as recognisable characters, and when it does not, the answer says so directly: the font's encoding is the reason, not a bug, and not a scan. A true scan, an image-only page with no text operators at all, gets a different message: the page is probably a scan, because there is no OCR here and there will not be one. Two different failure modes, two different reasons, in the answer, rather than one silent empty string that leaves you guessing which one happened.
There is no OCR, no form filling, no digital signatures, no redaction, and no PDF/A. Rotation is recorded as page metadata in multiples of 90 degrees; nothing is redrawn. Stamp text goes through a built-in font covering the WinAnsi character set, so characters outside it are dropped and counted in the response rather than silently failing the write. Files over 100 MB are refused, because rewriting a PDF needs several times its size in memory, and an encrypted file is refused by every writing tool with the fix named in the message: open it in a reader with the password and export a new, unencrypted copy.
Setup per client is on the setup pages. MCP PDF Tools has the
full tool table and the free-vs-Pro limits. Billable hours
and invoice PDFs are the two guides most people read next,
since mark_invoice_paid chains an invoice lookup straight into pdf_stamp.
The PDF's font uses a subset or CID encoding table this parser does not read, so the bytes in the content stream are glyph index numbers, not character codes. The answer names the font as the reason rather than returning the numbers as if they were text.
No, and it will not. An image-only page has no text operators to read at all, and pdf_text says the page is probably a scan instead of returning an empty string with no explanation.
No, 5 files is the free cap for pdf_merge. Files up to 30 pages are free for split, extract and rotate. Pro removes both limits.
No, it is drawn text through a built-in PDF font, so it can still be selected and searched in a reader afterward, unlike a stamp burned in as a picture.
Every tool that writes refuses it, with the reason and the fix in the message: open it in a reader with the password and export or print a new, unencrypted copy, then run the tool on that. pdf_info still reports encrypted: true, and pdf_count counts it as one unreadable file among the rest.