mcpField
P
PDF Verify (PDF Agent Stack)

PDF Verify (PDF Agent Stack)

本地服务
shuji-bonji.github.io安全02 周前更新

关于 PDF Verify (PDF Agent Stack)

PDF Verify 是用于验证 PDF 真实性与规范符合性的 MCP 服务,面向需要检查签名、篡改和文档标准的工作流。它结合密码学验证、修订变更分析与策略评估,并区分无法判定与通过。

主要功能

  1. 01验证数字签名及信任链
  2. 02检测签署后的文档变更
  3. 03识别 PAdES 基线等级
  4. 04验证 PDF/A 与 PDF/UA 符合性
  5. 05按规则评估信任策略

适用场景

  1. 01核验合同或财务 PDF 签名
  2. 02检查签署后是否发生未授权更改
  3. 03验证归档文件的 PDF/A 符合性
  4. 04按领域策略筛查文档风险

MCP 相关

PDF Verify 提供 MCP 工具,用于签名与完整性验证、PAdES 检测、符合性识别和验证、条款检查及策略评估。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"shuji-bonji-pdf-verify": {
"command": "npx",
"args": [
"-y",
"@shuji-bonji/pdf-verify-mcp"
]
}
}
}
启动命令npx -y @shuji-bonji/pdf-verify-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@shuji-bonji/pdf-verify-mcp0.31.0

工具

7

收录的工具列表 · 更新于 2 周前

