mcpField
S
sdcreceipt

sdcreceipt

本地服务
github.com/SemanticDataCharter金融数据03 天前更新

关于 sdcreceipt

sdcreceipt 是用于验证和结算 VSL Settlement Receipt 的轻量客户端,支持离线签名检查和受控授权,并将密钥与收据分开提供。

主要功能

  1. 01离线验证收据
  2. 02创建并签署结算
  3. 03设置参与方密钥
  4. 04检查发行方和参与方签名
  5. 05可选检查载荷与治理收据

适用场景

  1. 01无需联系发行方验证收据
  2. 02以参与方身份授权结算
  3. 03检查载荷或治理绑定
  4. 04将验证集成到 Shell 脚本

MCP 相关

其 MCP 服务提供 `verify_receipt`、`sign_trigger` 和 `settle`。`settle` 需要在启动时指定固定端点和令牌;签名密钥也在启动时提供。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"semanticdatacharter-sdcreceipt": {
"command": "uvx",
"args": [
"sdcreceipt"
]
}
}
}
启动命令uvx sdcreceipt

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

安装包
pypisdcreceipt4.3.4

工具

1

收录的工具列表 · 更新于 3 天前

参数类型必填说明
receiptobject是要验证的 Settlement Receipt 文档。
party_keysobject否可选。用于验证触发条件的参与方密钥文档。省略后将跳过触发条件检查;如果未持有这些密钥,这样做是合理的,结果中会注明。
issuer_keysobject是发行方以 JSON 发布的密钥文档。格式可以是包含 `keys` 数组的密钥集,也可以是 did:web DID 文档。
governance_receiptobject否可选。治理 Receipt(如有)。

详细介绍

sdcreceipt

验证并结算 VSL Settlement Receipts。

验证无需账户、网络,也无需发行方提供任何内容。 这正是该工具的意义:声称任何人都能独立核验 Receipt,其价值恰恰取决于是否真的能做到这一点。

Apache-2.0。

pip install sdcreceipt

四个动词

# Check a Receipt you were sent. Offline.
sdcreceipt verify receipt.json --issuer-keys issuer-keys.json --party-keys party-keys.json

# Set yourself up as a party: keypair + the document to publish.
sdcreceipt init --key-id https://vendor.example/.well-known/vsl-key.json

# Authorize a settlement you are a party to.
sdcreceipt trigger receipt.json --key vsl-party.pem \
    --key-id https://vendor.example/.well-known/vsl-key.json

# Ask an issuer for a Receipt. The one verb that needs an account.
sdcreceipt settle payload.xml \
    --party https://vendor.example/.well-known/vsl-key.json \
    --party did:web:partner.example

settle 会提示你提供所需但未给出的任何信息,current_state 除外;它默认使用载荷自身的 <current-state>。它会将 Receipt 写入 --out(或标准输出),以供 verify 和 trigger 使用;--response FILE 还会保存发行方的完整答复(治理决定和费用)。DENY 会被签发并签名,但不接受任何触发操作,settle 会说明这一点。其中有两个字段无法猜出,也从来无法猜出:发行方会对发布条件进行哈希处理,且不会存储该条件;current_state/target_state 则来自发行方持有的架构中定义的治理工作流,而不是你持有的架构。

如果发行方拒绝该状态转换,它会答复可接受的状态转换,settle 会将其打印出来:

Governance evaluation produced no Receipt. Decision was DENY

From 'draft' you can go to: review

This model's workflow:
  standard: draft -> review -> published

遇到这种情况时,它会以 2 退出;发生实际故障时则以 1 退出,因此脚本可以区分“换种方式重试”和“出了问题”。

verify 只有在所有检查都通过时才会以 0 退出,因此可以在 Shell 中组合使用,无需任何人解析输出。

这就是全部功能。这是一个客户端,而不是产品;它的价值在于足够精简,便于阅读。

无需阅读任何内容,立即试用

python examples/settle.py

一次端到端结算:两个参与方、两个签名,离线完成验证。无需账户、网络或 API 密钥。参见 examples/。

面向 Agent

四个动词中有三个通过 MCP 提供,且位于同一个包中:

sdcreceipt-mcp --key vsl-party.pem \
    --key-id https://vendor.example/.well-known/vsl-key.json

提供 verify_receipt、sign_trigger 和 settle。只有在服务具备所需条件时才会公布对应工具,因此不会提供每次调用都会失败的工具。

