关于 capacity-attest
capacity-attest 是用于在 x402 容量交易付款后记录签名交付声明的 MCP 服务。买方 Agent 可在交易前查看卖方的原始声明记录;它不提供评分或争议裁决。
主要功能
- 01记录签名交付声明
- 02验证声明哈希与签名
- 03按时间检索卖方记录
- 04检查关联声明中的遗漏
- 05从独立来源发现声明
适用场景
- 01记录付款后的 GPU 小时或存储交付
- 02付款前查看卖方的历史记录
- 03比较从多个来源收集的声明
MCP 相关
该 MCP 服务提供记录交付声明和检索卖方记录的工具。它会验证声明内容和买方签名,再将声明追加到本地账本。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
3收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| claimId | string | 是 | 内容寻址 ID:此声明内容字段规范 JSON 的 sha256——参阅 computeClaimId() |
| measured | object | 否 | 可选的定量记录,记录承诺数量和测量数量。是否存在此字段用作版本标记;缺失是表示“未测量”的唯一编码方式 |
| measured.unit | enum | 是 | 以下数量的单位——必须是此 assetType 对应的 UNITS_BY_ASSET_TYPE 条目中的单位gpu-second | byte | byte-second | call | token | credit |
| measured.basis | enum | 是 | 此数字统计卖家提供的数量(`supplied`),还是买家实际提取的数量(`consumed`)supplied | consumed |
| measured.method | object | 是 | 数字的获取方式 |
| measured.method.instrument | string | 是 | 关于测量仪器的自由文本,例如 "nvidia-smi accounting, 10s polling" |
| measured.method.attribution | enum | 是 | 谁生成了该数字——仅表示来源,不代表质量或信任信号buyer | seller | third-party | undisclosed |
| measured.method.readingsHash | string | 否 | 原始仪表数据转储的 sha256——不会存储转储本身。它与 evidenceHash 不同,后者涉及交付证据 |
| measured.period | object | 是 | 此测量涵盖的已闭合时间窗口 |
| measured.period.end | string | 是 | 已闭合测量窗口的结束时间,规范 UTC 时刻 |
| measured.period.start | string | 是 | 已闭合测量窗口的开始时间,规范 UTC 时刻 |
| measured.promisedAmount | string | 是 | 承诺的金额是多少,以规范十进制字符串表示 |
| measured.deliveredAmount | string | 是 | 测得的金额是多少,以规范十进制字符串表示 |
| assetType | enum | 是 | 此声明涉及哪种容量gpu-hours | storage | api-credits | bandwidth |
| delivered | enum | 是 | 承诺的内容是否实际交付yes | no | partial |
| signature | string | 是 | 买方针对 claimId 的 EIP-191 personal-sign 签名 |
| timestamp | string | 是 | 此声明创建时间的 ISO-8601 时间戳 |
| buyerAddress | string | 是 | 付款 Agent 的 0x 地址——必须与从 `signature` 恢复的地址一致 |
| evidenceHash | string | 是 | 此声明证据的 sha256 十六进制摘要(日志、响应载荷等)——此处不存储证据本身 |
| externalRefs | object | 否 | 可选的、未经验证的指针,指向其他 Agent 经济基础设施(身份、权限、意图、争议)。Tokenizen 不会解析或信任这些指针——它们是引用,而非经验证的事实 |
| externalRefs.intentRef | string | 否 | 指向外部签发的预签名意图对象的未经验证指针(例如 AP2 IntentMandate),用于描述买方的委托人最初要求的内容 |
| externalRefs.mandateRef | string | 否 | 指向外部签发的权限/授权对象的未经验证指针(例如 AP2 Payment/Cart Mandate),买方声称该对象涵盖此次交付。Tokenizen 不会据此检查范围、预算或有效性 |
| externalRefs.buyerAgentRef | string | 否 | 指向买方外部 Agent 身份记录的未经验证指针。Tokenizen 不会解析或验证此指针 |
| externalRefs.disputeContext | object | 否 | 仅当买卖双方在结算时已就外部争议条款达成一致时才提供。使 delivered:no 声明可作为该外部协议中的证据,而非由 Tokenizen 自行裁决 |
| externalRefs.disputeContext.protocol | string | 是 | 此声明可作为证据的外部争议/责任协议的简短标签,例如 "LCP" |
| externalRefs.disputeContext.termsHash | string | 是 | 双方在结算时接受的管辖条款的 sha256;此处不存储条款本身 |
| externalRefs.disputeContext.resolutionRef | string | 否 | 可选指针,指向 `protocol` 指定的外部协议中的解决记录/案件记录(如果已存在) |
| externalRefs.sellerAgentRef | string | 否 | 指向卖方外部 Agent 身份记录的未经验证指针(例如 ERC-8004 agent id 或 DID)。Tokenizen 不会解析或验证此指针 |
| externalRefs.mandateIssuerDid | string | 否 | 声称签发 `mandateRef` 所引用授权的委托人的 DID。不会根据授权本身进行验证 |
| priorClaimId | string | 否 | 可选链式链接:此买方关于同一 sellerAddress 的上一条声明的 claimId。买方首次针对某卖方提出声明时省略。使读者能够检测主机是否隐藏了中间声明——参见 analyzeCompleteness 和 DECISIONS.md D-006 |
| promisedSpec | any | 是 | 卖方承诺交付的内容——自由文本或结构化对象 |
| sellerAddress | string | 是 | 已付款且应履约的 Agent/服务的 0x 地址 |
| settlementRef | string | 是 | 此索赔所涉结算的 x402 付款引用或链上交易哈希 |
详细介绍
capacity-attest
荷兰语版 / Dutch version: README.nl.md
用于 AI Agent 之间 x402 容量交易交付证明的 MCP 服务。
状态:MVP,已发布到 npm(
npm install capacity-attest)和官方 MCP 注册表(io.github.holistis/capacity-attest)。
经独立核查,而非仅凭声明
以下关于本项目的每项声明都可以点击查看并独立核实,无需只听我们一面之词。
| 内容 | 核查方 | 状态 |
|---|---|---|
将 [email protected] 作为真实依赖,通过我们自己的代码验证 claim digest/claimId/签名 | YE-YI7/asm-spec#18 | 已合并 |
| 在相同的内容寻址声明格式上实现 BSV 轨道适配器 | YE-YI7/asm-spec#19(作者 EmbryoSpace) | 已合并 |
| 第三方在链上独立核实了我们的边界声明(“可发现性 ≠ 完整性”),并非任何内容都只凭信任 | x402-foundation/x402#3379 | 公开,持续进行中 |
| 在 Base 主网上以链上证明形式发布实时交付声明,任何人都可以解码 | 已交付=yes · 已交付=no | 在线 |
| 同样的内容已在第二和第三条链上实时运行(WP2),证明 EAS 源在不同部署中均可正常工作,而不仅限于 Base | Optimism · Ethereum 主网 | 在线 |
在 Base 主网的 ERC-8004 Reputation Registry 上真实调用 giveFeedback() | 交易 0x2217...efc0 | 在线 |
| 被提议作为对方 Agent 规范中面向买方的补充 | omworldprotocol/om-world#18 | 审核中,尚未合并 |
| 独立重建的仅使用 Python 标准库的验证器(自行实现 secp256k1/EIP-191/规范化 JSON,无共享代码),与我们的测试向量 7/7 匹配,包括两个负向控制(伪造签名、篡改声明);现已成为另一个独立发布项目中的永久回归测试 | x402-foundation/x402#2887 (comment),作者 goun7,已集成到 Tamga(pip install tamga-protocol) | 已永久集成到其他项目 |
在 ERC-8004 草案版 grounded-feedback 规范中,将 measured 块引用为计量交付的事实来源;该规范固定引用本仓库的特定提交,且两个独立验证器(Node 和 Python)均通过了五个已签名测试向量 | erc-8004/erc-8004-contracts#99,架构文档见 predgeAI/erc8004-outcome-validator | 草案 v0,公开,按提交哈希引用 |
**我们如实将以下内容与上表分开,因为这并非第三方审查:**在 0.6.0 之前(首个实际向区块链写入数据的版本),我们进行了自己的对抗性安全审查。共发现九项问题,现已全部修复:其中七项通过专门的回归测试关闭,一项通过打包检查(npm pack --dry-run)验证,而非单元测试;还有一项仅通过修正文档解决。这不是由外部机构进行的独立审计。完整且可核查的报告:docs/SECURITY-REVIEW-2026-09-11.md。
为什么要做这个项目
当 AI Agent 通过 x402 协议向另一个 Agent 或服务购买算力(GPU 小时、存储、API/推理额度、带宽)后,付款完成后并没有任何凭证能证明对方确实交付了承诺的内容。买方 Agent 自己心里清楚(它看到了输出,或者没有看到),但会话一结束,这些信息就丢失了。下一个想与同一卖家交易的 Agent 又得从零开始摸索。
capacity-attest 填补的正是这一空缺:结算完成后,付款方 Agent 会留下一条经过密码学签名的事实声明(delivered: yes/no/partial + 证据哈希)。其他 Agent 可以在与同一卖家交易之前查阅这段记录。
不做评判。不设声誉分数。没有“裁决”——只有一张签名的收据和声明,就像实物货物附带的交货单一样。
本项目明确不是什么
本项目明确且永久不会是:
- 不是声誉分数或评级。
get_delivery_history返回未经加工、按时间顺序排列的声明列表,不计算平均值、百分比或“信任分数”。把这些信息归纳成一个数字,隐含着评判意味,而项目设计阶段已明确否决这种做法。 - 不是金融产品。 没有利息、没有付款时间折扣、没有账本余额收益(这里没有余额,也不是托管服务)、没有借贷、没有抵押,也没有发票融资/保理。
assetType是一个封闭枚举,仅包含容量类型(gpu-hours、storage、api-credits、bandwidth),明确不包含任何类似金融工具的内容。 - 不是自有代币或币。 付款照常通过 x402/USDC 进行;本项目只记录已在别处完成结算的收据。
- 不是信贷。 只有在付款完成后才会创建声明。本项目不提供任何融资;它记录的是已完成的 ijara(租赁/服务)交易。
- 不是自有身份、权威或争议解决层。
externalRefs(见下文)纯粹是对其他系统(ERC-8004、AP2、Legal Context Protocol 等)的引用。本项目绝不会自行解析、验证或评判该引用。关于为何本项目明确没有发展成自己的协议,请参阅 DECISIONS.md 中的 D-007 至 D-013。
这是经过正式审查后有意作出的设计选择,并非偶然的范围限制。如果你正在考虑添加相关功能,请参阅项目简介中的防护原则部分:当你不确定某个字段或功能是否触及这条界线时,就不要添加。
明确暂缓的功能(锚定、中间状态、正式一致性测试向量),以及即使如此仍会开发它们的具体条件:请参阅 DECISIONS.md。
延伸阅读:伪造交付声明的九种方法,以及为何没有一种完全奏效,即上文 D-014/D-018 的公开说明。
工作原理
1. record_delivery
付款 Agent(买方)在 x402 结算后调用此工具,此时已知承诺的内容是否已交付。声明包含:
| 字段 | 含义 |
|---|---|
sellerAddress | 收款方的 0x 地址 |
buyerAddress | 付款 Agent 的 0x 地址,必须与从 signature 中恢复出的地址一致 |
assetType | gpu-hours | storage | api-credits | bandwidth |
promisedSpec | 承诺的内容:自由文本或结构化对象 |
delivered | yes | no | partial |
evidenceHash | 支持证据的 sha256 十六进制值(日志、响应负载等);不存储证据本身 |
settlementRef | x402 付款引用或底层付款的链上交易哈希 |
timestamp | ISO-8601 时间戳 |
claimId | 对以上所有字段进行内容寻址的 sha256 哈希,参见 src/schema.ts 中的 computeClaimId() |
signature | 买方对 claimId 的 EIP-191 personal-sign 签名 |
externalRefs | (可选,自 0.3.0 起) 指向其他 Agent 经济基础设施的未经验证的引用:sellerAgentRef/buyerAgentRef(例如 ERC-8004 Agent ID 或 DID)、mandateRef+mandateIssuerDid(外部签发的 AP2/AAE 授权)、intentRef(外部 AP2 IntentMandate)、disputeContext(protocol+termsHash+可选的 resolutionRef,例如 Legal Context Protocol 引用)。参见 DECISIONS.md D-007 至 D-013 |
priorClaimId | (可选,自 0.4.0 起) 你之前针对同一 sellerAddress 提交的声明的 claimId,使你针对该卖家的声明构成链。首次针对某卖家提交声明时省略。属于签名内容的一部分,因此主机无法将其剥除。让读取者能够发现主机隐藏中间声明的情况。参见 DECISIONS.md D-006 |
offerReceiptHash | (可选,自 0.8.0 起) 卖家签名的 x402 offer-receipt 的 sha256 十六进制值,即此声明所回应的收据;对收到的收据原样计算哈希。该收据是卖家关于服务已交付的陈述;此声明则是买方关于实际收到内容的陈述。将两者关联起来,争议双方就都能提供各自的说法,而不只是听取利益相关方一方的陈述。它属于签名内容的一部分,因此签名后无法替换或剥除该引用。包含双方内容及真实签名的完整示例:examples/offer-receipt-link-testvector.json |
服务器会先验证架构,然后验证 claimId 是否确实是内容的哈希,接着验证 signature 是否确实恢复出 buyerAddress。只有全部通过后,声明才会追加到只追加账本(data/claims.jsonl)中。无效签名或已存储的声明(claimId 相同)都会被拒绝。
2. get_delivery_history
给定一个 sellerAddress,此工具会按时间顺序(从最早到最晚)返回 此安装上该卖家的所有已知索赔记录。仅提供事实,不汇总数量。买家 Agent 会在付款之前调用此工具,查看潜在卖家的原始交付历史,并自行判断。
响应包括 sellerAddress、count 和 claims,以及 scope(始终为 "local-ledger")和 note:一段固定的事实性文本,说明此结果仅反映 此安装的本地账本。历史记录为空或较短,并不意味着卖家的记录良好——也可能只是因为这里尚未记录任何索赔。
从 0.4.0 开始,响应还包括 completeness:对恰好位于此结果集中的买家链(priorClaimId)进行分析。如果此处显示的索赔引用了一个不在结果集中的索赔,该情况就会显示在 possibleOmissions 中。这是一个具体、可核查的信号,表明主机可能隐藏了一条中间索赔,而非模糊的猜测。
请注意,这一点最重要:completeness 字段由返回这些索赔的同一服务计算。如果你不信任该服务,也不要相信这个字段——不诚实的主机可以直接声称“一切完整”。真正的保障在于索赔本身签名过的 priorClaimId,主机无法伪造或删除它。因此,你应根据收到的索赔自行重新执行检查:
// recompute-completeness.mjs
import { verifyClaim } from "capacity-attest/dist/signing.js";
import { analyzeCompleteness } from "capacity-attest/dist/completeness.js";
// `claims` = the array from the get_delivery_history response.
const allSigned = claims.every((c) => verifyClaim(c).ok); // is every claim genuine?
const report = analyzeCompleteness(claims); // recompute yourself, don't trust the host field
console.log({ allSigned, chainConsistent: report.chainConsistent, possibleOmissions: report.possibleOmissions });
坦诚地说:即使你自行重新计算,也无法发现被隐藏的最后一条索赔,或整个被隐藏的买家,因为这两种情况下都没有可供追溯的链接。并且,悬空的反向引用也不一定意味着恶意行为——较早的索赔可能只是在另一个安装上记录的(D-005 所述情况)。要获得真正的确定性,你仍需要外部见证:你自己保留的上述副本,以及通过 settlementRef 查询的链上付款。请参阅 DECISIONS.md D-006。
docs/COMPLETENESS-FIXTURE.md 中提供了一个公开、可自行核查的示例,其中模拟了隐藏记录的主机,并故意设置了错误的测试用例。运行 npm run fixture 即可;每次推送时都会将相同的检查作为测试运行。因此,你可以自行验证我们的说法,而不必只听我们一面之词。
发现其他安装中的声明(D-005)
get_delivery_history 按定义是本地操作:买家 B 看不到买家 A 在另一安装中记录的、关于同一卖家的信息。由于每条声明都可自行验证,因此可发现性不需要可信索引。discoverDeliveryHistory(seller, sources)(见 src/discovery.ts)会从多个彼此独立的非可信来源读取卖家的声明(你的本地账本,以及你想读取的任何独立于托管方的基础设施),进行去重、重新验证每条声明、过滤掉其他卖家的声明,并对合并后的集合执行完整性检查。注入伪造声明的来源会被拒绝;遗漏内容的来源属于 D-006 问题——该问题已纳入考量,但不会因此神奇地得到解决。
生产环境基础设施已在本项目面向的三条链上运行:Base 主网、Optimism 主网和 Ethereum 主网上均有 EAS 证明,每条都可通过公开区块浏览器链接独立验证,而非仅仅停留在描述层面。docs/DISCOVERY-FIXTURE.md 中提供了一个公开、可运行的双安装模拟示例,运行 npm run discovery-fixture 即可。参见 DECISIONS.md D-005。
此外还提供了另一种非 EAS、达到生产级别的 ClaimSource:httpClaimSource(src/http-source.ts),这是一个普通 HTTP 端点,遵循 GET <url>?seller=<address> -> JSON 声明数组这一约定,也是 discoverDeliveryHistory 自身头部注释中所说的“另一安装的公开端点”的一种具体形式。它的存在是为了验证聚合层能否处理真正不同类型的来源,而不只是第二个 EAS 部署;与所有来源一样,它不可信,因此格式错误或恶意的响应不会导致发现过程崩溃,只会显示为单个来源的错误。examples/reputation-lookup.mjs 是一个可运行的 CLI 示例,可在一次真实查询中组合本地账本与这两种生产来源(EAS 和 HTTP 来源):运行 npm run build && node examples/reputation-lookup.mjs <sellerAddress>(可先设置 RPC_URL 和/或 HTTP_SOURCE_URL;无需有余额的密钥,因为该示例只读取数据)。
docs/INTEGRATION-GUIDE.md 通过实际代码介绍了所有三种来源类型,还提供了由其他项目构建的两个独立真实集成(一个 Base 关联示例和一个 BSV 通道,均非本项目构建),作为将此声明格式扩展到新链的具体示例。
3. resolve_agent_identity (自 0.3.0 起)
对 ERC-8004 Identity Registry 执行只读查询:谁拥有 agentId(ownerOf),其注册文件位于何处(tokenURI)。只会调用标准 ERC-721 接口,不会调用任何 ERC-8004 专有接口。调用方必须提供 agentRegistryRef("eip155:<chainId>:<registryAddress>")和该链的 rpcUrl:本项目有意不捆绑自有 RPC 提供商,也不指定规范注册表地址,因为 ERC-8004 在每条链上都有独立部署,且 EIP 文本本身未指定固定地址。我们特意不会获取 tokenURI 指向的内容(该值只是一个指针,调用方想要的话可自行获取);获取此类内容可能会对由调用方控制的链上数据造成 SSRF 风险。
已通过可注入的 ContractFactory 进行测试(src/erc8004.test.ts,不依赖网络),并在 Base 主网真实部署的注册表上进行过实时测试(examples/verify-erc8004-live.mjs,运行 npm run build && node examples/verify-erc8004-live.mjs)。完整背景请参见 DECISIONS.md D-007。
4. publishReputationFeedback (自 0.6.0 起提供,是库函数,不是 MCP 工具)
注意(2026-09-11 对抗性审查):撰写本文时,npm 上发布的版本仍是 0.5.0,不包含此函数。 在 GitHub 上看到本文后立即按下文所述运行 npm install capacity-attest 的用户,目前还无法获得 publishReputationFeedback。导入此函数前,请通过 npm view capacity-attest version 确认实际发布的版本。以下内容描述的是 main 分支上的代码现状。
将已签名声明中的 delivered 事实发布到 ERC-8004 Reputation Registry 的 giveFeedback(),也就是约 50 万个已注册 Agent 已能查找信誉信号的同一位置,而不只是写入此安装实例自己的账本或 EAS。该合约要求提供数值型的 value 和 valueDecimals 字段;此软件包有意不自行设定评分尺度。value 只是对 delivered 的直接、机械映射(是 = 1.0,部分 = 0.5,否 = 0.0),绝不代表新的判断,而 capacity-attest 本身也不会在任何地方读取或显示这个数字。写入任何链上数据前,会重新验证声明的签名。
调用方必须提供 reputationRegistryRef("eip155:<chainId>:<registryAddress>",即 Reputation Registry,而非 Identity Registry)、agentRegistryRef(同一条链上的 Identity Registry)以及 rpcUrl;这与 resolve_agent_identity 一样,所有信息都由调用方提供。agentId(卖方的 ERC-8004 Agent)必须已在 Identity Registry 中有效注册;合约本身会拒绝来自该 Agent 所有者的反馈(“Self-feedback not allowed”)。自 2026-09-11 对抗性审查以来,写入任何链上数据前,还始终会通过 agentRegistryRef 检查 agentId 的注册所有者是否与 claim.sellerAddress 一致;否则,调用方可能会将真实且有效签名的声明关联到任意其他 agentId。
有意不将其设为 MCP 工具,原因与 EAS 的 publishClaim 相同:这是一个写入操作,需要真实且有资金的签名者和 Gas,而此服务有意不捆绑或存储自己的私钥。需要管理自己的签名者时,可直接导入(src/erc8004-reputation.ts)。
该功能已通过可注入的 ReputationContractFactory 测试(src/erc8004-reputation.test.ts,19 项测试,无网络依赖;包括一项明确验证 value 完全取决于 delivered 的测试,以及三项针对 agentId 所有权检查的测试),并在 Base 主网上通过真实部署的注册表进行了实测(examples/erc8004-reputation-live-demo.ts,npm run erc8004-reputation-demo):2026-09-10 使用我们自己的临时测试 Agent(agentId 85888)确认成功调用了真实的 giveFeedback(),交易 0x221797800d5941dff62e87022083e7c6dfba3e07b35c84e56b10fdca8967efc0,并通过单独调用 eth_getTransactionReceipt 进行了独立复核。完整背景请参见 DECISIONS.md 中的 D-016,其中也解释了为何尽管 D-005 设有触发条件,仍于今日构建此功能。
签名
声明由买方(付款方,因此知道实际交付了什么)签名,而非卖方。这里刻意使用纯粹的 EIP-191 personal_sign 对 claimId 签名(通过 ethers.Signer#signMessage),而非 EIP-712 类型化数据。这样能让此 MVP 的加密功能保持精简且易于审计。以后可以增量升级到 EIP-712(例如 mcp-paywall/src/x402.mjs 中的做法),而不会使现有声明失效。
独立验证一项声明
账本中的每项声明都可以仅凭 npm 包和原始声明字节重新检查,无需访问本项目,也无需向我们发起网络请求。不需要账户,也不需要托管调用。
npm install capacity-attest
// verify.mjs, run as an ES module (top-level await)
import { verifyClaim } from "capacity-attest/dist/signing.js";
const claim = JSON.parse(await (await fetch("<url to a claim.jsonl line>")).text());
console.log(verifyClaim(claim));
// { ok: true } if claimId really is the hash of the content AND signature really recovers to buyerAddress
注意:请直接导入 capacity-attest/dist/signing.js,而不是包的根入口。根入口(dist/index.js)在导入时会通过 stdio 启动 MCP 服务,这会导致独立验证脚本挂起。
verifyClaim() 只检查两件事:claimId 是否为声明字段的内容寻址哈希,以及 signature(EIP-191)恢复出的地址是否为 buyerAddress。它不会检查底层结算(settlementRef)是否确实在链上成立——这需要单独对照相关链进行检查;它也不会检查 delivered 是否为 true,或 evidenceHash 是否涵盖真实证据;这些仍由付款 Agent 自行声明。
github.com/YE-YI7/asm-spec,PR #18 中有一个已成功由外部复现的示例,展示了这些确切步骤:一个独立项目针对真实且已注册的声明进行了验证。
可以放心依赖的内容
如果你正在编写自己的验证器,或将此仓库固定在规范中,那么你需要关注的就是这部分:哪些内容不会发生变化。
有四项内容是固定的,今天签署的声明应当在数年后仍能通过验证:
- 计算声明哈希所用的规范形式,逐字节定义,详见
docs/metered-delivery-spec.md。 claimId如何从该规范形式推导得出。- 被签名的 EIP-191 消息,以及签名恢复出的地址为
buyerAddress。 - 严格的
issuedAt格式:YYYY-MM-DDTHH:MM:SS.sssZ,小数部分必须恰好为三位。
新增可选字段不构成破坏性变更,可以在次要版本中进行,因为旧验证器读取新声明时,对于它认识的字段仍会得到相同的 claimId。删除字段、重命名字段、调整规范形式的顺序,或改变哈希的计算方式,都会使所有曾签署的声明失效。因此,我们将这些视为不会做的变更,而不是需要通过版本升级处理的变更。
这项承诺有实际检查作为保障,而不只是口头声明。已发布的测试向量位于 examples/,分别记录了每个中间步骤:规范前像、字节长度、claimId、EIP-191 摘要、签名和预期恢复出的地址。每次 CI 运行都会由两个独立脚本验证这些数据;这两个脚本都是刻意重新实现的,只读取一个 JSON 文件,从不导入本包自身的源代码,因此不会因为与待验证的代码达成一致而误通过。格式一旦被破坏,CI 就会在任何内容发布前报错。
如果某种破坏性变更真的不可避免,我们会将其作为不同包名下的新主版本发布,旧版本会继续正常工作并持续发布;代码变更前,变更原因会记录在 DECISIONS.md 中。我们不会更改固定了某个提交的各方所依赖的内容。
分享你自己提交的声明,不依赖主机(D-006)
get_delivery_history 是否可信,取决于 MCP 服务的运营者是否诚实:请参阅该工具响应中的 note 和 DECISIONS.md(D-006)。显示的每条声明都确实存在(自 2026-09-06 起,读取时也会重新验证签名,而不只是在写入时验证),但没有任何东西能证明主机展示的是它实际持有的完整集合。
如果你是亲自提交声明的买方,就不必等待该主机:你已经亲自签署了该声明,因此可以直接向持怀疑态度的交易对手出示,绕过任何主机。
// export-my-claims.mjs
import { claimsForSeller } from "capacity-attest/dist/ledger.js";
const myAddress = "0x..."; // your buyerAddress
const seller = "0x..."; // the seller in question
const mine = (await claimsForSeller(seller)).filter(
(c) => c.buyerAddress.toLowerCase() === myAddress.toLowerCase(),
);
console.log(JSON.stringify(mine, null, 2));
列表中的每条声明都可以通过 verifyClaim() 独立验证(见上文),接收方无需信任你的安装或任何主机。这无法解决可发现性问题(D-005:如果你不分享自己的声明,别人如何找到它)或所有买方整体的完整性问题(D-006:这只能证明你提交了什么,不能证明主机是否向其他买方隐瞒了内容),但它为你提供了一种具体且免费的方式,无需信任主机即可证明某一项具体争议。
本地运行
npm install
npm run build # tsc -> dist/
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run demo # end-to-end local demo with TEST keys, no live infrastructure
npm start # start the MCP server over stdio (e.g. for Claude Desktop/Code as a local MCP server)
账本位置可通过 CAPACITY_ATTEST_DATA_DIR 配置(默认值:此软件包中的 ./data)。测试和演示始终使用各自独立的一次性临时目录,不会使用真实的 data/ 文件夹。
适用于需要网络端点的部署的 HTTP 可访问版本
一些 MCP 注册表和目录要求先提供可访问的 HTTPS 端点,才会收录服务。capacity-attest-http(src/http-server.ts)就是此类版本:一个纯 Node HTTP 服务,通过 POST /mcp 使用 MCP Streamable HTTP 传输。
它的范围刻意小于上文的 stdio 服务:只公开两个只读且无副作用的工具(get_delivery_history、resolve_agent_identity)。有意不提供 record_delivery。stdio 服务的账本是为单次本地安装设计的;将写入操作放在公开且未经身份验证的 HTTP 端点后面,会引出一个实际问题(匿名调用者写入的是谁的账本?),而此文件并未替你解答。完整理由以及如何应用 4 项强制检查(身份验证、数据验证、暴露控制、速率限制),请参阅 http-server.ts 顶部的注释。
npm run start:http # listens on :8402 by default, override with PORT=
curl -X POST http://localhost:8402/mcp \
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
架构
src/
schema.ts DeliveryClaim zod schema + content-addressing (computeClaimId, canonicalize)
signing.ts sign/verify a claim (ethers, EIP-191 personal-sign)
ledger.ts append-only JSONL storage (data/claims.jsonl), never mutated
tools.ts the actual logic behind both MCP tools, transport-agnostic
config.ts where the ledger directory lives, lazy so tests can override it
index.ts MCP server wiring (registers record_delivery + get_delivery_history)
examples/demo.ts end-to-end local example with TEST keys
tools.ts 保存实际的业务逻辑;index.ts 只负责将其转换为 MCP 工具调用。这样,测试和演示就可以直接调用相同的逻辑,而无需启动 stdio 传输。
与 x402 的关系
本项目本身既不验证也不结算 x402 付款——这些操作已在付款步骤中完成(例如,可参阅此生态中的 mcp-paywall/src/x402.mjs,其中包含完整的 EIP-3009 验证和结算实现)。settlementRef 只是指向已完成的结算。这也意味着,与真实 x402 促成方进行的 MVP 集成可以保持简单:settlementRef 是自由文本,前提是买方如实填写。后续版本可以选择针对真实促成方验证此字段(TODO,不在此 MVP 范围内)。
与 AWS Bedrock AgentCore Payments 的关系
没有重叠,也不存在竞争:它们处于流程链条中的不同环节。Bedrock AgentCore Payments(自 2026 年起由 Amazon 提供)负责处理支付步骤,直到“商家验证支付凭证……并返回请求的内容”为止(AWS 官方文档)。该凭证证明的是已支付,而不是已交付:在此步骤之后,系统并未记录 Agent 是否实际收到承诺提供的内容。这正是 capacity-attest 发挥作用的地方。与上文的 x402 一样,本项目不结算支付,也不与支付渠道竞争——无论支付是通过哪个渠道(x402 或其他渠道)完成的,本项目都会记录支付后实际收到或未收到的内容。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。