参数类型必填说明
passwordstring否加密 PDF 的密码。对于权限加密的 PDF 可省略(会自动尝试使用空用户密码)。
file_pathstring是本地 PDF 文件的绝对路径(例如,"/path/to/document.pdf")
trust_anchorsarray否信任锚证书的绝对路径(PEM 或 DER)。与 PDF_VERIFY_TRUST_ANCHORS 环境变量合并使用(指向包含 *.pem/*.crt/*.cer/*.der 文件的目录)。省略且未设置环境变量时,信任状态报告为 not_evaluated。
response_formatenum否输出格式:"markdown" 表示便于阅读,"json" 表示结构化数据markdown | json
check_revocationenum否吊销检查:“none”、“embedded”(PDF/CMS 中的 OCSP/CRL 数据,默认)或“online”(还会通过 HTTP 查询 OCSP 响应程序和 CRL 分发点)。none | embedded | online
revocation_freshnessinteger否验证时间之前 CRL / OCSP 响应可签发的秒数(thisUpdate),且仍可支持“good”。默认值为 86400(24 h);0 表示仅接受在验证时间或之后签发的数据。较早的数据会返回“unknown”。
trusted_ocsp_respondersarray否本地信任的 OCSP 响应者证书(PEM 或 DER)的绝对路径(RFC 6960 §4.2.2.2)。即使响应者不是签发 CA 或其委托方,由其中一个响应者签名的响应也会被接受。

详细介绍

pdf-verify-mcp

CI npm version License: MIT

日本語

用于 PDF 真实性与合规性验证的 MCP 服务——包括加密数字签名验证、篡改检测、PAdES 基线级别检测,以及 PDF/A(ISO 19005)/ PDF/UA(ISO 14289)验证。

与 pdf-reader-mcp(结构分析)和 pdf-spec-mcp(规范参考)同属 PDF 系列。pdf-reader-mcp 告诉你 PDF 包含什么,而 pdf-verify-mcp 告诉你它是否真实有效。

工具

工具用途
verify_signatures加密验证、根据信任锚评估信任链、吊销检查(嵌入式 OCSP/CRL 或在线检查)、RFC 3161 时间戳验证
verify_integrity篡改检测:增量更新、签名后的更改、按 P 值评估 DocMDP 认证违规(见下文),以及修订链的对象级差异(每次更新添加、重写或释放了哪些对象)。增量更新是合法的,因此差异用于指出需要审查的内容——不会据此作出任何判定。要了解这些对象在页面上的位置,请使用 pdf-reader-mcp 的 locate_objects
detect_pades_levelPAdES 基线级别(B-B / B-T / B-LT / B-LTA),包含经过内容验证的 LTV 数据
identify_conformance从 XMP 元数据识别声明的 PDF/A / PDF/UA 合规性
validate_conformancePDF/A(ISO 19005)和 PDF/UA(ISO 14289)验证:安装了 veraPDF 时使用 veraPDF,否则使用内置规则子集
validate_clauses映射自 ISO 32000-1/-2 条款的约束——即规范正文本身,而 PDF/A 和 PDF/UA 配置文件并未涵盖这部分内容
evaluate_policy根据固定规则表中的验证事实,给出确定性的 4 值信任判定(trust_and_use / use_with_caution / human_review_required / reject),并支持领域配置文件(合同、金融、法律、医疗、政府)。判定逻辑由代码实现;叙述说明由大模型生成

判定结果

判定结果含义
validByteRange 摘要匹配,且 CMS 签名在加密层面有效
invalid摘要不匹配或签名验证失败——可能遭到篡改
indeterminate格式不受支持,或无法完成验证

DocMDP 认证权限(v0.14)

认证签名的 P 值说明允许哪些类型的更改 (ISO 32000-2 表 257)。verify_integrity 会在对象级别对签名后的更改进行分类,并将其与 P 值允许的更改进行比较。

P允许的更改添加注释是否违规?
1无(DSS / 文档时间戳增量更新是 §12.8.2.2 中的例外)是
2填写表单、实例化页面模板、签名是——注释从 3 开始
3与 2 相同,另允许创建、删除和修改注释否

允许的更改必然会连带修改的对象——/Annots 增多的页面、目录、/Info、XMP 流——会被归类为 housekeeping,不计为违规。如果将它们计入,就会导致每个经过认证的文档都违规,因为合法的 P=3 注释添加会连带修改这四个对象。

violationAssessment 为三值
值含义
permitted签署后的所有变更均属于 P 允许的类型
violated至少有一项变更不属于允许范围
indeterminate无法确定(无法遍历 xref 链,或无法读取已变更对象的类型)

⚠️ indeterminate 不代表通过。 此服务会推翻结论,而「无法推翻」与「没有问题」是不同的说法——这与 validate_clauses 返回 needs_external_fact,而不是默认将检查判为通过,遵循的是同一原则。

为保持兼容,violatedByLaterChanges(布尔值)会将 indeterminate 归并为 false。凡是「无法判断」不能被误认为「没有问题」的场景,请使用 violationAssessment。evaluate_policy 也会将 indeterminate 提升为 human_review_required。

没有 /Type 的裸流会被视为未确定,而不是 content:相同的字节可能是表单字段的外观流(P=2 允许),也可能是页面内容流(任何 P 都不允许)。

响应大小(v0.29.0)

JSON 响应不会因长度而截断。列表会设上限,且每处截断都会在列表旁报告 { returned, total }:signatures / levels 上限为 32(verify_signatures 不会验证超出上限的字段;evaluate_policy 会验证全部字段,但仅限制 facts.signatures),revisions 上限为 32,violations / results 上限为 200(compliant、failedRules、violations、notDecided 等计数涵盖所有条目)。Markdown 响应会在 50,000 个字符处截断,并显示标记。

evaluate_policy 中的内容清单(v0.30.0)

evaluate_policy 还会统计文档中可执行或尚未完成的内容,并在 facts.content 下报告——即 ISO 32000-2 §12.8.7 表 264(法律内容证明)中的计数:JavaScriptActions、LaunchActions、URIActions、GoToRemoteActions、HideAnnotationActions、MovieActions、SoundActions,以及 SubmitFormActions、URI 主机、是否存在 /OpenAction 或文档级 /AA、批注数量,以及文件中仍存在的 /Subtype /Redact 批注数量。会遍历嵌套的(直接)动作字典,因此链接上的内联 /A 也会计入。两条规则会读取该清单:

  • POL-CAUTION-REDACT-PENDING — 仍存在涂黑批注(ISO 32000-2 §12.5.6.23)。已应用的涂黑不会留下批注,因此其标记的内容尚未从文件中移除。use_with_caution。
  • POL-CAUTION-ACTIVE-CONTENT — 存在 ECMAScript、Launch、远程跳转或 SubmitForm/ImportData 动作;原因会说明 /OpenAction / /AA 是否会使其中某些动作在打开时运行。use_with_caution。URI 动作不会改变判定结果;其主机名会列入提示信息。

清单是观测结果,而非判定结果:若结果为 null(无法获取),会报告为「未计数」,绝不会报告为 0;无法读取的对象会使计数成为下限。表 264 中未计数的键:AlternateImages、ExternalStreams、TrueTypeFonts、ExternalRefXobjects、ExternalOPIdicts、NonEmbeddedFonts、DevDepGS_*。

信任与撤销(v0.2)

传入 trust_anchors(PEM/DER 文件路径),或设置 PDF_VERIFY_TRUST_ANCHORS 环境变量(证书目录),以评估签名者的证书链:结果为 trusted / untrusted / not_evaluated,并附带证书路径。验证时间依次取已验证的签名时间戳、覆盖该签名的最早文档时间戳,或当前时间(v0.27.0);CMS signingTime 属性由签名者写入,不会用于验证。所选时间会以 validationTime 报告。

check_revocation 控制撤销检查:embedded(默认值——DSS、CMS SignedData.crls 或 CMS 签名属性 adbe-revocationInfoArchival 中的 OCSP/CRL 数据;以 revocation.origin 报告)、online(还会通过 HTTP 查询 OCSP 响应器和 CRL 分发点),或 none(revocation.status: not_checked)。如果 CRL 和 OCSP 响应的签名无法验证、其 nextUpdate 早于验证时间,或其 thisUpdate 比验证时间早超过 revocation_freshness 秒(默认值为 86400),结果将为 unknown(v0.28.0)。传入 trusted_ocsp_responders 可信任由其他 CA 签发的 OCSP 响应器。每个中间 CA 的结果都会在 trust.chainRevocation 中报告。如果时间戳能证明签名早于撤销时间,则已撤销的签名者证书会得到 revoked_after_validation_time(判定结果不变);否则结果为 revoked,判定为 indeterminate。在 online 模式下,会通过 AIA caIssuers 获取缺失的颁发者证书以补全证书链(v0.4)。提供信任锚时,也会评估 RFC 3161 时间戳的 TSA 证书链(tsaTrust)。

步骤检查内容网络
完整性/ByteRange 哈希与 CMS messageDigest 匹配无
签名值使用签名者证书的公钥验证签名值无
证书链链接至信任锚仅 online:通过 AIA caIssuers 获取颁发者证书
撤销签名者证书的 OCSP / CRLembedded 模式下无;online 模式下,嵌入数据无法给出结果时会通过 HTTP 查询
时间戳RFC 3161 令牌和 TSA 签名无

verdict: valid 表示完整性和签名值检查均通过(revoked 会使其变为 indeterminate)。online 结果反映 CA 在查询时的状态,之后可能发生变化。有关每个步骤及如何选择模式,请参阅站点指南。

未提供信任锚时,trust 保持为 not_evaluated;valid 判定表示密码学完整性有效,而非签名者身份有效。

权限加密的 PDF(用户密码为空)会自动解密;对于阅读器密码保护的 PDF,请传入 password。支持:RC4(R2–R4)、AES-128、AES-256(R6)。解密会还原字符串元数据(字段名称、/M、/Reason、/Location)和 XMP——签名的 /Contents 不加密,因此验证不会依赖它。

支持的 SubFilter:ETSI.CAdES.detached(PAdES)、adbe.pkcs7.detached、ETSI.RFC3161(文档时间戳)。RFC 3161 签名时间戳会经过完整验证(摘要值 + TSA 签名)。旧版 MD5/SHA-1 签名通过 node:crypto 验证,并标记为弱签名。

PDF/A 验证(v0.3)

validate_conformance 使用混合引擎。安装了 veraPDF 时(通过 PDF_VERIFY_VERAPDF 环境变量指定或位于 PATH 中),验证会交由它执行,以获得权威结果。否则,内置的约 15 条高价值 ISO 19005 规则会在本地运行(加密、尾部 /ID、LZW、字体嵌入、JavaScript/禁止的操作、OutputIntent、A-1 的透明度、XFA 等),并逐条报告对应的条款编号。

本地结果会如实说明其局限:发现违规意味着确定不符合要求;全部通过则表示“已检查的子集中未发现违规”,绝不等同于认证。

接受 PDF/A-4(pdfa-4、pdfa-4e、pdfa-4f)。请注意,PDF/A-4 没有符合性级别——不存在 pdfa-4b;e 和 f 是变体。本地规则依据 ISO 19005-1/-2 编写,尚未根据 ISO 19005-4 检查,因此 PDF/A-4 报告会明确说明本地判定的权威性低于 veraPDF。请使用 veraPDF 验证第 4 部分。

XMP 扩展架构和 TDMRep(v0.31.0)

ISO 19005 仅在 XMP 属性的架构为预定义架构(XMP Specification、pdfaid),或通过数据包中的 pdfaExtension:schemas 描述时,才接受该属性(19005-1 6.7.8、19005-2/-3/-4 6.6.2.3)。veraPDF 会将违规报告为“XMP property is either not predefined, or is not defined in any XMP extension schema”,并仅在检查上下文中指出命名空间。从 v0.31.0 起,validate_conformance 会将该名称写入违规项的 detail——例如 http://www.w3.org/ns/tdmrep/ (tdm:reservation, tdm:policy) — W3C TDM Reservation Protocol (TDMRep): …——并说明二者如何共存:只要数据包描述了 TDMRep 架构(reservation 为 Integer,policy 为 URL),PDF/A 与 TDMRep 就兼容。identify_conformance 会列出数据包声明的所有命名空间,并标记为预定义 / 已描述 / 已知;声明了 PDF/A 时,还会指出未描述的命名空间。evaluate_policy 会在建议中重述具体原因。使用 veraPDF 1.28.2 测得:包含 TDMRep 且没有扩展架构的 PDF/A-3B 数据包,其两个属性在 6.6.2.3.1 test1 和 test2 中均未通过;同一数据包若包含架构描述,则不会触发 XMP 失败。

ISO 32000 条款约束(v0.9)

validate_clauses 检查的是另一部分:PDF 规范正文,而非 PDF/A 或 PDF/UA 配置文件。文件即使被 veraPDF 判定为 COMPLIANT,仍可能违反 ISO 32000——例如在 /FontFile2 下嵌入 CFF 字体程序(表 124),这是一个真实案例,只在查看器警告中显现。

条款与结构条件之间的映射及其评估由 @shuji-bonji/pdf-constraints 提供。每份报告都会注明作出判定的版本,因为规则会随着约束的增加而变化。

每项约束会得到以下四种状态之一:

状态含义
pass无法证伪此约束中的任何内容
fail已证伪,并以事实及其测量值作为证据
not_applicable此条款不适用于该文档
needs_external_fact未提供文件之外的事实,因此尚未判定此约束

报告会刻意区分两件事:

  • needs_external_fact 不代表通过。 只有创建字体的人才知道它是否为子集——PDF 并未说明。可通过 given: { isSubset: true } 提供此信息;若不提供,约束会降低判定结果,而不会默认静默通过。
  • 有些失败是痕迹,而非违规。 如果条款针对的是 PDF 处理器(写入文件的行为),文件最多只能表明有人违反了条款——§14.3.4 明确允许保留已有的不一致,因此最后写入文件的人不一定有错。

这些属于 T1 条款,因此可以直接陈述失败,并引用条款 ID——使用 pdf-spec-mcp 的 get_requirements 获取条款原文。

PDF/UA 验证(v0.6)

传入 flavour: "pdfua-1"(或 "pdfua-2"),即可根据 ISO 14289 验证无障碍合规性。若已安装 veraPDF,则会通过 --flavour ua1 调用它;否则将运行 12 条原生规则:MarkInfo/Marked、StructTreeRoot、pdfuaid 声明、/Lang、DisplayDocTitle、文档标题、Figure /Alt、图像标记、标题层级、表格 TH/TR、Link /Contents 和加密屏障。标签通过 /RoleMap 解析。

PDF/UA 原生违规项带有 severity:只有 error 规则才能证明不合规,而 warning 规则会标记需要人工审核的内容。无障碍性无法完全通过机器判定——是否存在替代文本可以检查,是否有意义则无法检查。

原生子集的能力止于 pdf-lib 所及之处。需要分析内容流的规则——7.1-3(内容标记为 artifact 或带标签)、7.2-34(页面内容的语言)、7.18.1-1(嵌套在 Annot 标签中的注释)、7.18.3-1(/Tabs)——交由 veraPDF 处理,而不做近似判断。重视无障碍性时,请安装 veraPDF。

如果未显式指定 flavour,则仅当文档声明为 PDF/UA 且未声明为 PDF/A 时,才会选择 PDF/UA。使用 pdf-reader-mcp 的 inspect_tags 检查结构树本身;合规性判断在此完成。

安装

作为插件安装(通过 shuji-bonji/claude-plugins 市场,推荐):

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

或直接添加到 MCP 配置中:

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

请使用 @latest(或固定版本)。 不带版本号运行 npx -y <pkg> 时,会一直运行首次缓存的版本——-y 仅跳过安装提示,不会检查更新。要清除过期缓存:rm -rf ~/.npm/_npx。

使用示例

  • “验证 /path/to/contract.pdf 中的签名——签名后是否被篡改?”
  • “这份经过认证的 PDF 在认证后是否被修改?”
  • “此签名是否启用了 LTV(B-LT 或 B-LTA)?”
  • “此文档是否声明符合 PDF/A-2b?”

开发

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/

测试夹具(自签名证书 + 已签名 PDF)通过 pkijs + WebCrypto 以编程方式生成——仓库中不含二进制资源。

许可证

MIT © shuji-bonji

依赖项:pkijs / asn1js(BSD-3-Clause)、pdf-lib(MIT)、normativepdf(MIT)、@shuji-bonji/pdf-constraints(MIT)、@modelcontextprotocol/sdk(MIT)、zod(MIT)。

交叉引用章节由 normativepdf 读取。这是一个以条款为驱动的 PDF 库,每种行为都与 ISO 32000 中的条款绑定。它很严格——无法读取的章节在其中会被视为错误。损坏文件的恢复策略(回退到较早的 startxref、限制循环 /Prev 链的长度、将线性化文件的两个章节合并回一次保存)保留在此服务中,因为这属于取证判断,而非对规范的解读。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。