有两项刻意不提供的功能;这是安全策略,而非疏忽(另见 SECURITY.md):

  • 不生成密钥。 在 Agent 会话中生成的私钥,其保管方式并不明确。init 始终由人在终端中执行。
  • 不提交。 sign_trigger 会返回一个由你提交的已签名触发项。提交需要调用方提供目标地址,而已签名触发项加任意主机这一组合值得拒绝。

服务在启动时使用 --endpoint 和令牌启动后,才会提供 settle;这是唯一会访问网络的工具。端点和密钥一样,在启动时固定,因此调用方无法重定向载荷的发送位置。没有任何工具接受 URL;如果将来要增加其他工具,也必须保持这一不变量。

签名密钥在启动时提供,绝不会出现在工具调用中,因此不会经过对话传递。


如果你收到一份 Receipt

你不需要在任何地方拥有账户。你需要签发方发布的密钥文档;对于已结算的 Receipt,还需要每一方发布的密钥文档。Receipt 使用各方发布密钥的 URI 标识各方;签发方的密钥文档位于固定的知名路径。

pip install sdcreceipt
curl -o receipt.json https://sdcstudio.axius-sdc.com/api/v1/vsl/receipt/<receipt id>   # or the file you were sent
curl -O https://sdcstudio.axius-sdc.com/.well-known/sdcstudio-signing-keys.json
curl -o vendor-keys.json  https://vendor.example/.well-known/vsl-key.json
curl -o partner-keys.json https://partner.example/.well-known/did.json
sdcreceipt verify receipt.json --issuer-keys sdcstudio-signing-keys.json \
    --party-keys vendor-keys.json --party-keys partner-keys.json

签发方的文档用于验证签发方的签名;每一方的文档只用于验证该方的触发记录。 角色来自你的命令行,而非 Receipt;如果两个文档声明了相同的 key_id,则会拒绝。 自 4.3.3 起,旧的 --keys 标志会被拒绝:它会汇集所有文档,导致某一方自己的文档可以提供签发方密钥(GHSA-gwhr-82j5-883w)。

检查完成后,verify 会列出 VERIFIED 未涵盖的内容:触发记录的时间戳未签名,密钥有效期未与 Receipt 的时间进行比较,链路(previous_hash)不会被跟踪,且只有在你传入负载和治理 Receipt 时才会检查它们。

每项检查都会报告,而不仅仅是第一项失败的检查:

