关于 Verify SCITT receipts from Forestrie transparency logs, offline
@forestrie/mcp-verify 是用于离线验证 Forestrie 透明日志 SCITT 收据的 MCP 服务,面向需要核验声明来源和日志记录的 Agent。它依据调用方持有的信任根在本地检查收据,不连接后端或网络。
主要功能
- 01验证 SCITT 收据
- 02验证授权收据
- 03检查软件自身发布收据
- 04解码 CBOR 收据
- 05提供内置测试资源
适用场景
- 01离线核验声明是否写入日志
- 02检查签署者是否获准提交
- 03验证软件包发布来源
- 04使用内置资源运行收据验证
MCP 相关
通过 MCP 提供验证和解码收据的只读工具,并提供可供验证调用的 fixtures 资源。服务仅使用 stdio 传输,不进行网络访问。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
4收录的工具列表 · 更新于 1 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| trust | any | 是 | 你愿意信任的锚点 |
| entryId | string | 是 | 32 位小写十六进制:idtimestamp_be8 || mmrIndex_be8 |
| payload | any | 是 | EXACT 注册 payload 字节,其 SHA-256 是叶子 ContentHash — {b64: <standard base64>}(base64 可用作别名),或 {path: <本地服务读取的文件>} |
| receipt | any | 是 | 要渲染的 COSE 收据 — {b64: <standard base64>}(base64 可用作别名),或 {path: <本地服务读取的文件>} |
详细介绍
@forestrie/mcp-verify
在你持有的信任根下,验证来自 Forestrie 透明日志的 SCITT 收据。离线运行:无需后端、账号、密钥或网络。 一个仅提供收据验证和解码工具的 MCP 服务。
{
"mcpServers": {
"forestrie-verify": {
"command": "npx",
"args": ["-y", "@forestrie/mcp-verify"]
}
}
}
npx -y @forestrie/mcp-verify demo
原因
Agent 会依据自己未见证过的陈述采取行动:报价、批准、工具结果或其他 Agent 的输出。通常,说过的话由说话方保存,因此下游无人能问:“你真的这么说了吗?你是对所有人都这么说的吗?”
Forestrie 收据是一个证明,表明某项陈述已封存到一个只追加的透明日志中。此软件包会在你自己的进程中,依据你持有的信任根检查该证明,不会联系 Forestrie。使用正确的信任根,它还能回答更棘手的问题:你看到的日志是否就是其他人看到的日志。关于透明度能增加什么、其局限在哪里,以及收据包含什么:TRANSPARENCY.md。
它能证明什么
| 工具 | 参考命令 | 它回答的问题 |
|---|---|---|
verify_receipt | forestrie verify | 这些确切的载荷字节是否已按序列写入此条目 ID? |
verify_grant_receipt | forestrie verify-grant | 此授权是否已获准写入此日志——也就是说,签署者是否有权写入? |
verify_self | forestrie verify | 此软件包自身的发布收据是否能为其随附的字节作证? |
decode_receipt | forestrie decode-receipt --json | 此收据中实际包含什么?(仅渲染 CBOR,不执行任何验证。) |
每个工具都标注为 readOnlyHint: true, openWorldHint: false。这不是装饰:它是“此工具不会触及任何东西”的机器可读形式,Agent 无需运行任何内容就能看到这一点。
信任根
你不要求“验证”,而是指定你信任哪个根,结果会说明该根能看到什么:
| 根 | 你提供的内容 |
|---|---|
genesis | 森林的创世文档,即注册时捕获的文档 |
known-log-key | 你通过带外方式持有的日志所有者密钥(keyXy,P-256)或 KS256 地址(ks256Address) |
known-accumulator | 从链上读取的日志峰值快照 |
checkpoint-chain | 保留的 .sth 检查点链,以及 genesis 或 keyXy;会对每个链接强制执行委托限制 |
KS256(secp256k1)根也支持离线验证。EOA 根通过 ecrecover 验证,依据的是 genesis,或带有 ks256Address 的 known-log-key。合约根(Safe)无法在不读取链的情况下检查,而此软件包绝不会读取链:请传入 ks256Attestation,这是从其他地方获取的 ERC-1271 记录(通过 @forestrie/mcp-resolve 的 fetch_ks256_attestation 工具,或 forestrie-cli 的 fetch-ks256-attestation 获取)。此时结果在_证明所对应区块的合约签名者所授权的范围内_有效,并会说明该区块。20 字节的 ks256Address 只是声明了某个日志归其所有,并不能证明这一点。checkpoint-chain 也接受 ks256Attestation,并需要用于森林链 ID 的 KS256 genesis;一份证明只覆盖一张委托证书,因此 Safe 若更换过委托方,每张证书都需要一份证明:请将它们作为 ks256Attestations 数组传入。结果会报告每份证明是已使用,还是未使用并说明原因;不会静默忽略任何证明。checkpoint-chain 还会强制执行每个链接的委托限制(mmrStart、mmrEnd、expiresAt):delegation_out_of_range、delegation_expired。从 0.7.0 开始,回执附带的峰值会根据叶子和包含路径进行检查,而不再被直接信任(@forestrie/receipt-verify 3.2.0),从而堵住了 known-accumulator 和 checkpoint-chain 信任根中的一个漏洞。详情:docs/trust-roots.md。
这些根并非按强弱排序。前两个会在本地检查操作者的签名,但无法发现视图分裂。后两个会将峰值与操作者无法控制的累加器进行比对,因此能够发现视图分裂。每个结果都会回答四个问题:封存、视图分裂、追加权限和归属,每项结果为 ok、failed 或 not_answered_by_this_root。最后一种也是真实的回答,必须传达给用户;客户端若只呈现 ok,就是错误地使用了此工具。
各信任根在何种情况下是合适的选择、为什么在检查时获取的创世文档不如注册时留存的文档可靠、签名根无法区分什么,以及演示记录,请参阅: docs/trust-roots.md。
无需信任运营方
即使不假设 Forestrie 运营方诚实,收据依然有意义:
- 管道,而非存储。 日志中只记录内容哈希。你的声明和收据由你保管;验证只针对这些字节进行,因此检查时无需向运营方索取任何内容。
- 运营方不掌握权力。 日志的根密钥属于日志所有者;实例引导密钥属于部署森林合约的人。运营方的封存密钥仅为租用了该密钥的日志签署检查点,且仅限于各租约的 MMR 范围内。
- 一份已发布的历史记录。 检查点会发布到 univocity 合约,该合约会拒绝任何与其现有记录不一致的检查点。上面的累加器根会针对这些记录进行检查。
运营方仍可以拒绝行动,而且这一点是可见的:它可以拒绝接纳、扣留其提供的数据,或停止封存。但它无法改写或分叉已锚定的历史记录,也无法为未租用其密钥的日志签名。关于谁持有哪些密钥,以及运营方能做什么、不能做什么,请参阅 密钥托管 和 运营方权限。
本软件包自身的来源证明
软件来源证明是透明日志的常见用途,因此本软件包也将其应用于自身。每次发布都会在 Forestrie 日志中登记一份简短声明(软件包名称、版本、git 提交),并将收据随 tarball 一并发布。npx -y @forestrie/mcp-verify verify --self 或 verify_self 工具可以离线验证该收据。这是对 npm 的 SLSA 来源证明的补充,并不取代它。目前,该收据会链接到公共开发通道上的日志。详情请参阅:docs/self-registration.md。
该捆绑包也是一个完整示例:从公共通道获取本软件包自身发布的收据,使用随包提供的密钥进行验证,在 genesis 根下看到有文档说明的 delegation_invalid,并通过链读取得到 split-view ok——端到端只需几秒钟,且无需账户。该示例位于
@forestrie/mcp-resolve 的 README,
因为获取工作属于该软件包,而非本软件包。
验证运算来自 @forestrie/receipt-verify,该依赖固定到确切版本,并单独发布和认证。tarball 中包含 src 和用于测试的冻结一致性测试向量
(fixtures/PROVENANCE.md),因此可以重新运行这些运算,而不是盲目信任。
安装本软件包会引入验证器所需内容之外的依赖。@modelcontextprotocol/sdk 会带入包括 express、hono、jose、cors 和 ajv 在内的 Web 技术栈,供本软件包从未使用的 HTTP 传输使用:本软件包只构建 stdio 传输。验证核心从不导入 SDK,浏览器安全检查也会强制确保这一点,因此导入本软件包的 "." 导出即可使用这些运算,而无需引入上述依赖。
打包的资源,以及它们支持运行的两个调用
tarball 将其测试夹具作为 forestrie://fixtures/… MCP 资源提供,
因此,即使 Agent 没有自己的任何资源,也能进行真实验证。
仅凭资源就能通过的调用有两个;二者均由
test/node/mcp-smoke.test.ts 断言。
位于创世根的授权收据 — 使用以下参数调用 verify_grant_receipt:
| 参数 | 资源 |
|---|---|
receipt | golden/grant-receipt.cbor |
committedGrant | golden/committed-grant.cbor(读取时根据 golden/manifest.json 派生) |
entryId | golden/entry-id.txt 的文本 |
trust | {root: "genesis", genesis: golden/grant-genesis.cbor} |
结果:verify-grant: PASS · root=genesis · sealing ok, split-view not answered at this root, append-authority ok, attribution ok。
离线地,针对真实锚点,在累加器根验证载荷收据 — 使用 lane-A 资源包
(fixtures/lane-a/PROVENANCE.md) 调用 verify_receipt:这是来自公共通道的真实收据,以及单值性合约为其日志在区块 46770471 处发布的累加器,该数据由独立链上读取获取。
(该通道的内容已于 2026-09-20 重置;这些字节仍可验证,但它们来源的 URL 已无法访问。)
| 参数 | 资源 |
|---|---|
receipt | lane-a/receipt.cbor |
payload | lane-a/statement.cose |
entryId | lane-a/entry-id.txt 的文本 |
trust | {root: "known-accumulator", accumulator: lane-a/accumulator.cbor} |
结果:verify: PASS · root=known-accumulator · sealing ok, split-view ok, append-authority ok, attribution ok,且 anchor.matchedPeak 已设置。
与 demo 的自派生快照不同,此锚点是合约发布的状态,因此 split-view 答案是截至该区块的证据。
同一收据在 {root: "known-log-key", keyXy: {b64: <text of lane-a/log-key.xy.b64>}} 下也能通过;在
{root: "genesis", genesis: lane-a/genesis.cbor} 下则会报告
delegation_invalid,因为其日志是森林根的孙节点(docs/self-registration.md)。
资源的字节会以 {b64: <the blob>} 的形式传回;像
lane-a/log-key.xy.b64 这样的文本资源本身已经是 base64 文本,因此其文本可原样放入 b64。
golden/burial/public-key.xy.b64 以同样方式提供埋葬链的根密钥,因此可用资源驱动
checkpoint-chain — 得到文档所述的否定判定,因为埋葬资源包没有提供叶节点原像。
注册表
此服务在官方 MCP 注册表中列为 dev.forestrie/verify。
开发
mise install # node 22.14.0, pnpm 10.6.5
pnpm install
pnpm test # browser-safe gate + encoding-copy gate + server.json gate + unit tests
pnpm build
约定、不变量和发布检查清单:AGENTS.md。
许可证
MIT。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。