AI Agent 治理工具包:MCP 工具调用的离线可验证决策收据(mcp-receipt-governed)实战指南
【免费下载链接】agent-governance-toolkitAI Agent Governance Toolkit — Policy enforcement, zero-trust identity, execution sandboxing, and reliability engineering for autonomous AI agents. Covers 10/10 OWASP Agentic Top 10.项目地址: https://gitcode.com/GitHub_Trending/ag/agent-governance-toolkit
本文基于 agent-governance-toolkit 仓库中的 Tutorial 33《Offline-Verifiable Decision Receipts》编写,围绕
mcp-receipt-governed适配器展开。该组件为每一个 MCP(Model Context Protocol)工具调用生成带签名的治理收据(governance receipt),将 Cedar 策略决策、工具参数哈希与 Agent 身份 DID 绑定在一起,并支持在完全离线的环境下验证整条收据链的完整性与真实性。读完本文,你将掌握:如何安装适配器、如何用 Ed25519 对 RFC 8785 规范化载荷签名、如何通过哈希链检测收据的插入/删除/篡改、如何用 CLI 离线验链,以及如何将收据输出为 SLSA v1.0 provenance 供供应链验证工具消费。
背景:为什么每个工具调用都需要一张"可离线验证"的收据
在 AI Agent 治理场景中,一次 MCP 工具调用(读文件、删文件、发邮件……)往往发生在多云、多租户、跨组织的分布式环境里。仅仅"当时做了策略判断"是不够的——事后审计、合规取证、供应链安全验证都需要一份独立于原始基础设施的、第三方可以自行验证的证据。
mcp-receipt-governed的目标正是如此:把"Cedar 策略决策 + MCP 工具名与参数 + Agent DID"打包成一份结构化的GovernanceReceipt,用 Ed25519 私钥签名后写入哈希链。任何第三方拿到导出的 JSON,无需访问 AGT 基础设施、无需联网,即可验证:
- 每条收据的签名是否真实(Ed25519 / RFC 8032);
- 收据内容是否被篡改(签名 + 载荷哈希);
- 收据链是否连续(有没有被插入或删除伪造记录)。
该模块位于 agent-governance-python/agentmesh-integrations/mcp-receipt-governed/,包名为agentmesh_mcp_receipts(见 pyproject.toml),要求 Python 3.11+,底层加密依赖cryptography。
一、安装:核心适配器与 Ed25519 加密扩展
安装分两种场景:
# 核心适配器(无加密——verify_receipt() 恒返回 False) pip install -e agent-governance-python/agentmesh-integrations/mcp-receipt-governed # 带 Ed25519 签名与验证(推荐) pip install -e "agent-governance-python/agentmesh-integrations/mcp-receipt-governed[crypto]"两条命令的区别对应 pyproject.toml 中的可选依赖声明:
| 依赖组 | 内容 | 用途 |
|---|---|---|
| 默认(dependencies) | 空 | 适配器核心逻辑:策略评估、收据构造、哈希链 |
[crypto] | cryptography>=46.0.7,<48.0 | Ed25519 私钥签名、公钥验证 |
需要注意:不带[crypto]时,收据仍然会生成,但没有签名,verify_receipt()因缺少签名直接返回False。在需要证据效力(non-repudiation)的生产环境中,务必安装[crypto]并使用安全的 32 字节十六进制种子作为签名密钥。仓库中的 demo.py 在cryptography缺失时会打印告警并以"未签名"模式降级运行,这正是该前提的实际体现。
二、快速开始:从 Cedar 策略到第一条签名收据
2.1 创建适配器并治理工具调用
以下代码来自教程正文,完整可运行:
from mcp_receipt_governed import McpReceiptAdapter, verify_receipt # 1. 定义 Cedar 策略并创建适配器 adapter = McpReceiptAdapter( cedar_policy=""" permit(principal, action == Action::"ReadData", resource); forbid(principal, action == Action::"DeleteFile", resource); """, cedar_policy_id="policy:mcp-tools:v1", signing_key_hex="a" * 64, # 生产环境请使用安全的 32 字节十六进制种子 ) # 2. 治理工具调用——每次调用都会产出一张签名收据 r1 = adapter.govern_tool_call("did:mesh:agent-1", "ReadData", {"path": "/data/1.csv"}) r2 = adapter.govern_tool_call("did:mesh:agent-1", "ReadData", {"path": "/data/2.csv"}) r3 = adapter.govern_tool_call("did:mesh:agent-1", "DeleteFile", {"path": "/secret"}) # 3. 检查结果 for r in adapter.get_receipts(): icon = "✅" if r.cedar_decision == "allow" else "🚫" print(f" {icon} {r.tool_name}: {r.cedar_decision} (receipt: {r.receipt_id[:8]}...)") # 4. 验证签名收据 print(f" Signature valid: {verify_receipt(r1)}")2.2 参数与底层语义(源码级)
McpReceiptAdapter构造参数在 adapter.py 中定义:
| 参数 | 默认值 | 说明 |
|---|---|---|
cedar_policy | "" | Cedar 策略文本。空策略时所有调用默认deny(默认拒绝) |
cedar_policy_id | "default" | 策略标识,会写入每张收据,便于溯源到具体策略版本 |
signing_key_hex | None | 32 字节 Ed25519 私钥种子(十六进制)。为None时不签名 |
store | None | 自定义ReceiptStore;不传则新建内存存储,可用于多适配器共享审计链 |
session_id | 自动生成 UUID | 会话标识,会进入收据的规范化载荷并影响哈希 |
每次govern_tool_call()的完整流程(adapter.py):
- 调用
CedarPolicyEvaluator评估工具名对应的动作; - 取当前链尾收据的
payload_hash()作为新收据的parent_receipt_hash(链首为None); - 构造
GovernanceReceipt(含args_hash= 工具参数的 SHA-256); - 若配置了签名密钥,执行
sign_receipt();签名失败抛出ReceiptSigningError,fail-closed,绝不静默放行; - 写入
ReceiptStore(重复receipt_id会抛ValueError,防重放)。
策略评估有一个实用的降级设计:CedarPolicyEvaluator(adapter.py)优先尝试导入agentmesh.governance.cedar.CedarEvaluator;若未安装 agentmesh,则回退到内联的正则解析,识别permit(... Action::"X" ...)与forbid(... Action::"X" ...)语句,并支持permit(principal, action, resource);全量放行。这意味着核心测试可以在没有任何外部 SDK 的情况下独立运行,这一点在 tests/test_adapter.py 的模块注释中明确说明。
2.3 治理并执行:govern_and_execute
如果希望"策略判断 + 收据 + 实际执行"一步完成,可以使用govern_and_execute()(adapter.py):只有决策为allow时才调用真实工具函数;被deny的工具绝不会被执行(tests/test_adapter.py 中的test_denied_tool_not_executed断言call_count == 0);若工具执行抛异常,异常信息会写入收据的error字段,格式为execution_failed: <exc>,执行记录仍然留痕。
三、哈希链:插入、删除、篡改一网打尽
3.1 链式结构
收据通过parent_receipt_hash相互链接:每条收据包含上一条收据的规范化载荷的 SHA-256 哈希。由此得到三重防护:
- 插入伪造收据:下一条收据的
parent_receipt_hash与插入收据的哈希对不上,链立即断裂; - 删除收据:后续收据的
parent_receipt_hash指向一条已不存在的记录,链同样断裂; - 修改任何收据:既破坏该收据自身的 Ed25519 签名,又破坏下一条收据的哈希链接。
┌─────────┐ ┌─────────┐ ┌─────────┐ │Receipt 1│◀───│Receipt 2│◀───│Receipt 3│ │ (root) │ │parent=H1│ │parent=H2│ └─────────┘ └─────────┘ └─────────┘链首收据的parent_receipt_hash = None,且该字段为None时不会出现在规范化载荷中(见 receipt.py 的canonical_payload())。
3.2 规范化载荷与哈希:RFC 8785 (JCS) 细节
canonical_payload()是实现"确定性哈希"的关键,其序列化规则(receipt.py):
sort_keys=True:键按字典序排序,保证键序无关;separators=(",", ":"):紧凑无空白,消除空白差异;ensure_ascii=False:按 RFC 8785 §3.2.2.2 要求输出原始 UTF-8,而不是\uXXXX转义——这一点对包含中文、emoji 等 Unicode 工具名尤其重要,tests/test_receipt.py 的test_unicode_raw_utf8_not_escaped用"读取数据"、"قراءة"等用例专门验证了该行为;- 签名相关字段(
signature、signer_public_key)被排除在外——它们签名覆盖的正是这份载荷本身。
payload_hash()即对该规范化字符串做sha256(...).hexdigest()。同理,工具参数args_hash也是对参数做排序后的紧凑 JSON 再取 SHA-256(hash_tool_args,receipt.py):None与{}产生相同哈希,参数键序不影响哈希,不同参数必然产生不同哈希。
3.3 编程方式验链
from mcp_receipt_governed import verify_receipt_chain receipts = adapter.get_receipts() errors = verify_receipt_chain(receipts) if errors: for e in errors: print(f" ❌ {e}") else: print(" ✅ Chain is contiguous and signatures are valid")verify_receipt_chain()(receipt.py)返回错误字符串列表,空列表即链完全有效。它逐一检查:
- 链首约束:第一条收据不得携带
parent_receipt_hash; - 链连续性:第 i 条收据的
parent_receipt_hash必须等于第 i-1 条的payload_hash(); - 防重放:
receipt_id重复立即标记(possible replay attack); - 签名有效性:每条收据必须带合法 Ed25519 签名,公钥必须为 64 位十六进制;
- 可信签名者(可选参数
trusted_keys):传入公钥白名单时,签名者不在名单内的收据直接拒绝。
这些检查在 tests/test_receipt.py 中都有对应的独立测试用例:test_inserted_receipt_detected(插入伪造收据被检出)、test_deleted_receipt_detected(删除中间收据被检出)、test_tampered_signed_receipt_detected(篡改后签名失效)、test_untrusted_key_rejected(不可信签名者被拒)。
四、离线验证:导出 JSON,命令行验链,零网络依赖
这是本文档的核心场景:验证方不需要运行任何 AGT 基础设施,也不需要联网,只要拿到导出的 JSON 文件和(可选)签名者公钥,即可完成全部验证。
4.1 导出收据链
import json with open("receipts.json", "w") as f: json.dump(adapter.store.export(), f, indent=2)ReceiptStore.export()(receipt.py)基于线程安全的ReceiptStore(内部用threading.Lock保护,可被多个适配器共享),把每条收据的to_dict()完整导出,包含receipt_id、tool_name、agent_did、cedar_policy_id、cedar_decision、args_hash、timestamp、session_id、parent_receipt_hash、payload_hash、signature、signer_public_key、error等全部字段。
4.2 运行 CLI 验证器
cd agent-governance-python/agentmesh-integrations/mcp-receipt-governed python scripts/verify_receipts.py receipts.json预期输出(与教程一致):
╔══════════════════════════════════════════════════════╗ ║ MCP Receipt Chain — Offline Verification ║ ╚══════════════════════════════════════════════════════╝ Loaded 3 receipt(s) from receipts.json [0] Receipt 9f5b54c7-036… (tool: ReadData) ✅ Hash chain contiguous ✅ Payload hash verified ✅ Ed25519 signature valid [1] Receipt f31c719a-d97… (tool: ReadData) ✅ Hash chain contiguous ✅ Payload hash verified ✅ Ed25519 signature valid [2] Receipt 87e5cd86-780… (tool: DeleteFile) ✅ Hash chain contiguous ✅ Payload hash verified ✅ Ed25519 signature valid 🎉 Verification passed — chain is contiguous and signatures are valid.如果某条收据被改动、删除或插入,验证器会精确标记链断裂的位置(如Hash chain broken — expected …、Payload hash mismatch、Ed25519 signature verification failed)。
4.3 验证器实现要点与 CI 集成
scripts/verify_receipts.py 的实现有两个值得注意的细节:
- 逐条滚动校验:
verify_chain()用变量expected_parent记录上一条的payload_hash(),与当前条目的parent_receipt_hash比对;同时把导出的payload_hash字段与重算值比对,防止 JSON 文件本身被静默改写。 --json结构化输出:验证器提供--json参数,输出{"file": ..., "total_receipts": ..., "passed": ..., "exit_code": ..., "receipts": [...]},可直接接入 CI/CD 流水线。退出码约定:0= 全部通过,1= 链存在完整性错误,2= 文件加载失败。
4.4 内存审计存储的查询能力
除了导出,ReceiptStore还提供按agent_did、tool_name、cedar_decision组合过滤的query(),以及get_stats()审计摘要(总数、allow/deny 数、唯一 Agent 数、唯一工具数)。demo.py 在运行结束后即用get_stats()打印审计摘要,并将第一条allow收据的完整字段展示出来,是观察收据结构的快速途径。
五、SLSA Provenance:让收据进入供应链验证体系
收据可以输出为SLSA v1.0 provenance predicate,即标准的 in-toto Statement / SLSA Provenance 格式,从而被slsa-verifier、in-toto等标准供应链验证工具直接消费——把"一次 Agent 工具调用"建模成供应链中的一次"构建/执行"事件。
import json slsa = r1.to_slsa_provenance() print(json.dumps(slsa, indent=2))输出遵循 SLSA v1.0 schema(教程示例):
{ "_type": "https://in-toto.io/Statement/v1", "subject": [ { "name": "pkg:agentmesh/tool/ReadData", "digest": { "sha256": "..." } } ], "predicateType": "https://slsa.dev/provenance/v1", "predicate": { "buildDefinition": { "buildType": "https://agent-governance.org/schema/mcp-tool-call/v1", "externalParameters": { "agent_did": "did:mesh:agent-1", "cedar_policy_id": "policy:mcp-tools:v1", "cedar_decision": "allow" } } } }从源码看(receipt.py),to_slsa_provenance()还做了两件教程示例之外的事:
- subject digest 复用
args_hash:subject 的digest.sha256即工具参数哈希,把"这次调用用了什么参数"锚定进供应链证据; - resolvedDependencies 携带父收据哈希:非链首收据会把
parent_receipt_hash作为依赖项pkg:agentmesh/receipt/parent的摘要列出,从而把哈希链原样映射进 SLSA 依赖图(链首则为空列表),另外runDetails.metadata.startedOn以 UTC 时间(Z结尾)输出。
to_slsa_provenance()的结构正确性在 tests/test_receipt.py 的TestSLSAProvenance中逐字段断言(_type、predicateType、subject 名称、父依赖、builder ID 域名、startedOn时区等)。
六、标准对齐一览
本文档所述能力对应的标准与用途如下:
| 标准 | 在本模块中的用途 |
|---|---|
| RFC 8032(Ed25519) | 收据签名与验证(sign_receipt/verify_receipt) |
| RFC 8785(JCS) | 哈希前的规范化 JSON 序列化(canonical_payload) |
| SLSA Provenance v1 | 可选的 provenance predicate 输出(to_slsa_provenance) |
| in-toto Statement v1 | SLSA 输出的外层 Statement 信封(_type字段) |
| IETF draft-farley-acta | 签名收据信封(signed receipt envelope)设计参考 |
对应实现证据:receipt.py 中的canonical_payload()(RFC 8785)、sign_receipt()/verify_receipt()(RFC 8032,基于cryptography的Ed25519PrivateKey/PublicKey)、to_slsa_provenance()(SLSA v1 + in-toto v1)。
七、完整演示与下一步
仓库提供了一个开箱即用的端到端演示:
pip install -e "agent-governance-python/agentmesh-integrations/mcp-receipt-governed[crypto]" python examples/mcp-receipt-governed/demo.pydemo.py 从 policies/mcp-tools.cedar 加载策略(允许ReadData/ListFiles/SearchData,禁止DeleteFile/DropTable/SendEmail),模拟两名 Agent(did:mesh:researcher、did:mesh:analyst)发起 7 次工具调用,逐条打印决策、签名状态与验证结果,最后给出审计摘要和一条完整收据样例。该 cedar 策略文件本身也是理解"哪些调用会被记录为 deny"的直观示例。
继续深入可参考:
- 完整演示:examples/mcp-receipt-governed/demo.py
- Agent 身份与信任:docs/tutorials/02-trust-and-identity.md
- Cedar 策略引擎:docs/tutorials/01-policy-engine.md
- MCP 信任代理(另一条治理路径):agent-governance-python/agentmesh-integrations/mcp-trust-proxy/
- 模块测试(策略评估、哈希链、签名、SLSA 输出的完整用例):tests/test_adapter.py 与 tests/test_receipt.py
生产实践建议:生产环境务必使用持久化、来自密钥保管库(vault)的 32 字节 Ed25519 种子,而不是教程示例中的占位密钥;将签名失败视为 fail-closed 事件;定期把ReceiptStore.export()的 JSON 归档,并用verify_receipts.py --json接入 CI,让每一次 Agent 工具调用都成为可独立举证、可离线审计、可对接供应链标准的治理证据。
【免费下载链接】agent-governance-toolkitAI Agent Governance Toolkit — Policy enforcement, zero-trust identity, execution sandboxing, and reliability engineering for autonomous AI agents. Covers 10/10 OWASP Agentic Top 10.项目地址: https://gitcode.com/GitHub_Trending/ag/agent-governance-toolkit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考