Skip to content

pdf-verify-mcp

The server that judges whether a signature is cryptographically valid and whether the file meets the standard. It verifies electronic signatures cryptographically, detects changes made after signing, and scores conformance to PDF/A (archiving) and PDF/UA (accessibility).

What this one server gives you

"Is the signature on this contract valid?" "Was it changed after signing?" "Will this PDF survive as PDF/A?" — all answerable here. Verdicts come from cryptography and rule tables, so the same file yields the same result every time. Deciding whether an incoming PDF may be used in a business process (incoming audit) centres on this server.

What it can decide

QuestionWhat is measuredToolAssertion strength
Is the signature cryptographically valid?ByteRange digest recomputation, CMS messageDigest comparison, signature value verification, RFC 3161 timestampsverify_signaturesT1
Is the signer trustworthy?Certificate chain against trust anchors, revocation (OCSP / CRL)verify_signatures (needs trust_anchors)T1
Was it changed after signing?Incremental revisions, signed-range coverage, DocMDP permissions and violations, which objects changedverify_integrityT1
Does it breach the ISO 32000 body?The constraint tables of pdf-constraints (where veraPDF does not look)validate_clausesT1
Does it conform to PDF/UA (accessibility)?ISO 14289, via veraPDF or 12 built-in rulesvalidate_conformanceT1
Does it conform to PDF/A (archiving)?ISO 19005, via veraPDF or 15 built-in rulesvalidate_conformanceT2
Does it carry long-term-preservation structure?PAdES B-B / B-T / B-LT / B-LTA-matching structuredetect_pades_levelT3 (observation only)
Does it claim to be PDF/A or PDF/UA?The pdfaid / pdfuaid declarations in XMPidentify_conformanceReading a declaration
May it be used in the business process?The facts above applied to a fixed rule table and reduced to 4 valuesevaluate_policyAggregation of facts

What it gives you together with a Skill

This MCP server sits in the judgment layer of the four (judgment = pass or fail over observed facts): it decides pass or fail over the facts observed. What to measure in which order, how to explain the verdict and which legal grounds to attach are a Skill's job.

Shapes carry meaning (→ legend).

SkillWhat this server does thereRequired?
pdf-trustThe axis of the audit. evaluate_policy decides the 4-value verdict; the Skill explains firedRules, recommends actions and cites legal groundsRequired (v0.7.0+, v0.21.0+ recommended)
pdf-publishThe exit gate: machine-scores the produced PDF with veraPDF. At the conformance level the pipeline aborts without itRequired at conformance

The judge is code, the narrative is the LLM

Use the returned firedRules / advisories to explain the outcome, never to override it. Do not read an advisory as a failure. Do not read the absence of advisories as a pass.

What it cannot do

  • It never proves conformance. What it does is look for demonstrable errors. Finding one lets you state that the file does not meet the standard; finding none does not prove that it does
  • Without trust anchors it cannot speak to identity. Without trust_anchors (or the env var), valid means only that the cryptography checks out (trust: not_evaluated). Likewise for revocation: if it could not be checked, you may not say "not revoked"
  • PDF/UA cannot be fully decided by machine. Whether alt text exists is checkable; whether it is meaningful is not
  • PAdES never becomes a conformance verdict. ETSI EN 319 142 is not in the spec corpus and there is no third-party validator, so the result is "the structure matches B-LT", never "conforms to PAdES B-LT" (every report carries normativeBasis: "T3")

What it does not do

  • Judging whether the content is true (a properly signed document can still state something untrue)
  • Observation (→ pdf-reader), citing the spec (→ pdf-spec), production (→ pdf-writer)

Installation

jsonc
{
  "mcpServers": {
    "pdf-verify": {
      "command": "npx",
      "args": ["-y", "@shuji-bonji/pdf-verify-mcp@latest"],
      "env": {
        "PDF_VERIFY_VERAPDF": "/usr/local/bin/verapdf",
        "PDF_VERIFY_TRUST_ANCHORS": "/path/to/trust-anchors"
      }
    }
  }
}

Both environment variables are optional; the built-in rules work without veraPDF.

Common parameters

Every tool accepts these.

ParameterTypeDescription
file_path requiredstringAbsolute path to a local PDF
response_formatmarkdown / jsonOutput format. Default markdown
passwordstringPassword for an encrypted PDF. Permissions encryption (empty user password) is tried automatically (where supported)

Tools

Parameters, types and defaults are in the tools reference (generated from tools/list).

ToolOne-liner
verify_signaturesCryptographic signature verification (chain, revocation, timestamps)
verify_integrityAnalysis of changes after signing (incremental updates, coverage, DocMDP)
detect_pades_levelObservation of PAdES B-B / B-T / B-LT / B-LTA-matching structure
identify_conformanceReading XMP declarations (pdfaid / pdfuaid) — the entry point of judgment
validate_conformancePDF/A / PDF/UA validation. Delegates to veraPDF, or built-in rules
validate_clausesConstraint checks against the ISO 32000 body (where veraPDF does not look)
evaluate_policyDeterministic 4-value verdict from the facts

