Labsco
Nizoka logo

pdfnative

โ˜… 1

from Nizoka

Local-first PDF engine for AI agents. Zero-dep TypeScript, PDF/A, signatures, 800+ pages/sec.

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅโœ“ VerifiedFreeNeeds API keys

pdfnative-mcp

Model Context Protocol (MCP) server that bridges the pdfnative library โ€” a zero-dependency, ISO 32000-1 compliant PDF engine โ€” to any MCP-compatible AI client (Claude Desktop, Cursor, Continue, ChatGPT, Zed, โ€ฆ).

npm downloads

OpenSSF Scorecard


โœจ Features

pdfnative-mcp exposes 19 production-grade tools to any MCP host:

ToolPurpose
generate_basic_pdfMulti-page A4 documents from structured blocks (headings, paragraphs, lists, page breaks). Embedded newlines auto-split into paragraphs. Optional pdfA.
add_barcodeQR Code, Code 128, EAN-13, Data Matrix, PDF417 โ€” embedded in a single-page PDF.
add_international_text24 scripts (incl. Latin & COLRv1 colour emoji) with BiDi & OpenType shaping; multi-lang per document.
add_tableTabular reports with smart fields (wrap, repeatHeader, zebra, caption, minRowHeight, cellPadding).
add_formInteractive AcroForm PDFs with text fields, checkboxes, radio buttons, dropdowns.
embed_imageEmbed a JPEG or PNG image (base64) into a titled PDF document.
prepare_signature_placeholderStep 1 of the two-step sign workflow โ€” create a PDF with a /Sig AcroForm placeholder.
sign_pdfApply a PAdES-compatible CMS signature (RSA-SHA256 / ECDSA-SHA256 P-256). Auto-injects a placeholder when needed.
verify_pdfVerify every PAdES signature in a PDF (integrity + signature value + optional chain trust).
validate_pdf (new in v1.1.0)Validate a Tagged PDF for PDF/UA (ISO 14289-1) structural conformance (read-only).
add_attachmentGenerate a PDF/A-3 document with embedded files (Factur-X / ZUGFeRD invoices).
extract_attachmentsRead-only extraction of embedded files (Factur-X / ZUGFeRD XML round-trip) with byte-for-byte payloads.
extract_textBest-effort plain-text extraction from a non-encrypted PDF.
inspect_pdfRead-only inspection: PDF version, page count, encryption, PDF/A claim, signatures, attachments, placeholder state.
merge_pdfs (new in v1.3.0)Concatenate 2โ€“50 PDFs into one via pdfnative's page-tree API.
split_pdf (new in v1.3.0)Split one PDF into one document per page range (multi-output).
extract_pages (new in v1.3.0)Pull an arbitrary page subset into a single PDF.
annotate_pdf (new in v1.4.0)Add markup annotations (highlight, note, square/circle, line, freetext) as a visual overlay โ€” not a redaction.
draft_governance_issue (new in v1.4.0)Draft a governance-compliant GitHub issue locally for human review; never submits, no network.

New in v1.4.0:

  • ๐Ÿค AI governance + human-in-the-loop โ€” draft_governance_issue lets an agent draft a fully compliant GitHub issue locally (draft .md + machine-readable compliance report). The agent is a draftsman, never an autonomous submitter: a human is the only gate, and the server makes zero GitHub writes and no outbound network calls. Backed by the governance_contract and draft_issue_workflow MCP prompts.
  • โœ๏ธ Markup annotations โ€” annotate_pdf overlays highlight, sticky-note, underline, strikeout, squiggly, square, circle, line, and freetext annotations on an existing PDF via incremental update. It is a visual review layer, not a redaction โ€” underlying bytes remain.
  • ๐Ÿ”ข Page labels in inspect_pdf โ€” read-only surfacing of /PageLabels ranges (roman, decimal, prefixed).
  • โˆ‘ Math / scientific script โ€” add_international_text accepts lang: 'math' (explicit, like emoji) to embed the Noto Sans Math face on demand.
  • ๐Ÿงฉ MCP prompts โ€” the server now advertises the prompts capability with governance_contract and draft_issue_workflow.
  • โฌ† Engine upgrade โ€” pdfnative v1.5.0.

