Skip to main content
Glama
shuji-bonji

pdf-verify-mcp

by shuji-bonji

pdf-verify-mcp

CI npm version License: MIT

日本語

MCP server for PDF authenticity and conformance verification — cryptographic digital signature verification, tamper detection, PAdES baseline level detection, and PDF/A (ISO 19005) / PDF/UA (ISO 14289) validation.

Part of the PDF family alongside pdf-reader-mcp (structure analysis) and pdf-spec-mcp (specification reference). Where pdf-reader-mcp tells you what is in a PDF, pdf-verify-mcp tells you whether it is genuine.

Tools

Tool

Purpose

verify_signatures

Cryptographic verification, trust chain evaluation against trust anchors, revocation checking (embedded OCSP/CRL or online), RFC 3161 timestamp verification

verify_integrity

Tamper detection: incremental updates, changes after signing, DocMDP certification violations assessed per P value (below), and an object-level diff of the revision chain (which objects each update added, rewrote or freed). Incremental updates are legal, so the diff says what to review — no verdict rests on it. Where those objects sit on the page is pdf-reader-mcp locate_objects

detect_pades_level

PAdES baseline level (B-B / B-T / B-LT / B-LTA) with content-validated LTV data

identify_conformance

Declared PDF/A / PDF/UA conformance from XMP metadata

validate_conformance

PDF/A (ISO 19005) and PDF/UA (ISO 14289) validation: veraPDF when installed, built-in rule subset otherwise

validate_clauses

Constraints mapped from ISO 32000-1/-2 clauses — the specification body itself, which the PDF/A and PDF/UA profiles do not cover

evaluate_policy

Deterministic 4-value trust verdict (trust_and_use / use_with_caution / human_review_required / reject) from a fixed rule table over the verification facts, with domain profiles (contract, financial, legal, medical, government). The judge is code; the narrative is the LLM

Related MCP server: MCP PDF

Verdicts

Verdict

Meaning

valid

ByteRange digest matches and the CMS signature is cryptographically valid

invalid

Digest mismatch or signature verification failure — possible tampering

indeterminate

Unsupported format or verification could not complete

DocMDP certification permissions (v0.14)

A certification signature's P value states which kinds of change are allowed (ISO 32000-2 Table 257). verify_integrity classifies the changes made after signing at the object level and compares them against what that P permits.

P

Permitted changes

Is adding an annotation a violation?

1

none (DSS / document-timestamp incremental updates are the §12.8.2.2 exception)

yes

2

filling in forms, instantiating page templates, signing

yes — annotations start at 3

3

as for 2, plus annotation creation, deletion and modification

no

Objects that a permitted change necessarily drags along — the page whose /Annots grew, the catalog, /Info, the XMP stream — are classified as housekeeping and are not counted as violations. Counting them would make every certified document violate, since a lawful P=3 annotation addition moves all four.

violationAssessment is three-valued

Value

Meaning

permitted

every change after signing is of a kind P allows

violated

at least one change is outside it

indeterminate