How to use it

Per-tool cautions and prompt → parameters → returned JSON are at the end of each tool on the tools reference.

Check the signatures

verify_signatures returns three values per signature. They are independent.

FieldValuesWhat it looks at
verdictvalid / invalid / indeterminatewhether the cryptography matched
trusttrusted / untrusted / not_evaluatedthe certificate chain
revocationgood / revoked / unknown / not_checkedOCSP / CRL

Without trust anchors (trust_anchors or PDF_VERIFY_TRUST_ANCHORS), trust stays not_evaluated. That valid means the digest matched; it does not prove the signer is who they claim to be. evaluate_policy then stops at use_with_caution.

Revocation checking defaults to embedded (data inside the PDF and CMS). online queries OCSP and CRL over HTTP.

When the file grew after signing

What verify_integrity returns is what to look at — not an automatic finding of tampering. Adding a signature, DSS or a document timestamp is a permitted way to write PDF. Per ISO 32000-2 §12.8.2.2, DSS / document-timestamp increments after a P=1 certification are not reported as violations (flagged laterChangesAppearLtvOnly).

Since v0.10.0 it also returns which objects were written after signing (revisions / objectChangesAfterLastSignature), walking the xref chain over raw bytes (table / xref stream / hybrid). That diff does not move the signature verdict.

Not being able to walk the xref chain is not the same as nothing having changed

When the chain cannot be walked, the result is null, not an empty array. Three things go wrong in a naive implementation:

  • A linearized file has two xref sections for one save. Without merging them, every object looks "added"
  • A full save reports an inflated change count (224,065 in one measurement)
  • Reading "could not walk" as "unchanged" states as settled a fact that was never established

All three were fixed against real measurements.

A claim in the file is not a measurement

identify_conformance only reads whether the XMP wrote "I am PDF/A". Writing it is not evidence. Rule checking is validate_conformance.

validate_conformance delegates to veraPDF when it is present (authoritative), and otherwise runs the built-in rules. flavour accepts "pdfa-1b""pdfa-3b" / "pdfa-4" / "pdfa-4e" / "pdfa-4f" (v0.11.0+) / "pdfua-1" / "pdfua-2". When omitted it follows the XMP declaration (PDF/A wins when both are declared; otherwise pdfa-2b). PDF/A-4 has no conformance level, so "pdfa-4b" does not existe / f are variants, not levels.

Read compliant as follows. Under veraPDF it is true / false. Under the built-in rules, false means a decisive violation, and null means "no violation in the subset that was checked" (not a certificate). Native PDF/UA violations carry a severity: only error can prove non-conformance; warning needs a person to review.

Check against ISO 32000 clauses

validate_clauses looks at constraints mapped from the ISO 32000-1/-2 body. A file can pass PDF/A or PDF/UA and still violate ISO 32000 (example: embedding a CFF font program under /FontFile2, which Table 124 forbids). The mapping and its evaluator live in pdf-constraints, and the output names the version that decided.

StateMeaning
passnothing in this constraint could be disproved
faildisproved, with the fact and measured value
not_applicablethe clause does not apply to this document
needs_external_facta fact outside the file was missing, so no decision was made (never defaulted to pass)

Failures marked trace mean the clause binds the PDF processor — evidence that someone broke it, not necessarily the last writer.

Observe PAdES structure

detect_pades_level observes structure. Do not write "conforms to PAdES". Levels are added in this order.

LevelStructure (each row adds to the one above)Meaning
B-BCAdES signaturesignature only
B-T+ signature timestamp (RFC 3161)a third party attests the signing time
B-LT+ DSS with validation data (certificates, OCSP/CRL)revocation-checking material is self-contained in the document
B-LTA+ document timestampthe validation material itself is sealed for long-term preservation

B-LT and B-LTA also require that the DSS revocation data actually covers the signer certificate. Otherwise the level stops at B-T. Legacy adbe.pkcs7.detached is reported as non-PAdES.

Ask whether it may be used in the process

evaluate_policy runs verify_signatures, verify_integrity and detect_pades_level internally (plus validate_conformance for long-term-preservation profiles). It then applies those facts to a fixed rule table and reduces them to one of four values. The same facts and the same profile always yield the same verdict.

Choose profile from general / contract (signature required, identity-focused) / financial and government (long-term-preservation checks) / legal / medical (most conservative — caution escalates to review).

It returns verdict, firedRules (fired rule IDs and reasons), advisories (recommendations that do not move the verdict) and a facts summary. The Skill that builds a whole audit around this verdict is pdf-trust.

Assertion strength

How strongly a verdict may be stated depends on whether the normative text is at hand → the T1/T2/T3 rule. ETSI PAdES (T3) stays a structural observation, PDF/A (T2) goes as far as "veraPDF judged it", ISO 32000 / PDF/UA (T1) can quote the clause and state it plainly.

MIT Licensed