New in v1.3.0:

  • ๐Ÿ†• Three page-tree tools โ€” merge_pdfs, split_pdf, extract_pages (built on pdfnative v1.4.0's page-tree API; encrypted sources are rejected).

  • ๐Ÿ”– Bookmarks, page labels & nested lists โ€” generate_basic_pdf gains outline ('auto' or explicit tree), pageLabels, multi-level list items, and viewerPreferences.

  • ๐Ÿ“ Table cell borders & alignment โ€” add_table gains cellBorders, cellVAlign, and viewerPreferences; add_international_text gains viewerPreferences.

  • ๐Ÿ” Constant-time signing โ€” sign_pdf signs RSA and EC-DER keys through a node:crypto provider with a transparent pure-JS fallback; signatures stay interoperable.

  • โฌ† Engine upgrade โ€” pdfnative v1.4.0.

  • ๐Ÿ†• Tool extract_attachments โ€” read embedded files back out of a PDF (completes the Factur-X / ZUGFeRD round-trip) with byte-for-byte payloads, a filename filter, and an includeData: false metadata-only probe.

  • ๐Ÿ’ง Watermarks โ€” generate_basic_pdf and add_table accept an optional watermark (text, opacity, angle, colour, position) rendered on every page.

  • ๐ŸŒ Unicode normalize โ€” opt-in NFC/NFD/NFKC/NFKD on generate_basic_pdf and add_international_text.

  • ๐Ÿช™ Token-frugal reads โ€” the read-only tools (inspect_pdf, verify_pdf, validate_pdf, extract_text, extract_attachments) accept optional verbosity: 'summary' and fields: [โ€ฆ] inputs for ~90% smaller responses on large results, with no loss of the fields agents branch on. Defaults are unchanged.

  • ๐Ÿช™ No base64 duplication โ€” generated PDFs (base64 mode) are returned once as an embedded resource content block instead of also being copied into structuredContent.

  • ๐Ÿ”ง MCP registry publish fix โ€” mcpName now uses the canonical GitHub login casing (io.github.Nizoka/pdfnative-mcp) so the registry's case-sensitive validation accepts the npm package.

  • โฌ† Dependency โ€” upgraded to zod 4.

New in v1.1.0:

  • ๐Ÿ†• Tool validate_pdf โ€” read-only PDF/UA (ISO 14289-1) structural conformance check.
  • ๐Ÿ†• Six new scripts โ€” Telugu, Sinhala, Tibetan, Khmer, Myanmar, Ethiopic (24 scripts total).
  • ๐Ÿ†• COLRv1 colour emoji โ€” native colour emoji with monochrome fallback.
  • ๐Ÿ†• Newline sanitizer โ€” embedded \n in paragraphs auto-splits into separate paragraphs (Safe PDF/A).
  • ๐Ÿ†• Automatic NFC normalisation for add_international_text.
  • ๐Ÿ›  Engine upgrade โ€” pdfnative v1.3.0: the Euro sign / CP-1252 symbols now extract correctly, and wrapped table cells get unique per-line MCIDs (PDF/UA-safe).

New in v1.0.0:

  • ๐Ÿ†• Three new tools: verify_pdf, add_attachment (Factur-X / ZUGFeRD), extract_text.
  • ๐Ÿ†• Smart-table fields: wrap, repeatHeader, zebra, caption, minRowHeight, cellPadding.
  • ๐Ÿ†• inspect_pdf now reports hasSignaturePlaceholder and per-attachment summary; new check values 'placeholder' and 'attachments'.
  • ๐Ÿ†• Signing ergonomics: sign_pdf accepts ECDSA SEC1 / PKCS#8 DER keys and auto-injects a /Sig placeholder when missing (one-call signing of any PDF).
  • ๐Ÿ†• Opt-in cache (PDFNATIVE_MCP_CACHE_DIR): SHA-256 keyed, 1ย h TTL, 256ย MiB LRU.
  • ๐Ÿ†• _meta.apiVersion and per-tool _meta.examples for AI-agent discovery โ€” see docs/API_STABILITY.md.
  • ๐Ÿ†• AI agent guide: docs/AI_GUIDE.md โ€” decision tree + common pitfalls. See also the root AGENTS.md operations manual.
  • ๐Ÿ†• PDF/A authoring guide: docs/guides/PDFA.md.
  • ๐Ÿ›  Env-var rename: PDFNATIVE_MCP_OUTPUT_DIR (was PDFNATIVE_MPC_OUTPUT_DIR; old name still works with a one-shot deprecation warning).
  • โœ… Now shipped: merge_pdfs, split_pdf, extract_pages (v1.3.0) and annotate_pdf (v1.4.0). redact_pdf stays deferred โ€” pdfnative can only overlay content, and an overlay-only "redaction" would create false security, so it is intentionally not shipped (tracked as an upstream content-removal request).

All tools support two output modes:

  • base64 (default) โ€” the generated PDF is returned once as an embedded resource content block (a data:application/pdf;base64,โ€ฆ URI); structuredContent carries only { mode, sizeBytes }.
  • file โ€” the PDF is written to a sandboxed directory configured via PDFNATIVE_MCP_OUTPUT_DIR. File output is disabled unless this variable is set; absolute paths, path traversal, non-.pdf extensions, and NUL bytes are all rejected.

Upgrading from v1.1.0: the only behaviour change is that base64-mode bytes are no longer duplicated into structuredContent.base64. Read them from the embedded resource block instead:

- const base64 = response.structuredContent.base64;   // v1.1.0
+ const block = response.content.find((c) => c.type === 'resource');
+ const base64 = block.resource.blob;                  // v1.2.0

Token-frugal reads (v1.2.0). The four read-only tools accept two optional inputs:

  • verbosity: 'summary' โ€” returns a compact scalar-only verdict (drops the heavy arrays / full text). E.g. verify_pdf โ†’ { signatureCount, allValid, invalid, summary }.
  • fields: ['a', 'b.c'] โ€” projects the structured result to named dot-paths; composes after verbosity. Unknown paths are omitted leniently.

Smallest โ€œis this PDF signed and valid?โ€ probe: { "pdfBase64": "โ€ฆ", "verbosity": "summary", "fields": ["allValid"] }.

Why pdfnative?

pdfnative-mcp inherits every guarantee of the underlying engine:

  • Zero runtime dependencies โ€” pure JavaScript, no native bindings.
  • ISO 32000-1 (PDF 1.7) compliant output.
  • PDF/A-1b/2b/3b, AES-128/256 encryption, AcroForm, digital signatures.
  • 16 Unicode scripts with built-in BiDi reordering, Arabic positional shaping, Thai/Devanagari/Bengali/Tamil OpenType shaping.
  • Tree-shakeable ESM build.

๐Ÿ›  Tool reference

generate_basic_pdf

{
  "title": "Q1 2026 Report",
  "blocks": [
    { "type": "heading", "text": "Executive summary", "level": 1 },
    { "type": "paragraph", "text": "Revenue grew 24% year over year." },
    { "type": "list", "style": "bullet", "items": ["Strong APAC", "Stable EU", "Soft NA"] },
    { "type": "pageBreak" },
    { "type": "heading", "text": "Details", "level": 2 }
  ],
  "footerText": "Confidential โ€” Internal use only",
  "outputMode": "base64"
}

add_barcode

{
  "format": "qr",
  "data": "https://pdfnative.dev",
  "caption": "Scan to learn more",
  "ecLevel": "H",
  "outputMode": "file",
  "outputPath": "tickets/event-42.pdf"
}

Supported formats: qr, code128, ean13, datamatrix, pdf417.

add_international_text

{
  "title": "ู…ุฑุญุจุง ุจุงู„ุนุงู„ู…",
  "lang": "ar",
  "paragraphs": [
    "ู‡ุฐุง ุงุฎุชุจุงุฑ ู„ู„ู†ุต ุงู„ุนุฑุจูŠ ู…ุน ุชุดูƒูŠู„ OpenType ูˆู…ุญุงุฑู ุซู†ุงุฆูŠุฉ ุงู„ุงุชุฌุงู‡.",
    "Mixed content: ุงู„ุนุฑุจูŠุฉ + English โœ“"
  ]
}

Supported lang codes: ar, he, th, ja, zh, ko, el, hi, bn, ta, ru, ka, hy, tr, vi, pl, latin, emoji, math.

Multi-script documents โ€” pass an array or comma-separated list:

{
  "title": "Mixed Script",
  "lang": ["ar", "emoji"],
  "paragraphs": ["ุงู„ุนุฑุจูŠุฉ ู…ุน ุฑู…ูˆุฒ ๐ŸŽ‰๐Ÿš€"],
  "pdfA": "pdfa2u"
}

sign_pdf

As of v1.0.0, sign_pdf auto-injects a /Sig placeholder when missing โ€” you can sign any PDF in one call:

{
  "pdfBase64": "<any base64 PDF>",
  "algorithm": "rsa-sha256",
  "certDerBase64": "<base64 X.509 cert in DER>",
  "rsaKeyPkcs1DerBase64": "<base64 PKCS#1 RSAPrivateKey DER>",
  "signerName": "Alice",
  "reason": "Approval",
  "location": "Paris, FR",
  "signingTime": "2026-01-15T10:30:00Z"
}

For ECDSA P-256: use algorithm: "ecdsa-sha256" and supply either ecPrivateKeyDerBase64 (SEC1 or PKCS#8 DER) or ecPrivateScalarHex (64 hex chars).

PEM โ†’ DER conversion:

openssl x509 -in cert.pem -outform DER | base64 -w0                 # cert
openssl rsa  -in key.pem  -outform DER -traditional | base64 -w0    # RSA PKCS#1
openssl pkey -in key.pem  -outform DER | base64 -w0                 # ECDSA

Use prepare_signature_placeholder only when you need to customize the placeholder (e.g. larger placeholderBytes for >4096-bit RSA keys). Otherwise call sign_pdf directly.


add_table

{
  "title": "Monthly Sales",
  "headers": ["Region", "Units", "Revenue"],
  "rows": [
    ["APAC", "1200", "$240,000"],
    ["EMEA", "800", "$160,000"]
  ],
  "infoItems": [{ "label": "Period", "value": "January 2025" }],
  "footerText": "Internal use only",
  "outputMode": "base64"
}

add_form

{
  "title": "Employee Onboarding",
  "fields": [
    { "fieldType": "text", "name": "fullName", "label": "Full Name", "required": true },
    { "fieldType": "dropdown", "name": "dept", "label": "Department", "options": ["Engineering", "Sales", "HR"] },
    { "fieldType": "checkbox", "name": "agree", "label": "I agree to the terms", "checked": false }
  ],
  "outputMode": "base64"
}

embed_image

{
  "title": "Product Photo",
  "imageBase64": "<base64-encoded JPEG bytes>",
  "mimeType": "image/jpeg",
  "caption": "Front view of Model X",
  "width": 400,
  "outputMode": "base64"
}

Note: pdfnative does not support alpha-channel PNGs (color type 6). Pre-process such images to remove the alpha channel before embedding.

prepare_signature_placeholder

{
  "title": "Service Agreement",
  "signerName": "Alice Dupont",
  "reason": "Approved",
  "location": "Paris, FR",
  "blocks": [
    { "type": "paragraph", "text": "By signing below, I accept the terms and conditions." }
  ],
  "outputMode": "base64"
}

Pass the returned PDF bytes to sign_pdf to complete the signing workflow.

inspect_pdf

Read-only structural and security inspection โ€” useful for downstream verification, CI assertions, and AI agents that need to reason about a PDF before acting on it.

{
  "pdfBase64": "<base64 PDF>",
  "pages": true,
  "check": ["pdfa", "signed", "attachments"]
}

Returns:

{
  "version": "1.7",
  "pageCount": 3,
  "encryption": "none",          // 'none' | 'aes-128' | 'aes-256' | 'rc4' | 'unknown'
  "pdfA": "3B",                  // null when no PDF/A claim is present
  "signatureCount": 1,
  "hasSignaturePlaceholder": false,
  "attachments": [{ "filename": "factur-x.xml", "mimeType": "application/xml", "sizeBytes": 1234, "relationship": "Source" }],
  "info": { "Producer": "pdfnative", "Title": "Invoice INV-2025-001" },
  "perPage": [{ "index": 0, "width": 595, "height": 842 }],
  "checks": { "pdfa": true, "signed": true, "attachments": true },
  "checksPassed": true
}

check[] accepts any of 'pdfa', 'signed', 'encrypted', 'placeholder', 'attachments'. checksPassed is the AND of all requested checks.

validate_pdf

Read-only PDF/UA (ISO 14289-1) structural conformance check for a Tagged PDF. Generate an accessible document with any tool using pdfA (e.g. pdfA: 'pdfa2u'), then validate the result:

{ "pdfBase64": "<tagged-pdf-base64>" }

Returns:

{
  "standard": "pdf-ua-1",
  "valid": true,
  "errors": [],          // blocking structural violations (empty when valid)
  "warnings": [],        // non-blocking best-practice recommendations
  "summary": "PDF/UA structural prerequisites hold."
}

It verifies catalog /MarkInfo /Marked true, /StructTreeRoot (+ /ParentTree), /Metadata (XMP), /Lang, and per-page MCID uniqueness. This is a fast developer-time gate โ€” not a substitute for a full reference validator (veraPDF), which additionally checks fonts, colour, and rendering.

annotate_pdf

Overlay markup annotations on an existing PDF via incremental update. This is a visual review layer, not a redaction โ€” the underlying content is untouched.

{
  "pdfBase64": "<base64 PDF>",
  "annotations": [
    { "type": "highlight", "page": 0, "rect": [72, 700, 520, 715], "color": [1, 1, 0], "contents": "Check this figure" },
    { "type": "text", "page": 0, "rect": [540, 700, 560, 720], "contents": "Reviewer note" }
  ]
}

Types: text, highlight, underline, strikeout, squiggly, square, circle, line, freetext. Encrypted sources are rejected (ENCRYPTED_SOURCE).

draft_governance_issue

Draft a governance-compliant GitHub issue locally for a human to review and submit. The server never contacts GitHub and makes no outbound network calls; it returns the draft Markdown plus a machine-readable compliance report.

{
  "title": "add_table drops the caption on the second page",
  "issueType": "bug",
  "summary": "The table caption is only rendered on page 1 when repeatHeader is true.",
  "reproduction": { "command": "node examples/run.mjs add-table-caption.json", "result": "Page 2 has no caption row." },
  "expectedBehavior": "The caption repeats with the header on every page.",
  "duplicateSearchPerformed": true
}

A draft that proposes a runtime dependency, omits a reproduction, or sets duplicateSearchPerformed: false is rejected with GOVERNANCE_VIOLATION. See docs/guides/AI_GOVERNANCE.md for the full human-in-the-loop contract.

verify_pdf, add_attachment, extract_text

See the dedicated sections in docs/AI_GUIDE.md and the reference in docs/KNOWLEDGE_BASE.md. Ready-to-run examples live under examples/.


๐Ÿ” Security model

pdfnative-mcp runs inside the host process and exposes a stdio MCP server. It does not open network sockets and does not perform any I/O outside the configured sandbox.

  • File writes are gated by PDFNATIVE_MCP_OUTPUT_DIR. When unset, the file output mode is rejected with a SecurityError.
  • Path resolution rejects absolute paths, traversal sequences (..), NUL bytes, and any extension other than .pdf.
  • Output size is capped at 50 MB per call.
  • Inputs are validated against strict JSON Schemas + Zod runtime checks at the boundary of every tool.

See SECURITY.md for the responsible disclosure process.


๐Ÿงช Local development

git clone https://github.com/Nizoka/pdfnative-mcp.git
cd pdfnative-mcp
npm install
npm run typecheck
npm run lint
npm test
npm run build

Smoke-test the server over stdio:

node dist/cli.js
# In another terminal, send a JSON-RPC initialize request via stdin (e.g. with mcp-inspector).

Contributors: see docs/guides/LOCAL_TESTING.md for the full local-verification workflow โ€” the quality gate, examples-as-tests, validating that generated PDFs are structurally correct (assertValidPdf, inspect_pdf, validate_pdf, verify_pdf), opening output in a viewer, external PDF/A checking with veraPDF, and the MCP Inspector.

๐Ÿ“ฃ Release process

pdfnative-mcp follows the same release formalism as pdfnative:

  • One release note file per tag in release-notes/vX.Y.Z.md
  • CHANGELOG.md mirrors each release bullet list
  • GitHub Release body is copied from release-notes/vX.Y.Z.md
  • npm publication is handled by GitHub Actions Trusted Publishing (OIDC), without NPM_TOKEN

See release-notes/TEMPLATE.md for the canonical structure and publication checklist.


๐Ÿ“š Project structure

src/
โ”œโ”€โ”€ cli.ts                      # stdio entrypoint (#!/usr/bin/env node)
โ”œโ”€โ”€ index.ts                    # public library exports
โ”œโ”€โ”€ server.ts                   # McpServer factory + tool registry
โ”œโ”€โ”€ output.ts                   # sandboxed file writer / base64 emitter (single + multi)
โ”œโ”€โ”€ text.ts                     # newline sanitizer (Safe PDF/A)
โ”œโ”€โ”€ doc-features.ts             # nested lists, outline, page labels, viewer prefs
โ”œโ”€โ”€ pagetree.ts                 # page-tree error mapping (merge/split/extract)
โ”œโ”€โ”€ crypto-provider.ts          # node:crypto constant-time signature provider
โ”œโ”€โ”€ errors.ts                   # ToolError, SecurityError
โ””โ”€โ”€ tools/
    โ”œโ”€โ”€ generate-basic-pdf.ts
    โ”œโ”€โ”€ add-barcode.ts
    โ”œโ”€โ”€ sign-pdf.ts
    โ”œโ”€โ”€ add-international-text.ts
    โ”œโ”€โ”€ add-table.ts
    โ”œโ”€โ”€ add-form.ts
    โ”œโ”€โ”€ embed-image.ts
    โ”œโ”€โ”€ inspect-pdf.ts
    โ”œโ”€โ”€ verify-pdf.ts
    โ”œโ”€โ”€ validate-pdf.ts
    โ”œโ”€โ”€ add-attachment.ts
    โ”œโ”€โ”€ extract-attachments.ts
    โ”œโ”€โ”€ extract-text.ts
    โ”œโ”€โ”€ merge-pdfs.ts
    โ”œโ”€โ”€ split-pdf.ts
    โ”œโ”€โ”€ extract-pages.ts
    โ””โ”€โ”€ prepare-signature-placeholder.ts
tests/                          # vitest suites

๐Ÿ—บ Roadmap

v1.3.0 is shipped. The full plan โ€” released milestones, in-progress work, and long-term direction โ€” lives in ROADMAP.md.

Blocked upstream (page-tree manipulation):

  • redact_pdf and an encrypted-PDF round-trip โ€” pdfnative does not yet export the content-redaction / decryption primitives required to build these safely. They remain on the roadmap, blocked on an upstream API. (merge_pdfs, split_pdf and extract_pages shipped in v1.3.0.)

Have a feature idea? Open an issue or PR.


โญ Star the project

If pdfnative-mcp is useful to you, please โญ this repository โ€” and consider also starring the underlying engine Nizoka/pdfnative. Stars help others discover the project and motivate continued development.


๐Ÿค Contributing

Contributions are very welcome. Please read CONTRIBUTING.md, check the open issues, and follow the code of conduct.


๐Ÿ“„ License

MIT ยฉ 2026 Nizoka

pdfnative-mcp is built on top of pdfnative and the Model Context Protocol TypeScript SDK.