it could not be determined (the xref chain could not be walked, or a changed object's kind could not be read)

⚠️ indeterminate is not a pass. This server disproves, and "could not be disproved" is a different statement from "is fine" — the same discipline as validate_clauses returning needs_external_fact rather than defaulting a check into a pass.

violatedByLaterChanges (boolean) is kept for compatibility and collapses indeterminate to false. Read violationAssessment wherever "could not tell" must not be mistaken for "fine". evaluate_policy raises indeterminate to human_review_required as well.

A bare stream with no /Type is treated as not determined rather than as content: the same bytes could be a form field's appearance stream (which P=2 permits) or a page's content stream (which no P permits).

Response size (v0.29.0)

A JSON response is never cut by length. Lists are capped instead, and every cut is reported next to the list as { returned, total }: signatures / levels at 32 (verify_signatures does not verify the fields beyond the cap; evaluate_policy verifies all and caps only facts.signatures), revisions at 32, violations / results at 200 (counts such as compliant, failedRules, violations, notDecided cover all entries). A markdown response is cut at 50,000 characters with a visible marker.

Trust & revocation (v0.2)

Pass trust_anchors (PEM/DER file paths) or set the PDF_VERIFY_TRUST_ANCHORS env var (a directory of certificates) to evaluate the signer's chain: results are trusted / untrusted / not_evaluated with the certificate path. The validation time is a verified signature timestamp, else the earliest document timestamp covering the signature, else the current time (v0.27.0); the CMS signingTime attribute is written by the signer and is not used. The chosen time is reported as validationTime.

check_revocation controls revocation checking: embedded (default — OCSP/CRL data in the DSS, CMS SignedData.crls, or the CMS signed attribute adbe-revocationInfoArchival; reported as revocation.origin), online (additionally query OCSP responders and CRL distribution points over HTTP), or none (revocation.status: not_checked). CRLs and OCSP responses whose signatures cannot be verified, whose nextUpdate is before the validation time, or whose thisUpdate is more than revocation_freshness seconds (default 86400) before it give unknown (v0.28.0). Pass trusted_ocsp_responders to trust an OCSP responder issued by another CA. Each intermediate CA's result is reported in trust.chainRevocation. A revoked signer certificate gives revoked_after_validation_time (verdict unchanged) when a timestamp proves the signature predates the revocation; otherwise revoked with verdict indeterminate. In online mode, missing issuer certificates are fetched via AIA caIssuers to complete the chain (v0.4). When anchors are provided, TSA certificate chains of RFC 3161 timestamps are evaluated too (tsaTrust).

Step

What is checked

Network

Integrity

/ByteRange hash matches the CMS messageDigest

none

Signature value

Signature value verifies with the signer certificate's public key

none

Certificate chain

Chains up to a trust anchor

online only: issuer certificates fetched via AIA caIssuers

Revocation

OCSP / CRL for the signer certificate

none under embedded; under online, HTTP queries when embedded data gives no answer

Timestamp

RFC 3161 token and TSA signature

none

verdict: valid means integrity and signature value passed (revoked turns it into indeterminate). online results reflect the CA's state at query time and can change later. See the site guide for each step and how to choose a mode.

Without trust anchors, trust stays not_evaluated and a valid verdict asserts cryptographic integrity, not signer identity.

Encrypted PDFs are decrypted automatically when permission-encrypted (empty user password); pass password for reader-password PDFs. Supported: RC4 (R2–R4), AES-128, AES-256 (R6). Decryption recovers string metadata (field name, /M, /Reason, /Location) and XMP — a signature's /Contents is exempt from encryption, so verification never depends on it.

Supported SubFilters: ETSI.CAdES.detached (PAdES), adbe.pkcs7.detached, ETSI.RFC3161 (document timestamps). RFC 3161 signature timestamps are fully verified (imprint + TSA signature). Legacy MD5/SHA-1 signatures are verified via node:crypto and flagged as weak.

PDF/A validation (v0.3)

validate_conformance uses a hybrid engine. With veraPDF installed (PDF_VERIFY_VERAPDF env var or on PATH) validation is delegated for authoritative results. Otherwise a built-in subset of ~15 high-value ISO 19005 rules runs natively (encryption, trailer /ID, LZW, font embedding, JavaScript/prohibited actions, OutputIntent, transparency for A-1, XFA, and more), each reported with its clause reference.

Native results are honest about their limits: violations mean definitively non-compliant; all-passed means "no violations in the checked subset" — never certification.

PDF/A-4 (pdfa-4, pdfa-4e, pdfa-4f) is accepted. Note that PDF/A-4 has no conformance level — there is no pdfa-4b; e and f are variants. The native rules were written from ISO 19005-1/-2 and have not been checked against ISO 19005-4, so a PDF/A-4 report says outright that the native verdict ranks below veraPDF. Validate part 4 with veraPDF.

ISO 32000 clause constraints (v0.9)

validate_clauses covers different ground: the body of the PDF specification, not the PDF/A or PDF/UA profiles. A file can be judged COMPLIANT by veraPDF and still violate ISO 32000 — embedding a CFF font program under /FontFile2 (Table 124) is a real example that surfaced only as a viewer warning.

The mapping from clauses to structural conditions, and its evaluation, live in @shuji-bonji/pdf-constraints. Every report names the version that decided it, because the rules move as constraints are added.

Each constraint resolves to one of four states:

State

Meaning

pass

Nothing in this constraint could be disproved

fail

Disproved, with the fact and its measured value as evidence

not_applicable

The clause does not apply to this document

needs_external_fact

A fact outside the file was not supplied, so the constraint was not decided

Two things the report distinguishes deliberately:

  • needs_external_fact is not a pass. Whether a font is a subset is known only to whoever made it — the PDF does not say. Supply it with given: { isSubset: true }; without it the constraint degrades rather than defaulting into silent approval.

  • Some failures are traces, not violations. Where a clause addresses the PDF processor (the act of writing), a file can only show that someone broke it — §14.3.4 explicitly allows leaving an existing inconsistency alone, so the last writer is not necessarily at fault.

Because these are T1 clauses, a failure can be stated plainly and its clause ID quoted — retrieve the wording with pdf-spec-mcp's get_requirements.

PDF/UA validation (v0.6)

Pass flavour: "pdfua-1" (or "pdfua-2") to validate accessibility conformance against ISO 14289. veraPDF is delegated to with --flavour ua1 when installed; otherwise 12 native rules run: MarkInfo/Marked, StructTreeRoot, pdfuaid declaration, /Lang, DisplayDocTitle, document title, Figure /Alt, image tagging, heading hierarchy, table TH/TR, Link /Contents, and encryption barriers. Tags are resolved through /RoleMap.

PDF/UA native violations carry a severity: only error rules can prove non-conformance, while warning rules flag what needs human review. Accessibility is not fully machine-decidable — whether alt text is present is checkable, whether it is meaningful is not.

The native subset stops where pdf-lib does. Rules needing content-stream analysis — 7.1-3 (content marked as artifact or tagged), 7.2-34 (language of page content), 7.18.1-1 (annotations nested in Annot tags), 7.18.3-1 (/Tabs) — are left to veraPDF rather than approximated. Install veraPDF when accessibility matters.

Without an explicit flavour, PDF/UA is selected only when the document declares PDF/UA and not PDF/A. Use pdf-reader-mcp's inspect_tags to examine the structure tree itself; conformance judgment lives here.

Installation

As a plugin (via the shuji-bonji/claude-plugins marketplace, recommended):

/plugin marketplace add shuji-bonji/claude-plugins
/plugin install pdf-verify-mcp@shuji-bonji

Or add directly to your MCP config:

{
  "mcpServers": {
    "pdf-verify": {
      "command": "npx",
      "args": ["-y", "@shuji-bonji/pdf-verify-mcp@latest"]
    }
  }
}

Use @latest (or pin a version). npx -y <pkg> without a version keeps running whatever it cached the first time — -y only skips the install prompt, it does not check for updates. To clear a stale cache: rm -rf ~/.npm/_npx.

Usage examples

  • "Verify the signatures in /path/to/contract.pdf — has it been altered since signing?"

  • "Was this certified PDF modified after certification?"

  • "Is this signature LTV-enabled (B-LT or B-LTA)?"

  • "Does this document declare PDF/A-2b conformance?"

Development

npm install
npm test           # vitest (fixtures are generated in-memory)
npm run build
npm run check      # biome lint + format
npm run test:fixtures  # write sample signed/tampered PDFs to tests/fixtures/generated/

Test fixtures (self-signed certificate + signed PDFs) are generated programmatically with pkijs + WebCrypto — no binary assets in the repository.

License

MIT © shuji-bonji

Dependencies: pkijs / asn1js (BSD-3-Clause), pdf-lib (MIT), normativepdf (MIT), @shuji-bonji/pdf-constraints (MIT), @modelcontextprotocol/sdk (MIT), zod (MIT).

Cross-reference sections are read by normativepdf, a clause-driven PDF library in which every behaviour is tied to an ISO 32000 clause. It is strict — an unreadable section is an error there. The recovery policy for damaged files (falling back to an older startxref, capping a cyclic /Prev chain, folding a linearised file's two sections back into one save) stays in this server, because it is a forensic judgement rather than a reading of the specification.

Available Tools

7 tools
detect_pades_levelDetect PAdES Baseline LevelA
Read-onlyIdempotent

Observe which PAdES baseline level (ETSI EN 319 142) the structure of each signature matches.

This is an observation, not a conformance verdict. ETSI EN 319 142 is not in this family's spec corpus, and unlike PDF/A there is no third-party validator to delegate to — so the result says "the structure matches B-LT", never "conforms to PAdES B-LT". Every report carries normativeBasis: "T3" to make that explicit.

Detection is structural: B-B (CAdES signature), B-T (+ RFC 3161 signature timestamp), B-LT (+ DSS with validation data), B-LTA (+ document timestamp). Legacy adbe.pkcs7.detached signatures are reported as non-PAdES.

Args:

  • file_path (string): Absolute path to a local PDF file

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: An object of the form { scope, levels: [...] }. The top level changed from an array to an object in v0.21.0 - read .levels for the list.

Size (v0.29.0): at most 32 signatures are listed; levelsTruncated = { returned, total } says when the list was cut. JSON is never cut by length.

Every report begins with a "scope" object - how far the reading got, not a verdict: whether the cross-reference chain could be walked to the end (chainStop), whether this tool had to rebuild the cross-reference table itself (reconstructed - when true, the table is this tool's reconstruction and not the one the file carries), how many objects and sections were read, and whether an encrypted document could be opened. Read it before the verdict: "no violations" over a rebuilt table is not the same statement as "no violations" over the file's own table.

Per-signature level with evidence (signature timestamp, DSS, VRI, document timestamp presence).

Note: B-LT / B-LTA additionally require that the DSS revocation data actually covers the signer certificate (content-level LTV validation); otherwise the level is capped at B-T.

Examples:

  • Check if a signature is long-term validation (LTV) enabled

  • Audit whether archived contracts meet B-LTA requirements

ParametersJSON Schema
NameRequiredDescriptionDefault
file_pathYesAbsolute path to a local PDF file (e.g., "/path/to/document.pdf")
response_formatNoOutput format: "markdown" for human-readable, "json" for structured datamarkdown

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even with readOnlyHint and idempotentHint annotations, the description adds substantial behavioral detail: the structural detection ladder, legacy adbe.pkcs7.detached handling, normativeBasis 'T3', scope object semantics, cross-reference table reconstruction caveats, truncation behavior, and LTV capping rules. It clarifies exactly how results should be interpreted, which far exceeds what the annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-organized and front-loaded: purpose first, then the critical observation-versus-verdict caveat, followed by technical details, arguments, return shape, and examples. The Args block is somewhat redundant with the schema, but the density is justified given that there is no output schema and the tool has nuanced interpretation semantics.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden of explaining what the tool returns, and it does so thoroughly: top-level object shape, .levels, levelsTruncated, scope object fields, per-signature evidence, and the LTV cap. It also covers edge cases like reconstructed cross-reference tables, encrypted documents, and legacy signatures, making the tool safely callable and interpretable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already covers both parameters with 100% coverage, so the baseline of 3 applies. The description's Args section mostly repeats the schema (absolute path, markdown/json default) and adds little new semantic meaning about the parameters themselves, though it does tie response_format to output behavior like JSON never being length-truncated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific action ('Observe which PAdES baseline level...') on a specific resource ('the structure of each signature'), immediately grounding the tool's purpose. It also distinguishes itself from conformance validation by explicitly saying 'This is an observation, not a conformance verdict,' which separates it from siblings like validate_conformance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear use cases ('Check if a signature is long-term validation (LTV) enabled', 'Audit whether archived contracts meet B-LTA requirements') and strongly warns against treating results as conformance verdicts. It does not explicitly name sibling tools or state 'use X instead', but the observation-versus-verdict framing and examples provide clear contextual guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

evaluate_policyEvaluate Trust Policy (deterministic verdict)A
Read-onlyIdempotent

Produce a deterministic 4-value trust verdict (trust_and_use / use_with_caution / human_review_required / reject) for a PDF.

Runs verify_signatures, verify_integrity and detect_pades_level internally (plus validate_conformance for long-term-preservation profiles) and folds the facts through a fixed rule table — the same facts and profile always yield the same verdict. The verdict is decided entirely by code; use the returned firedRules/advisories to explain the outcome, never to override it. It judges authenticity and integrity only, never the truth of the document's content.

Args:

  • file_path (string): Absolute path to a local PDF file

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

  • profile ('general' | 'contract' | 'financial' | 'legal' | 'medical' | 'government'): Judgment profile (default: 'general')

  • trust_anchors (string[], optional): Trust anchor certificate paths. Without them, signer identity stays not_evaluated and the verdict is capped at use_with_caution

  • check_revocation ('none' | 'embedded' | 'online'): Revocation mode (default: 'embedded')

  • revocation_freshness (integer seconds, default 86400): How long before the validation time a CRL / OCSP response may have been issued and still count as "good"

  • trusted_ocsp_responders (string[], optional): Certificates of locally trusted OCSP responders (RFC 6960 §4.2.2.2)

  • password (string, optional): Password for an encrypted PDF

Returns: Every report begins with a "scope" object - how far the reading got, not a verdict: whether the cross-reference chain could be walked to the end (chainStop), whether this tool had to rebuild the cross-reference table itself (reconstructed - when true, the table is this tool's reconstruction and not the one the file carries), how many objects and sections were read, and whether an encrypted document could be opened. Read it before the verdict: "no violations" over a rebuilt table is not the same statement as "no violations" over the file's own table.

Size (v0.29.0): the verdict is computed over EVERY signature; facts.signatures lists at most 32 of them and facts.signaturesTruncated = { returned, total } says when it was cut. JSON is never cut by length.

verdict, firedRules (rule IDs with per-rule verdict and reason), advisories (recommendations that do not affect the verdict), and the underlying facts summary.

Examples:

  • Gate incoming invoices before filing them (profile: financial)

  • Decide whether a countersigned contract can be relied on (profile: contract, with the counterparty CA as trust anchor)

  • Batch-audit a folder of received PDFs with a reproducible, model-independent verdict

ParametersJSON Schema
NameRequiredDescriptionDefault
profileNoJudgment profile: "general" (default thresholds), "contract" (signature required, identity-focused), "financial" (long-term preservation checks), "legal", "medical" (most conservative; caution escalates to review), "government" (long-term checks, unsigned tolerated).general
passwordNoPassword for an encrypted PDF. Omit for permission-encrypted PDFs (an empty user password is tried automatically).
file_pathYesAbsolute path to a local PDF file (e.g., "/path/to/document.pdf")
trust_anchorsNoAbsolute paths to trust anchor certificates (PEM or DER). Merged with the PDF_VERIFY_TRUST_ANCHORS environment variable. Without anchors, valid signatures are capped at use_with_caution (identity not evaluated).
response_formatNoOutput format: "markdown" for human-readable, "json" for structured datamarkdown
check_revocationNoRevocation checking: "none", "embedded" (default), or "online" (queries OCSP/CRL endpoints over HTTP).embedded
revocation_freshnessNoSeconds before the validation time that a CRL / OCSP response may have been issued (thisUpdate) and still support "good". Default 86400 (24 h); 0 accepts only data issued at or after the validation time. Older data gives "unknown".
trusted_ocsp_respondersNoAbsolute paths to certificates (PEM or DER) of locally trusted OCSP responders (RFC 6960 §4.2.2.2). A response signed by one of them is accepted even when the responder is not the issuing CA or its delegate.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/openWorld/idempotent/non-destructive, and the description adds meaningful behavioral detail: verdicts are deterministic and code-decided, firedRules/advisories are explanatory not overridable, the scope object must be read before the verdict, reconstructed xref tables change the meaning of results, and signature lists can be truncated but JSON is not. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The text is long but structured into Purpose, Args, Returns, and Examples, and each section serves a clear need for a tool of this complexity. The core purpose is front-loaded, and the return-value caveats are grouped rather than scattered. No sentence is purely filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description correctly takes responsibility for explaining return semantics. It covers the scope object, verdict, firedRules, advisories, truncation behavior, and the reconstructed-table caveat. Given the tool's 18 parameters and complex behavior, nearly everything an agent needs to select and invoke it correctly is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the Args section largely restates the schema's parameter meaning. The description does add some contextual significance, such as trust anchors capping the verdict and revocation freshness affecting 'good' status, but those points are also present in the schema. This is the baseline case where structured data already does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and outcome: 'Produce a deterministic 4-value trust verdict... for a PDF.' It also differentiates itself from lower-level siblings by stating that it runs verify_signatures, verify_integrity, and detect_pades_level internally, so the agent knows this is the policy-level aggregation tool, not a raw verifier.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The examples give concrete use cases (gating invoices, deciding on countersigned contracts, batch-auditing), and the description clarifies it is not a content-truth tool. It names the internal verifiers as components rather than alternatives, but does not explicitly say 'use verify_signatures when you need raw signature details,' so explicit when-not guidance is slightly incomplete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

identify_conformanceIdentify PDF/A / PDF/UA DeclarationsA
Read-onlyIdempotent

Identify declared PDF/A (pdfaid) and PDF/UA (pdfuaid) conformance in a PDF's XMP metadata.

Args:

  • file_path (string): Absolute path to a local PDF file

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: Every report begins with a "scope" object - how far the reading got, not a verdict: whether the cross-reference chain could be walked to the end (chainStop), whether this tool had to rebuild the cross-reference table itself (reconstructed - when true, the table is this tool's reconstruction and not the one the file carries), how many objects and sections were read, and whether an encrypted document could be opened. Read it before the verdict: "no violations" over a rebuilt table is not the same statement as "no violations" over the file's own table.

Declared PDF/A part/conformance level and PDF/UA part, plus the PDF version.

IMPORTANT: This tool only IDENTIFIES the declared conformance — a declaration does not guarantee actual conformance. For real PDF/A rule checking use the validate_conformance tool (native rule subset, or veraPDF when installed).

Examples:

  • Check whether a document claims PDF/A-2b before archiving

  • Detect PDF/UA declarations for accessibility workflows

ParametersJSON Schema
NameRequiredDescriptionDefault
file_pathYesAbsolute path to a local PDF file (e.g., "/path/to/document.pdf")
response_formatNoOutput format: "markdown" for human-readable, "json" for structured datamarkdown

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the description adds valuable context beyond that: it explains the 'scope' object, what chainStop and reconstructed mean, and warns that results over a rebuilt cross-reference table carry different weight. It also mentions encryption handling. This is rich behavioral disclosure not available in annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with distinct sections (Args, Returns, IMPORTANT, Examples) and is front-loaded with the core purpose. Every section earns its place, providing essential context about output semantics and usage. Despite its length, it remains focused and technically precise without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must explain return values. It does so thoroughly, detailing the scope object, the declared conformance fields, and the PDF version. Examples further clarify expected use. Given the tool's complexity and the absence of an output schema, the description is complete enough for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with both file_path and response_format already clearly described, including the enum and default. The description's 'Args' section restates these but doesn't add new meaning beyond the schema. Thus the baseline of 3 applies; no extra semantic value is introduced.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (Identify) and resource (declared PDF/A and PDF/UA conformance in XMP metadata), and explicitly distinguishes itself from validate_conformance by noting it only identifies declarations, not actual conformance. This clearly differentiates it from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly names the alternative tool (validate_conformance) and the exact condition when to use it instead ('for real PDF/A rule checking'), along with examples of appropriate use cases. This leaves no ambiguity about when to select this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_clausesCheck ISO 32000 Clause ConstraintsA
Read-onlyIdempotent

Check a PDF against constraints mapped from ISO 32000-1/-2 clauses — the body of the PDF specification itself, not PDF/A or PDF/UA.

This covers what veraPDF does not look at. veraPDF judges PDF/A and PDF/UA profiles; a document can pass those and still violate ISO 32000 (for example embedding a CFF font program under /FontFile2, which Table 124 forbids).

The mapping and its evaluation live in @shuji-bonji/pdf-constraints; this tool reports which version decided the result. Same file plus same given facts always produce the same result.

Bundled domains: font-embedding, document-metadata, annotation

Args:

  • file_path (string): Absolute path to a local PDF file

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

  • domains (string[], optional): Restrict to specific domains

  • given (object, optional): External facts, e.g. { "isSubset": true }

Returns: Every report begins with a "scope" object - how far the reading got, not a verdict: whether the cross-reference chain could be walked to the end (chainStop), whether this tool had to rebuild the cross-reference table itself (reconstructed - when true, the table is this tool's reconstruction and not the one the file carries), how many objects and sections were read, and whether an encrypted document could be opened. Read it before the verdict: "no violations" over a rebuilt table is not the same statement as "no violations" over the file's own table.

Size (v0.29.0): results lists at most 200 entries (file order); violations and notDecided are counted over all of them and resultsTruncated = { returned, total } says when the list was cut. JSON is never cut by length.

Per-constraint results with the clause IDs they come from. Four states:

  • pass — nothing in this constraint could be disproved

  • fail — disproved, with the fact and its measured value as evidence

  • not_applicable — the clause does not apply to this document

  • needs_external_fact — a fact outside the file was not supplied, so the constraint was not decided (never defaulted into a pass)

Because these are T1 clauses, a failure can be stated plainly and the clause ID quoted — retrieve the wording with pdf-spec-mcp's get_requirements. Failures marked as traces are different: the clause addresses the PDF processor, so the file only shows that someone broke it, not that the last writer did.

Some failures carry a Context note. Those clauses are real and the failure is real, but the industry deviates from them deliberately — text markup QuadPoints are written in Z order by nearly every writer because following the clause literally breaks rendering in major viewers. Pass the context on; a failure reported without it reads as a defect.

Every result also carries observation — how far the reading got: whether the revision chain could be walked to the end, how many objects the cross-reference tables list, and whether the page tree was reached. This is the scope of the verdict, not a verdict. A subject count of zero means "not looked at" when the page tree was not reached; a chain that stopped early means the constraints were applied to part of the file. Read it before the numbers.

A result with no failures is not proof of conformance — only that nothing in the bundled constraints could be disproved.

Examples:

  • Find out why a viewer warns about a font that veraPDF considers fine

  • Check whether Info and XMP agree on the document dates (§14.3.4)

  • Verify a generated PDF before shipping it, beyond the PDF/A profile

ParametersJSON Schema
NameRequiredDescriptionDefault
givenNoFacts that are NOT in the file but are needed to decide some clauses, e.g. { "isSubset": true }. A clause whose applicability depends on a missing fact is reported as needs_external_fact — it is never defaulted into a pass.
domainsNoConstraint domains to apply. Omit to apply all bundled domains (font-embedding, document-metadata, annotation).
file_pathYesAbsolute path to a local PDF file (e.g., "/path/to/document.pdf")
response_formatNoOutput format: "markdown" for human-readable, "json" for structured datamarkdown

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive behavior. The description adds substantial behavioral context beyond that: determinism ('Same file plus same given facts always produce the same result'), result-size limits and truncation semantics (200 entries, resultsTruncated), the reconstruction of the cross-reference table and its meaning, the four decision states including needs_external_fact (never defaulted into pass), and the warning that 'A result with no failures is not proof of conformance'. This is far more transparency than annotations alone provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but appropriate for the tool's complexity. It is front-loaded with the core purpose, then structured into Args, Returns, and Examples. There is some redundancy (e.g., 'observation' is explained multiple times, and the 'scope' warning appears twice), which slightly dilutes conciseness, but each section earns its place by conveying necessary detail for correct invocation and interpretation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema, the description must carry the full burden of explaining return semantics. It does so thoroughly: public scope object, result states, evidence for failures, context notes, traces, truncation, observation fields, and the conformance caveat. For a tool with nested parameters and complex outcomes, nothing essential for correct use is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for all four parameters, giving a baseline of 3. The description adds meaning beyond that: it explains the 'given' parameter as external facts that can yield needs_external_fact outcomes, contextualizes 'domains' as the bundled set (font-embedding, document-metadata, annotation), and clarifies response_format choices. It does not repeat schema details but enriches them with operational consequences.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise verb ('Check') and resource ('a PDF'), then delimits the scope: constraints mapped from ISO 32000-1/-2 clauses, explicitly excluding PDF/A or PDF/UA. It distinguishes itself from veraPDF and sibling conformance tools by pointing out what it covers that they do not. This gives an agent a clear, non-overlapping purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when this tool is appropriate: when veraPDF is insufficient (e.g., 'Find out why a viewer warns about a font that veraPDF considers fine') and for going beyond PDF/A profiles before shipping. It names veraPDF as the alternative for profile checks. It does not explicitly enumerate exclusions for every sibling (signatures, integrity, policy), but the scope definition ('not PDF/A or PDF/UA') and examples make the intended use fairly unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_conformanceValidate PDF/A and PDF/UA ConformanceA
Read-onlyIdempotent

Validate a PDF against a PDF/A flavour (ISO 19005, archiving) or a PDF/UA flavour (ISO 14289, accessibility).

Hybrid engine: when veraPDF is installed (PDF_VERIFY_VERAPDF env var or on PATH) validation is delegated to it for an authoritative result. Otherwise a built-in rule subset is checked natively:

  • PDF/A (15 rules): encryption, file ID, LZW, font embedding, JavaScript/prohibited actions, OutputIntent, transparency for A-1, XFA, and more

  • PDF/UA (12 rules): MarkInfo/Marked, StructTreeRoot, pdfuaid declaration, /Lang, DisplayDocTitle, document title, Figure /Alt, image tagging, heading hierarchy, table TH/TR, Link /Contents

Args:

  • file_path (string): Absolute path to a local PDF file

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

  • flavour (string, optional): e.g. "pdfa-2b", "pdfa-4", "pdfa-4f", "pdfua-1". Defaults to the XMP declaration (PDF/A wins when both are declared; fallback: pdfa-2b). PDF/A-4 has no A/B/U level, so there is no "pdfa-4b"

  • engine ('auto' | 'verapdf' | 'native'): Engine selection (default: 'auto')

  • password (string, optional): Password for an encrypted PDF. PDF/UA validation decrypts the document first so structure rules see real structures; permission-encrypted PDFs (empty user password) are decrypted automatically

When veraPDF does not run, the report says so before the numbers: authoritativeValidation.performed is false and names the reason ("not_installed", "configured_path_unusable" when PDF_VERIFY_VERAPDF points at something that is not executable, or "native_engine_requested"). A configured-but-unusable path is never silently replaced by another executable — with engine: "verapdf" it errors as VERAPDF_NOT_AVAILABLE.

Returns: Every report begins with a "scope" object - how far the reading got, not a verdict: whether the cross-reference chain could be walked to the end (chainStop), whether this tool had to rebuild the cross-reference table itself (reconstructed - when true, the table is this tool's reconstruction and not the one the file carries), how many objects and sections were read, and whether an encrypted document could be opened. Read it before the verdict: "no violations" over a rebuilt table is not the same statement as "no violations" over the file's own table.

Size (v0.29.0): violations lists at most 200 entries; failedRules and compliant are computed over all of them and violationsTruncated = { returned, total } says when the list was cut. JSON is never cut by length.

Per-rule results with ISO clause references. compliant is true/false for veraPDF; for the native engine, false means definitive violations were found and null means "no violations in the checked subset" (NOT certification). PDF/UA native violations carry a severity: only 'error' rules can prove non-conformance, 'warning' rules need human review. For an encrypted PDF that cannot be decrypted, structure-dependent PDF/UA rules are reported in skippedRules (not checked) rather than as violations. The PDF/A font-embedding rule looks at fonts that are actually rendered (text rendering mode 3 is invisible and needs no embedded program, ISO 32000-2 9.3.6); when the content streams cannot be read far enough to tell, that rule is reported in skippedRules instead of guessing.

Note: PDF/UA cannot be fully decided by machine — whether alt text is present is checkable, whether it is meaningful is not. Use pdf-reader-mcp's inspect_tags to examine the structure tree itself.

Examples:

  • Check whether a scanned archive PDF actually meets its declared PDF/A-2b

  • Verify a generated document is tagged and accessible before publishing (pdfua-1)

  • Find why a document fails PDF/A before submitting it to an archive system

ParametersJSON Schema
NameRequiredDescriptionDefault
engineNoValidation engine: "auto" (veraPDF when installed, else native subset), "verapdf" (require veraPDF), "native" (built-in rule subset).auto
flavourNoFlavour to validate against. PDF/A: "pdfa-1b", "pdfa-1a", "pdfa-2b", "pdfa-2u", "pdfa-3b", etc. PDF/A-4 takes no conformance level — use "pdfa-4", or "pdfa-4e" / "pdfa-4f" for the variants ("pdfa-4b" does not exist). PDF/UA: "pdfua-1", "pdfua-2". Omit to use the document's XMP declaration (PDF/A takes precedence when both are declared; falls back to pdfa-2b).
passwordNoPassword for an encrypted PDF (PDF/UA validation only — the document is decrypted before checking structure-dependent rules). Omit for permission-encrypted PDFs (an empty user password is tried automatically).
file_pathYesAbsolute path to a local PDF file (e.g., "/path/to/document.pdf")
response_formatNoOutput format: "markdown" for human-readable, "json" for structured datamarkdown

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, so the description's job is to add context beyond those. It does extensively: explains the hybrid engine selection (veraPDF vs native), how failures are reported (authoritativeValidation.performed and reason), the exact meaning of the 'scope' object, truncation behavior, severity levels for PDF/UA, and the handling of encrypted PDFs. No contradiction with annotations, and it provides a rich behavioral layer well beyond what annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured: it opens with a purpose statement, then engine details, an Args list, Returns section, a Note on limitations, and Examples. Each sentence carries information and there is no redundant padding. While length is high, it is justified by the tool's complexity; it earns a 4 rather than 5 because the length could be slightly tightened without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (hybrid engine, multiple flavours, varied return semantics, and truncation rules), the description is remarkably complete. It explains the return structure ('scope' object, violation list truncation, severity handling), addresses edge cases (encrypted PDFs, missing veraPDF, unreconstructable content streams), and even notes when rules are skipped rather than guessed. With no output schema present, the description carries the full burden of explaining return values, and it does so thoroughly. No important aspect seems missing for an agent to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaningful semantics beyond the schema: it explains default flavour behavior (PDF/A precedence over PDF/UA, fallback to pdfa-2b), engine 'auto' behavior (delegates to veraPDF when installed), encryption handling for password (decryption before structure checks, empty user password tried automatically), and validation rules lists. This goes beyond the schema's terse field descriptions, justifying one point above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool validates PDFs against PDF/A (ISO 19005, archiving) or PDF/UA (ISO 14289, accessibility), giving both the verb and specific resource. It distinguishes itself from likely siblings like identify_conformance (detection) and validate_clauses (different focus) by explicitly focusing on conformance validation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context on when to use the tool (checking archive conformance, verifying accessibility before publishing) and provides three concrete examples. It also notes limitations (PDF/UA cannot be fully decided by machine) and directs users to pdf-reader-mcp's inspect_tags for deeper structure examination. However, it does not explicitly contrast with sibling validation tools, so a half-point is lost.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verify_integrityVerify PDF Integrity (tamper detection)A
Read-onlyIdempotent

Analyze a PDF for modifications after signing.

Reports: number of revisions (incremental updates), whether bytes were added after each signature's signed range, whether the last signature covers the entire file, DocMDP certification permissions and violations, and DSS presence.

DocMDP is assessed against what the P value actually permits (ISO 32000-2 Table 257): P=1 permits nothing, P=2 form fill-in and signing, P=3 additionally annotation creation/deletion/modification. The later changes are classified from the object-level diff (changeClass), so adding an annotation to a P=2 document is reported as a violation while the same change to a P=3 document is not. Objects a permitted change necessarily drags along — the page whose /Annots grew, the catalog, /Info, the XMP stream — are classified as housekeeping and do not by themselves constitute a violation. Per ISO 32000-2 §12.8.2.2, DSS/document-timestamp incremental updates after a P=1 certification are NOT violations (flagged as laterChangesAppearLtvOnly).

violationAssessment is three-valued: "permitted" / "violated" / "indeterminate". "indeterminate" is not a pass — it means the chain could not be walked or a changed object's kind could not be read, so nothing could be disproved. The boolean violatedByLaterChanges collapses indeterminate to false for backward compatibility; read violationAssessment when "could not tell" must not be mistaken for "fine".

Also reports an object-level diff of the incremental-update chain: for each revision, which objects were added, rewritten or freed, with the object's /Type and a plain-language role (annotation, form field widget, page object, content stream, …), plus the shortlist of objects written after the last signed range (objectChangesAfterLastSignature). Cross-reference and object streams are flagged as bookkeeping. Where the objects sit on the page is pdf-reader-mcp's answer, not this server's.

Limits of the diff — it is an observation, never a verdict:

  • Incremental updates are legal in PDF (ISO 32000-2 §7.5.6). A rewritten object says what to review, not that the file was tampered with. No verdict moves because of it.

  • revisions: null means the cross-reference chain could not be walked (revisionChain.status: 'unwalkable') — "not determined", NOT "nothing changed".

  • A non-null revisions list is not necessarily the whole history. revisionChain.status says which it is: 'complete' (walked from the newest cross-reference section back to the original revision), 'partial' (a list came back but revisionChain.missing names the end that is absent), or 'unwalkable' (the case above). revisionChain.missing holds 'oldest' when the chain ended before the original revision, and 'newest' when the last startxref did not point at a parseable section so an older entry point was used and the last append is not listed; both can be absent at once.

  • Only 'complete' makes "no such change appears in the list" mean "that change was not made." With a cut chain the surviving revision is reported as the original one — changeCount: 0, changes: null, objectChangesAfterLastSignature empty — so every other field reads as "nothing was appended". revisions are listed oldest first. Why the chain was cut (a damaged or cyclic /Prev, the revision cap, an unparseable section) stays in notes.

  • Objects stored inside an object stream are listed with inObjectStream: true and no type.

  • revisionCount counts "startxref" keywords; revisions lists the cross-reference sections the chain reached. The two differ lawfully, so revisionCountAgreement says whether the difference is explained: 'agree', 'accounted' (causes names 'linearised' and/or 'chain-incomplete'), or 'unaccounted' — the file holds a startxref the walked chain does not reach, which is the case worth looking at.

  • Linearised files (ISO 32000-2 Annex F) carry two cross-reference sections for one save; they are merged back into one revision rather than reported as an update, so revisionCount is one higher than the number of saves.

Args:

  • file_path (string): Absolute path to a local PDF file

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: Every report begins with a "scope" object - how far the reading got, not a verdict: whether the cross-reference chain could be walked to the end (chainStop), whether this tool had to rebuild the cross-reference table itself (reconstructed - when true, the table is this tool's reconstruction and not the one the file carries), how many objects and sections were read, and whether an encrypted document could be opened. Read it before the verdict: "no violations" over a rebuilt table is not the same statement as "no violations" over the file's own table.

Size (v0.29.0): revisions lists at most 32 revisions (newest first) and 25 changes per revision; revisionsTruncated / changesTruncated say when a list was cut. revisionCount and revisionChain cover the whole walk. JSON is never cut by length.

Integrity report, including revisionChain: { status, missing } — read it before treating the revision list as the file's whole history — and revisionCountAgreement: { status, causes } — read it before quoting revisionCount as the number of times the file was saved. Note that incremental updates after signing are legal in PDF (adding signatures, DSS/LTV data) — findings indicate what to review, not automatically tampering.

Examples:

  • Check whether a signed document was modified after signing

  • Verify a certified (DocMDP) document respects its declared permissions

  • Find out which objects an incremental update touched after a signature was made

ParametersJSON Schema
NameRequiredDescriptionDefault
file_pathYesAbsolute path to a local PDF file (e.g., "/path/to/document.pdf")
response_formatNoOutput format: "markdown" for human-readable, "json" for structured datamarkdown

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnly/idempotent annotations by explaining non-obvious behavior: 'indeterminate' is not a pass, a non-null revisions list may be incomplete, 'unwalkable' means undetermined rather than unchanged, reconstructed cross-reference tables weaken conclusions, and lists can be truncated. It also clarifies that incremental updates are legal and findings are observations, not verdicts. This is exactly the kind of behavioral nuance an agent needs beyond structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though long, the description is dense and well organized: purpose, key outputs, classification rules, limits, argument list, return-scope guidance, and truncation policy. Every section earns its place given the complexity of the tool, and the most decision-critical caveats are emphasized with bold text. It is structured for efficient scanning rather than padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must carry the burden of explaining return semantics, and it does: scope object, revisionChain status values, revisionCountAgreement, violationAssessment values, truncation behavior, and meaningful examples. Given the tool's complexity and the absence of an output schema, nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both file_path and response_format, including the enum and default. The Args section in the description duplicates that information without adding new semantic constraints. Baseline 3 is appropriate because the description does not need to compensate for schema gaps here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: "Analyze a PDF for modifications after signing." It clearly distinguishes this tool from signature-validity or conformance checking by focusing on post-signing modifications, revision history, and tamper-relevant observations. The title reinforces this as tamper detection, and the scope is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when the tool is appropriate: checking whether a signed document was modified after signing, and reviewing integrity findings rather than treating them as automatic tampering verdicts. It also explicitly offloads page-geometry questions to pdf-reader-mcp, which helps an agent decide what this tool is not for. It does not explicitly name sibling tools or state 'use X instead' conditions, so it stops just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verify_signaturesVerify PDF Digital Signatures (cryptographic)A
Read-onlyIdempotent

Cryptographically verify the digital signatures in a PDF document.

For each signature this tool: recomputes the ByteRange digest and compares it with the CMS messageDigest attribute, verifies the CMS/PKCS#7 signature value against the signer certificate, verifies any RFC 3161 signature timestamp, evaluates the certificate chain against trust anchors, and checks revocation status.

Args:

  • file_path (string): Absolute path to a local PDF file

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

  • trust_anchors (string[], optional): Paths to trust anchor certificates (PEM/DER). Also reads the PDF_VERIFY_TRUST_ANCHORS env var (directory).

  • check_revocation ('none' | 'embedded' | 'online'): Revocation mode (default: 'embedded'; 'online' queries OCSP/CRL endpoints over HTTP)

  • revocation_freshness (integer seconds, default 86400): How long before the validation time a CRL / OCSP response may have been issued and still count as "good"

  • trusted_ocsp_responders (string[], optional): Certificates of locally trusted OCSP responders (RFC 6960 §4.2.2.2)

  • password (string, optional): Password for an encrypted PDF (permission-encrypted PDFs are decrypted automatically with the empty user password)

Returns: An object of the form { scope, signatures: [...] }. The top level changed from an array to an object in v0.21.0 - read .signatures for the list.

Size (v0.29.0): a JSON response is never cut by length. At most 32 signature fields are verified (file order); when the file has more, signaturesTruncated = { returned, total } is set and the remaining fields are NOT verified — evaluate_policy verifies every field. A markdown response is cut at 50,000 characters with a visible marker.

Every report begins with a "scope" object - how far the reading got, not a verdict: whether the cross-reference chain could be walked to the end (chainStop), whether this tool had to rebuild the cross-reference table itself (reconstructed - when true, the table is this tool's reconstruction and not the one the file carries), how many objects and sections were read, and whether an encrypted document could be opened. Read it before the verdict: "no violations" over a rebuilt table is not the same statement as "no violations" over the file's own table. For this tool it matters most: when scope.reconstructed is true, a signature the rebuild did not reach is absent from the list, so a short or empty list is not proof that the file carries no other signatures.

Per-signature verdict ('valid' / 'invalid' / 'indeterminate'), trust status ('trusted' / 'untrusted' / 'not_evaluated' with certificate path), revocation status ('good' / 'revoked' / 'revoked_after_validation_time' / 'unknown' / 'not_checked'; 'not_checked' when check_revocation is 'none') with source, origin ('dss' / 'cms_signed_data' / 'cms_revocation_info_archival'), revocationTime, thisUpdate and nextUpdate, per-intermediate-CA results in trust.chainRevocation, validationTime ({ time, source: 'signature_timestamp' | 'document_timestamp' | 'current_time' }), and signature timestamp verification.

Validation time: a verified timestamp (the signature's own, else the earliest document timestamp covering it) or, without one, the current time. The CMS signingTime attribute is written by the signer and is never used. A revoked signer certificate makes the verdict 'indeterminate' unless a timestamp proves the signature predates the revocation (then the status is 'revoked_after_validation_time' and the verdict is unchanged). CRLs and OCSP responses whose signatures cannot be verified, that expired before the validation time, or that were issued more than revocation_freshness seconds before it give 'unknown'.

Note: without trust_anchors (or the env var), trust is reported as not_evaluated — a 'valid' verdict then means cryptographic integrity, not signer identity assurance.

Complements pdf-reader-mcp's inspect_signatures, which inspects structure only.

Examples:

  • Verify a signed contract has not been altered since signing

  • Validate a signature against your organization's CA (trust_anchors)

  • Check whether the signer certificate has been revoked (check_revocation: "online")

ParametersJSON Schema
NameRequiredDescriptionDefault
passwordNoPassword for an encrypted PDF. Omit for permission-encrypted PDFs (an empty user password is tried automatically).
file_pathYesAbsolute path to a local PDF file (e.g., "/path/to/document.pdf")
trust_anchorsNoAbsolute paths to trust anchor certificates (PEM or DER). Merged with the PDF_VERIFY_TRUST_ANCHORS environment variable (a directory of *.pem/*.crt/*.cer/*.der files). When omitted and the env var is unset, trust is reported as not_evaluated.
response_formatNoOutput format: "markdown" for human-readable, "json" for structured datamarkdown
check_revocationNoRevocation checking: "none", "embedded" (OCSP/CRL data inside the PDF/CMS, default), or "online" (additionally query OCSP responders and CRL distribution points over HTTP).embedded
revocation_freshnessNoSeconds before the validation time that a CRL / OCSP response may have been issued (thisUpdate) and still support "good". Default 86400 (24 h); 0 accepts only data issued at or after the validation time. Older data gives "unknown".
trusted_ocsp_respondersNoAbsolute paths to certificates (PEM or DER) of locally trusted OCSP responders (RFC 6960 §4.2.2.2). A response signed by one of them is accepted even when the responder is not the issuing CA or its delegate.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the annotations by disclosing exact verification behavior: digest recomputation, CMS verification, timestamp validation, trust-chain evaluation, revocation modes, scope.reconstructed semantics, response truncation, and validation-time rules. It also clarifies that without trust_anchors, trust is not_evaluated. No annotation contradiction exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured: purpose, Args, Returns, behavioral caveats, alternatives, examples. The front-loaded core sentence and clear headings help an agent locate relevant sections quickly. Some redundancy exists between Args and the input schema descriptions, but the overall organization earns its length for a complex verification tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description explains the return shape in detail, including scope semantics, per-signature status fields, truncation behavior, validation-time selection, and trust-anchor implications. It also covers important edge cases like rebuilt cross-reference tables and revoked certificates. This is complete enough for an agent to call the tool correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description largely restates the schema's parameter descriptions rather than adding substantially new semantics. Some context is added (e.g., trust env var behavior, RFC 6960 reference), but most parameter-meaning is already present in the input schema, so the description does not meaningfully compensate beyond the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource: 'Cryptographically verify the digital signatures in a PDF document.' The title reinforces the scope, and the description distinguishes it from structural inspection by naming inspect_signatures, which 'inspects structure only.' The purpose is unambiguous and differentiates the tool's role from the listed siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context through the cryptographic verification steps, the note that inspect_signatures is structural only, and three concrete example use cases (integrity check, trust anchor validation, revocation checking). It does not explicitly enumerate exclusions for every sibling tool, so it stops short of a 5, but the guidance is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv0.29.1
    • First observeddetect_pades_level
    • First observedevaluate_policy
    • First observedidentify_conformance
    • First observedvalidate_clauses
    • First observedvalidate_conformance
    • First observedverify_integrity
    • First observedverify_signatures

TDQS

A4.7/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a distinct aspect of PDF verification: signature cryptography, integrity analysis, PAdES level detection, conformance identification, conformance validation, ISO clause checking, and policy evaluation. Even the related identify_conformance and validate_conformance are clearly separated by their stated purpose (declaration vs. actual validation).

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case: detect_pades_level, verify_signatures, verify_integrity, identify_conformance, validate_conformance, validate_clauses, evaluate_policy. The verbs (detect, verify, identify, validate, evaluate) are semantically appropriate and used consistently.

Tool Count5/5

With 7 tools, the server is well-scoped for its purpose of PDF verification. Each tool covers a distinct functional area needed for comprehensive document trust evaluation, and the set is neither sparse nor bloated.

Completeness5/5

The tool surface covers the full verification lifecycle: signature cryptographic verification, integrity/modification analysis, PAdES level detection, declared conformance identification, PDF/A-UGUA validation against external and native engines, ISO 32000 clause checking, and a composite policy verdict. No dead ends or obvious missing operations within the stated domain.

Maintenance

ActivityNo data
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables AI-powered extraction and analysis of PDF documents with 40+ specialized tools for text, tables, images, layout analysis, security assessment, and document intelligence. Supports both text-based and scanned PDFs with OCR capabilities.
    134 PyPI
    10
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables PDF document processing including text, image, and table extraction, as well as intelligent classification and similarity analysis across multiple languages.
    49
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables PDF processing and analysis including text extraction, metadata retrieval, search, page manipulation, splitting/merging, conversion to images, and form handling.
    10
    MIT