PASS  receipt_hash: matches the canonical content
PASS  signature[sdcstudio-signing-key-v1]: verifies over receipt_hash (ES256)
PASS  signature[sdcstudio-pq-signing-key-v1]: verifies over receipt_hash (ML-DSA-65)
PASS  signatures.algorithms: carries every signature version 1.1 requires (ES256, ML-DSA-65)
PASS  trigger[https://vendor.example/.well-known/vsl-key.json]: verifies over {condition_hash, receipt_id}
PASS  trigger[did:web:partner.example]: verifies over {condition_hash, receipt_id}
PASS  triggers.unique: one trigger per party
PASS  settlement.complete: every listed party has triggered

VERIFIED

如果只有签发方的文档,则会检查签发方签名和哈希,并将 settlement.complete 记录为尚未确立,因此 Receipt 无法通过验证:每一方都已触发这一点涉及授权声明,而没有检查任何触发签名。这是正确的结果,并非缺陷。还需传入 --schema settlement-receipt-1.0.schema.json(或与 Receipt 的 version 匹配的 -1.1),以先检查结构(pip install 'sdcreceipt[schema]')。

Receipt 1.1(自 4.3.0 起)是在 1.0 的基础上,由签发方对同一个 32 字节摘要签署两次:一次是 ES256 签名,另一次是 ML-DSA-65(FIPS 204,后量子)签名。每个列出的签名都必须通过验证,且标明 1.1 的 Receipt 必须同时包含两者;1.0 Receipt 的验证方式则与以往完全相同。签发方的密钥文档会列出这两把密钥,并为每把密钥列出其 alg。ML-DSA-65 验证功能来自 cryptography 48 或更高版本,这是此工具的必需版本。

Receipt 只携带哈希承诺,绝不携带负载。因此,验证可以告诉你一次符合规范、经过授权且由双方触发的交换已经发生,而无需任何人披露交换内容。如果你还持有负载或治理 Receipt,也可以传入它们进行检查:

sdcreceipt verify receipt.json --issuer-keys issuer-keys.json --party-keys party-keys.json \
    --payload manifest.xml --governance governance-receipt.json

如果你需要成为其中一方

结算会通过你控制的 key_id 标识每一方。这是有意为之:这样验证你的签名就无需经过签发方,因此无需任何人持续在线,你过去的签名也能继续具有意义。

sdcreceipt init --key-id https://vendor.example/.well-known/vsl-key.json

这会写入私钥(模式 0600)和密钥文档,并告知你该文档必须可通过哪个确切 URL 访问。发布一个 JSON 文件就是全部的接入要求。

之后,当你收到一份需要授权的 Receipt 时:

sdcreceipt trigger receipt.json --key vsl-party.pem --key-id <your key_id>

它会输出一条已签名的触发记录,然后停止。签名本身不会产生实际操作;提交则会产生副作用,因此你需要自行发送,或添加 --submit <url>。


★ 切勿从文档中获取验证密钥

接受哪些密钥在你读取文档之前就已确定, 文档不能改变这一点。

XML-Signature 中的 ds:RetrievalMethod、JOSE 中的 jku 和 x5u,以及其他地方的等效字段,都在说*“我的密钥在这里。”* 这个指针由文档的生成者写入,因此跟随它就等于让文档指定裁定自身的密钥。伪造的文档会指定伪造者的密钥,验证便会“成功”。

这种失误悄无声息。指针可能指向一个在文档签署时有效、后来却已失效的域名;任何注册该域名的人都能在该路径提供密钥,而文档看起来毫无问题——因为文档本身确实没有问题。验证者被告知去哪里查找,也照做了。

这个工具不会犯这种错误:verify 将密钥作为参数接收,没有任何代码路径会去获取密钥。这是一项安全属性,而非不便之处。

参与方密钥也是如此,但这属于附带说明,而非例外。这些 key_id 确实是由对方控制的 URI,这是有意为之。只对你信任的 Receipt 中已有记录的标识符通过 HTTPS 解析,并保存副本——参与方日后失去某个域名,不得因此改变其旧签名的含义。

参与方密钥也必须提供。它们之所以是可选的,是因为无需它们也能检查颁发者签名和负载哈希;但这不代表缺少它们时 Receipt 已结算就有任何意义。每个参与方是否都已触发,是一项关于授权的声明,因此若没有密钥可用于核验签名,settlement.complete 会被记录为尚未确立,而非通过,Receipt 也无法通过验证。在 4.2.1 之前,只比较 key_id 字符串就会通过验证,并将伪造的触发报告为 VERIFIED。


一致性

tests/conformance/ 提供发行方发布的测试向量,测试套件会使用这些向量验证此实现。

共 16 个测试向量,其中 11 个针对 Receipt 1.0,5 个针对 1.1(每个向量都使用其自身 version 指定的架构进行检查)。每个无效向量都对应一个实际出现过的缺陷,而非假设情形:ES256 要求使用 P1363,却使用了 DER 签名;对 receipt_hash 的十六进制文本而非原始字节进行签名;治理绑定与持有的证据不匹配;从另一个具有相同发布条件的 Receipt 重放触发器,等等。因错误原因而失败不算通过——清单明确指出必须触发哪项检查。

pytest

坦诚说明独立性。 通过这些测试向量,说明此工具符合发行方发布的预期,且从未偏离这些预期。它并非独立推导的结果:此实现与发行方有着共同的设计和历史。这些测试向量对仅依据规范编写验证器的人最有价值,这也是发布它们的目的。

底层的规范化则是另一回事,并且已通过独立实现进行验证。 Receipt 中的每个哈希都基于 RFC 8785 规范化字节计算,因此,其他验证的基础是各方对规范化结果达成一致。2026 年 9 月,我们与 MTCP 项目(Ahmad Abby)进行了双向验证。该项目使用 Trail of Bits 的 rfc8785 而非 sdcgovernance 实现 RFC 8785:

  • 使用 sdcgovernance.jcs 验证了 MTCP 发布的 5 个测试向量。所有向量的规范字符串和 SHA-256 均逐字节一致。这组测试向量于 2026 年 9 月 9 日发布,是一组经过整理后重新生成的向量,其中使用了真实架构中的合成值:audit_record、evaluation_summary、score_record、sensor_calibration 和 arabic_content。它取代了 9 月 1 日发布的 4 个测试向量;承载规范形式的字段也从 canonical_hex 重命名为 output,因此,针对早期测试向量编写的运行器需要更新。
  • 使用 MTCP 的实现验证了 sdcgovernance/test-vectors/rfc8785-canonicalization.json 中的 21 个测试向量。没有任何不一致,包括边界测试集:负零、次正规数、从定点到指数表示的 1e21 边界、以小写 \u00xx 表示的 C0 控制字符、不转义的实线号、增补平面字符,以及跨越 UTF-16 代理对的键排序。
  • MTCP 发布了一次一致性测试结果,使用 cyberphone 附录 G 参考测试向量验证了19 项纯 RFC 8785 测试:6 个官方测试向量、十六进制验证、10 项硬错误拒绝测试(NaN、无穷大、超出 2^53 的整数、非 JSON 类型)、一项数字格式化测试、一项整数边界测试,以及一项针对 2011 种 IEEE-754 模式的 Node.js 差分测试,结果为零处不一致。

双方都独立进行了 Node.js 差分测试,因此数字格式化结果经过了 JS 引擎验证,而不是重新实现。这是因为 RFC 8785 §3.2.2.3 原样采用 ECMAScript Number::toString,所以对于实际容易出错的部分,应以该引擎为参照。两个语言中的三个实现,没有任何不一致。这并非任何一方项目都能单独对自身做出的声明,也正是它比同一技术脉络中的第二种意见更值得采用的原因。

这并不意味着上述 Receipt 测试向量是独立的。这意味着,当它们与你的实现不一致时,分歧在于 Receipt 规则,而非底层字节。

构建你自己的实现

你不必使用此工具,而且规范也不依赖它。 如果你要编写验证器:

不要再编写一个规范化器。 使用 sdcgovernance 或其他符合 RFC 8785 的实现。两个实现可能产生不一致,而且这种不一致不会显现出来:字节不同,哈希也不同,产物看起来就像被篡改了,而不是编码错误。此工具重新导出 sdcgovernance.jcs 正是出于这个原因,不添加任何其他内容。

无法确定时应拒绝,而不是猜测。 超出 ±(2⁵³−1) 的整数无法通过 IEEE 754 双精度浮点数往返保真,NaN/Infinity 也没有 JSON 表示形式。为这些值生成内容会产生看似正常的哈希,却只会在其他人的验证器中验证失败。

报告每项检查。 在首次失败时停止,会掩盖最重要的情况:Receipt 的签名验证通过,但治理绑定未通过。

检查曲线。 根据意外曲线上的密钥验证签名,并不能证明是你认为的那个参与方进行了签名。

版本管理

MAJOR 对应 SDC 参考模型,因此 4.x.x 版本面向 SDC4。版本号从 4 开始,而不是从 0 开始,是因为这一约定,并非此前已有三个版本。MINOR 表示功能,PATCH 表示修复。SDC5 参考模型会对应 5.x.x。

sdcvalidator、sdcgovernance 及同系列的其他项目也采用相同的方案,因此无需查找其他信息,就可以通过版本号了解产物面向哪个参考模型。

请注意,Receipt 格式版本是独立的:Receipt 中的 "version": "1.0" 或 "1.1" 表示线格式版本,而非此软件包的版本。4.3.0 是首个支持验证 1.1 的版本;更早的版本会根据版本号拒绝它,而不是猜测,这是格式要求。

依赖项

Python 3.10 或更高版本。

有两个直接依赖项,均为兼容 Apache-2.0 的库: sdcgovernance(固定为 >=4.2.0,<5),用于 RFC 8785 规范化;以及用于 ECDSA 的 cryptography。jsonschema 是可选依赖项,仅在使用 --schema 时需要。执行一次干净的 pip install sdcreceipt 会解析这两个依赖项及其各自的依赖项,总计约 14 个软件包;pip install --report 会列出适用于你平台的确切软件包集合。

这些是库依赖项。此处没有任何内容会调用服务,verify 完全不会发出网络请求。settle 和 trigger --submit 会拒绝任何非 https:// 端点,但本地发行方的回环地址除外。

安全

请参阅 SECURITY.md,了解如何报告漏洞、支持的版本,以及此工具提供和不提供的保护。

评论

支持 Markdown

第一次接触 MCP?

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

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