mcpField
R
reader

reader

远程服务
github.com/cyninzf金融数据11 天前更新
代码仓库

关于 reader

reader 是一项开源服务,可从公开区块链数据重建 Agent 的付款权限和活动记录。它面向需要可复现且带引用事实、而非评价结论的团队和分析人员。

主要功能

  1. 01索引付款权限及相关事件
  2. 02读取 NablaZ 和第三方记录
  3. 03引用链、区块、交易和日志信息
  4. 04提供复现每条日志的命令
  5. 05通过只读 API 查询地址事实
  6. 06支持 Arbitrum One 和 Base

适用场景

  1. 01核验地址记录的支出权限
  2. 02追踪付款及其权限条款
  3. 03通过 RPC 复现引用的链上证据
  4. 04查看 Agent 反馈和钱包历史

MCP 相关

托管服务通过 Streamable HTTP 提供 MCP 服务,包含一个名为 read_subject 的工具。MCP 客户端可提交链 ID 和地址,以获取已索引且带引用的事实。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://read.nablaz.io/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

详细介绍

nablaz-sdk

一款用于读取 Agent 付款权限的开源工具。它根据公开的链上数据,还原某个地址获准支出的金额、实际支出金额及相关条款,并将每条事实与可重现该事实的命令放在一起。它读取 NablaZ 记录和受托人金库、Coinbase 支出权限、MetaMask 委托以及 Agent Credit Lines。

它不持有任何密钥,无需账户或 API 密钥,只要有 RPC 端点,就能在任何地方运行。

读取内容

Arbitrum One 和 Base 均已启用。NablaZ 合约目前仅部署在 Arbitrum One 上,因此在 Base 上,读取器只会索引第三方来源。

两个链上的第三方来源:

  • Coinbase SpendPermissionManager:SpendPermissionApproved、SpendPermissionUsed、 SpendPermissionRevoked。
  • MetaMask DelegationManager(委托框架 v1.3.0):RedeemedDelegation,并解码所有 caveat。对于每次兑换,读取器都会读取交易收据,并保留委托人发出的 ERC-20 Transfer。单独的兑换不构成付款;只有这类 Transfer 才算。
  • 在已配置的贷款方处读取 Agent Credit Lines(Borrowed、Repaid、Defaulted)。目前这两个链上都没有已知的贷款方,因此尚未注册任何贷款方。解码器附带测试;如果没有索引到任何内容,读取结果会显示“没有索引到内容”及其区块范围。
  • ERC-8004:来自“Reputation Registry”的 NewFeedback(谁对哪个 agentId 进行了评分,以及评分发生在哪里;绝不读取反馈值、小数位数、标签、端点或 URI),以及来自 Identity Registry 的 MetadataSet 和 ERC-721 Transfer 中的 agentWallet 和所有者历史记录。地址来自 src/generated/erc8004.json(其中固定了供应商提交版本)。

已部署 NablaZ 的链上来源:

  • NablaRecord 中的 RecordEntry,包含所有字段。
  • NablaAccountFactoryPermanent 和 AccountRegistryV6 中的 AccountCreated,用于发现账户。
  • 每个已发现账户代理上的 ERC-1967 Upgraded。
  • 当授权方或发送方是受托人金库时,读取 USDC AuthorizationUsed 和 Transfer。金库仅通过日志发现:PAY_AUTHORIZED 条目会指出金库,而同一笔交易中的资金 Transfer 会确认该金库。

写入内容

表每行对应
record_entriesRecordEntry 原始记录
obligation_pairs按 obligationRef 分组的 OBLIGATION_OPENED / REPAY / OBLIGATION_CLOSED 记录
vault_payments结算:某个金库的 AuthorizationUsed 与其 Transfer 配对,以及该笔付款所依据的授权和信封
implementation_history每个账户的 Upgraded 日志或 IMPLEMENTATION_CHANGED 记录
counterparties不重复的(主体、交易对手方)配对,包含首条证据和计数
accounts、grants、vaults、vault_fundings上述各表所依据的发现和配对状态
factory_accounts在永久工厂上创建的账户,以及来自工厂自身事件的所有者
external_permissions支出权限或已赎回的委托,包含其类型、标签和解码后的条款
external_paymentsSpendPermissionUsed,或赎回交易中来自委托方的 ERC-20 Transfer
external_redemptionsRedeemedDelegation,无论是否发生价值转移
credit_line_events配置的贷款方处发生的 Borrowed / Repaid / Defaulted 事件
feedbacksERC-8004 NewFeedback:agentId、评分者、反馈索引;不含价值、标签或 URI
agent_wallets代理的 agentWallet 键对应的 ERC-8004 MetadataSet:agentId 和钱包(清除时为 null)
agent_ownersERC-8004 身份 Transfer(ERC-721):agentId 和新所有者

行中记录事实和计数。读取器只陈述事实,不对任何主体作出判断。

在 vault_payments 中,提交结算交易的一方(tx.from)记录为 submitter。它绝不会被视为交易对手方;交易对手方是 Transfer 的接收方。

结算不会写入 NablaRecord 记录。付款记录由两部分组成,由读取器配对:账户在预留资金至被授权方金库时写入的 PAY_AUTHORIZED 记录(预留记录,位于 record_entries),以及 USDC 自身的 AuthorizationUsed 和 Transfer 事件(结算记录,位于一行 vault_payments 中)。引用一笔付款时,须同时引用两者:PAY_AUTHORIZED 日志(区块、交易哈希、日志索引),以及 USDC 结算交易及其区块。

引用规则

日志是事实依据;此读取器只是便于查询日志的工具。每行都包含其证据的链 ID、区块号、交易哈希和日志索引,以及可从任意 RPC 返回该日志的 cast logs 命令和等效的原始 eth_getLogs 请求。如果无法用该行的命令复现该行内容,就是一个错误。

有一个字段读取的是状态,而非日志:vault_payments 中的信封过期时间。它标记为“状态读取 — 需要归档 RPC”。读取器会在区块 N−1 和结算区块 N 调用账户授权合约上的 envelopeOf(account, granteeKey, token),并将两次调用都保存为 cast call --block 命令。如果两次读取结果一致,就保存该值。如果结果不同,则表示信封在区块 N 内发生了变化,该字段会保存为“无法确定”,并引用两次读取结果。2026-10-23,通过 https://arb1.arbitrum.io/rpc 在距离链头 50,000 个区块处进行相同的历史 eth_call,10 次中有 6 次返回结果,另外 4 次返回“historical state … is not available”,因此不能依赖公共端点获取此字段。其他所有内容都可在任意 RPC 上通过日志重建。

读取

GET /read/:chainId/:address 会返回某个地址的所有已索引事实。无需密钥:该端点读取公开日志。

{ "subject": "0x…", "chainId": 8453, "asOfBlock": "53160200",
  "facts": [ { "source": "metamask:delegation_payment", "label": "(b) exact execution, once", "shape": "b",
               "terms": { "payer": "0x…", "payee": "0x…", "token": "0x…", "amount": "…" },
               "cite": { "chainId": 8453, "block": "…", "tx": "0x…", "logIndex": 0 },
               "reproduce": "cast receipt 0x… --rpc-url \"$BASE_RPC_URL\" --json | jq …" } ],
  "selfDealing": null, "exposure": null,
  "cShare": { "chainId": 8453, "asOfBlock": "53160200",
              "byToken": { "0x…": { "count": { "c": 0, "total": 1 }, "value": { "c": "0", "total": "…" } } } },
  "notes": [ "no Agent Credit Lines lender registered on this chain",
             "SpendPermissionManager permissions and spends for this address: nothing indexed (blocks 53160000..53160200)" ] }
  • facts:每条记录条目、金库付款、支出权限、委托、付款、赎回和信用额度事件各一条。每条都会注明来源和权限标签、区块、交易和日志索引,以及一条可从任意 RPC 获取相同日志的单行命令。
  • selfDealing(仅限 NablaZ 账户):付款对象数量、付给同一控制者名下账户的金额占比、付给无记录付款对象的金额占比,以及句子“A payee controlled by the same person under another key cannot be detected from chain data.”。
  • exposure(仅限 NablaZ 账户):按授权和代币列出各窗口中剩余额度的最小值,以及金库余额;同时说明链上无法观测未完成的授权。
  • cShare:按代币列出本次读取中标记为 (c) 的付款事实数量和金额,以及所有付款事实的总数和金额;绝不跨代币求和。
  • notes:每个未返回结果的来源(“未索引任何内容(区块 X..Y)”,或者索引器落后于来源起始区块时显示“已索引至 X;来源从 Y 开始”),以及每条无法确定的事实,并以文本说明。

每个权限标签都属于以下五种形式之一:

形式标签来源
(a)按周期 / 总额 / 每次调用 / 每次执行 / 流式的额度Coinbase 支出权限;MetaMask 金额执行器;NablaZ CAM V4 窗口(规范的 NablaZ 账户会标注“按构造符合授权范围”)
(b)精确执行,执行一次 / N 次 / 次数不限MetaMask 精确调用执行器;LimitedCallsEnforcer 或单次使用执行器中的计数
(c)无法确定不在任何厂商列表中的执行器、无法解码的条款、非规范的 NablaZ 账户
(d)金额或调用次数不受限制限制条件仅限制调用或赎回者的委托
(e)第三方证明,注明写入者Agent Credit Lines;其他写入者创建的记录条目;ERC-8004 反馈(注明评分者)

MetaMask 执行器表由厂商在固定提交版本中的 Deployments.md 生成(scripts/gen-enforcers.ts、src/generated/enforcers.json)。如果厂商的主分支列出了表中没有的执行器,测试就会失败。

单行命令才是事实依据。 读取器是对日志的便捷封装。每个 reproduce 字段都是一条 cast 命令,你可以使用 $ARB_ONE_RPC_URL 或 $BASE_RPC_URL 中的 RPC URL 自行运行。

反馈溯源

当主体是 agentWallet 或 ERC-8004 agentId 的所有者时,关于该 agentId 的每条 NewFeedback 都会成为一个 erc8004:feedback_grounding 事实(R-D2B-2)。如果评分者向身份的付款地址发起的 ERC-20 Transfer 在该反馈之前结算(按区块排序,同一区块内再按日志索引排序),则该反馈具有溯源依据,无论代币或路径如何(R-S191-11)。付款地址按转账所在区块解析,绝不使用之后的地址:先在该区块调用 getAgentWallet,否则调用该区块的 ownerOf;事实会说明适用的是哪项绑定(R-S191-16)。在身份存在之前发生的转账不构成溯源依据(“付款区块时身份不存在”)。反馈区块时的钱包地址会与溯源依据一并报告(“feedback block 的钱包:

”或“feedback block 的钱包:已清除”),但绝不会用作判定条件(R-S191-12)。

普通转账不会被索引。读取时,读取器会调用 eth_getLogs,设置 topic0 = Transfer、topic1 = 评分者、任意代币地址,并指定从 Identity Registry 的起始区块(或该实例的起始区块)到反馈区块的范围;事实会注明该范围。候选地址来自身份的 agentWallet 历史记录(MetadataSet)和所有者历史记录(ERC-721 Transfer),并会在转账所在区块逐一确认。来自评分者自己的受托人金库的结算视为由评分者付款(R-S191-17)。不会读取原生代币转账(“未读取原生代币转账”,R-S191-18)。如果某笔转账属于读取器的付款事实,则保留其权限标签;其他转账会标记为 (c),原因是“直接转账,没有权限对象”。事实还会说明评分者是否为主体,以及当双方都是 NablaZ 账户时是否共用一个控制者。事实不包含金额、小数位数、标签或 URI,也不会获取反馈文件(“未读取 feedbackURI”)。

test/fork/afg.fork.test.ts 会在 Agentic Finance Graph 的 Base 测试夹具中,对 816 条具有溯源依据的反馈条目运行此溯源检查(CC BY 4.0,见 NOTICE),并将比较结果写入 docs/reader/afg-agreement-2026-10-20.csv。docs/reader/retroactive-binding-2026-10.md 说明了其余差异。

托管读取

https://read.nablaz.io 在同一实例中运行读取器和下方的 MCP 服务,支持两条主链(链 ID 为 42161 和 8453),并从每个来源的部署区块开始索引。它无需密钥,且仅提供读取功能。它有两个入口:

  • GET https://read.nablaz.io/read/:chainId/:address:返回本地 GET /read 所返回的 JSON。
  • POST https://read.nablaz.io/mcp:MCP 服务的 Streamable HTTP 传输,包含一个工具 read_subject。对于需要 URL 的 MCP 客户端:{ "type": "http", "url": "https://read.nablaz.io/mcp" }。

两个入口都会按客户端 IP 限流;超过限额的请求会收到 429 响应和纯文本正文。此外,GET /live(进程正在运行)会返回状态码和简短文本;GET /ready(索引已追上)在就绪时返回 HTTP 200 和空正文,未就绪时返回 503 和 {"ready":false};除此之外不提供任何内容:没有状态、指标或计数端点。读取基于已索引的区块,并引用合约自身的日志和状态,因此每条事实都可以通过你自己的 RPC 和一行命令进行核查。部署配置包括 fly.toml、Dockerfile 和 scripts/reader-start.sh; docs/runbooks/hosted-read.md 列出了读取器读取的变量、两个健康检查路径以及数据库备份计划。

在 Claude 中使用托管版读取器

阅读 NablaZ 的开放记录:受权限约束、带链上引用的 Agent 操作。证据,而非裁决。

设置。 在 Claude 中,依次选择 Settings → Connectors → Add custom connector → https://read.nablaz.io/mcp → No sign-in (该服务无需密钥)。也可通过普通 HTTP 执行相同读取: GET https://read.nablaz.io/read/{chainId}/{address}。

示例。

示例 1 — 读取某个主体的记录。 提示词:“使用 NablaZ Reader,查询链 42161 上 0x8E65fa412e14c1859a9a278fdEFDE89A3c15b11c 的记录。” 执行过程:read_subject 调用 GET /read/42161/<address>,并返回该账户的已索引事实; 每条事实都附带自己的区块编号和交易引用,付款则同时引用两部分——授权记录和结算交易。

示例 2 — 每笔付款所依据的权限。 提示词:“这些付款各自依据什么权限进行?” 执行过程:每条付款事实都会根据条款形式附带权限标签(精确执行、额度授权、无限额、无法判定或第三方证明),并附带指出其来源权限系统的来源标签。

示例 3 — 没有记录的主体。 提示词:“查询链 42161 上 0x0000000000000000000000000000000000051900 的记录。” 执行过程:读取器会回答“未索引任何内容”,并同时说明已覆盖的区块范围——空结果会注明其覆盖范围;它绝不会声称相关内容不存在。

隐私。 读取器无需密钥,也不持有用户账户;它提供公开的链上数据,且只记录运行服务所需的信息。完整政策:https://nablaz.io/privacy

支持。 请在此代码库提交 GitHub 问题,或联系 [email protected]。

在本地运行

以下所有内容都在你的计算机上运行:读取器、MCP 服务和技能。需要 Node 22.12+ 和 pnpm。使用干净的代码检出目录:

pnpm install --frozen-lockfile
export READER_ARBITRUM_RPC_URL=...             # Arbitrum One RPC; archive for the envelope and exposure reads
export READER_ARBITRUM_GROUNDING_RPC_URL=...   # Arbitrum One RPC for backfill eth_getLogs and grounding reads
export READER_BASE_RPC_URL=...                 # Base RPC
export READER_BASE_GROUNDING_RPC_URL=...       # Base RPC for backfill eth_getLogs and grounding reads
export PONDER_TELEMETRY_DISABLED=true
export READER_EXTERNAL_FROM=42161:518780000,8453:53160000   # optional; see below
pnpm reader                          # = cd packages/reader && pnpm start --schema reader

每条链需要两个 RPC URL,分别用于两种角色,且两者都是必需的;同一个 URL 可以承担两种角色。第一个 URL 负责跟踪最新区块和读取状态。第二个 URL 负责处理所有按区块范围执行的 eth_getLogs(回填和用于事实依据的读取),因此应支持无限范围。只有第一个 URL 出错时,跟踪最新区块的调用才会回退到第二个 URL;用于事实依据的读取绝不会使用第一个 URL。

读取器在 localhost:42069 上提供服务。/ready 返回 200 后,表示已追上进度,读取内容会截至已索引区块:

curl localhost:42069/ready
curl localhost:42069/read/42161/0x8E65fa412e14c1859a9a278fdEFDE89A3c15b11c

数据表存储在 packages/reader/.ponder/ 下的本地 PGlite 数据库中。RPC URL 只从环境中读取,不会写入代码库。使用上方的 READER_EXTERNAL_FROM 行时,首次运行大约花了十分钟才追上两条链的进度(2026 年 10 月 27 日)。

第三方数据源从其部署区块开始,涵盖数年的历史记录。 READER_EXTERNAL_FROM 可按链指定较晚的起始区块。该区块之前的事实不会被索引,每次读取的备注都会注明读取范围。READER_CHAINS=8453 可将实例限制为一条链; READER_SOURCES=external(或 nabla)可将实例限制为一个数据源组。

MCP 服务

packages/mcp 是一个 MCP 服务,默认使用 stdio,提供一个工具 read_subject(参数为 chainId、address)。它调用读取器上的 GET /read/:chainId/:address,并在一行链名称和截至区块后,原样返回 JSON。它只读:没有写入或签名工具,也不持有任何密钥。读取器 URL 通过 --reader-url 或 NABLAZ_READER_URL 指定,默认值为 http://localhost:42069。

pnpm --silent mcp                    # = cd packages/mcp && pnpm start

stdout 承载协议,因此启动时不要先运行任何会向 stdout 打印内容的命令(不带 --silent 的 pnpm 会打印横幅)。对于从 JSON 配置启动 stdio 服务的 MCP 客户端:

{
  "mcpServers": {
    "nablaz-read": {
      "command": "node",
      "args": ["--experimental-strip-types", "--disable-warning=ExperimentalWarning", "/path/to/nablaz-sdk/packages/mcp/src/main.ts"],
      "env": { "NABLAZ_READER_URL": "http://localhost:42069" }
    }
  }
}
HTTP 传输

--transport http 会通过 Streamable HTTP 在 POST /mcp 上提供相同的服务和同一个 read_subject 工具。它是无状态的:没有会话、密钥、写入或签名路径。端口由 --port 或 PORT 决定(默认值为 3042)。进程会按客户端 IP 限制请求频率,每分钟上限由 MCP_RATE_LIMIT_PER_MIN 指定(默认值为 60);超限请求会收到状态码 429 和纯文本响应体。客户端 IP 是套接字对端地址,除非 MCP_CLIENT_IP_HEADER 指定了一个由前置代理覆盖的请求头(例如 X-Real-IP)。只能指定代理始终会设置的请求头:客户端可以发送的请求头,也可以由客户端伪造。GET /read/:chainId/:address 和 GET /ready 会在相同限制下转发给读取器,因此一个端口同时提供这两个入口:状态码低于 500 时原样返回;/ready 返回 503 时响应体为 {"ready":false};其他任何 5xx 响应体均为 {"error":"internal error"},读取器自身的响应体只会写入前端日志。只要前端已启动且读取器进程有响应,GET /live 就返回 200;否则返回 503,无论索引进度如何。没有 CORS 请求头,也没有计数或指标端点;其他所有路径均返回 404。

pnpm --silent mcp -- --transport http --port 3042

要将读取器和 HTTP MCP 服务作为一个实例一起运行,并读取完整历史记录,请使用以下环境变量。两个链都会被读取,每个来源都从其部署区块开始:

READER_ARBITRUM_RPC_URL=...             # Arbitrum One RPC, archive: head tracking and state reads
READER_ARBITRUM_GROUNDING_RPC_URL=...   # Arbitrum One RPC, archive, unlimited eth_getLogs range
READER_BASE_RPC_URL=...                 # Base RPC, archive
READER_BASE_GROUNDING_RPC_URL=...       # Base RPC, archive, unlimited eth_getLogs range
PONDER_TELEMETRY_DISABLED=true
NABLAZ_READER_URL=http://localhost:42069
PORT=3042
MCP_RATE_LIMIT_PER_MIN=60
MCP_CLIENT_IP_HEADER=                # the client-IP header the proxy in front overwrites; unset without one

请将 READER_EXTERNAL_FROM、READER_CHAINS、READER_SOURCES 和 READER_START_BLOCK 保持未设置状态。

在本地核实反馈归因和 (c) 占比

ERC-8004 来源属于第三方组,因此上述运行会对它们进行索引;设置 READER_EXTERNAL_FROM 后,它们会与其他第三方来源从同一区块开始。该区块之前设置的 agentWallet 不会被识别,读取结果会显示没有为其索引任何内容。接着:

curl localhost:42069/read/8453/<agentWallet>   # grounding facts, cShare, notes

整个索引中、按代币统计、在一个区块范围内标记为 (c) 的支付事实占比(请先停止读取器:此脚本会打开其数据库):

pnpm report:c-share 8453 53160000 53160200   # READER_PGLITE_DIR defaults to packages/reader/.ponder/pglite

脚本会打印输入、每个代币一行,以及可复现该计数的 SQL。Arbitrum One 上的 Vault 支付通过其账户进行标记,因此需要 READER_ARBITRUM_RPC_URL。

技能

skills/read-record/SKILL.md 介绍如何调用该工具或 GET /read、如何读取各来源及其标签格式,以及读取器不会说明的内容。skills/pay-inside-grant/SKILL.md 介绍如何从受款人 Vault 付款。

测试

pnpm typecheck
pnpm test          # unit
pnpm test:fork     # needs anvil and cast (Foundry) and the RPC variables below
NABLAZ_PROTOCOL_DIR=/path/to/nablaz-protocol pnpm test   # also checks the lineage copy against nablaz-protocol

读取器的分叉测试会读取 READER_ARBITRUM_RPC_URL(归档节点)、READER_BASE_RPC_URL 以及对应的两个 *_GROUNDING_RPC_URL;packages/sdk 的读取测试会读取 READER_ARB_RPC_URL(归档节点)。

分叉测试会运行 Arbitrum One 的 anvil 分叉,通过 TypeScript 使用 abis/ 中的 ABI 驱动线上合约,从头开始索引结果,并断言派生出的行。测试会索引两次,并要求表格完全一致。另有一项独立测试,会将 Arbitrum One 索引到第一个账户之前的区块,并要求所有表均为空。在两条链上,第三项测试会在一个固定窗口内索引第三方来源。它会通过 cast 对每个来源运行一条格式化后的一行命令,要求计数与读取器的行数一致,并打印标记为“无法确定”的抽样赎回占比。账户受款人测试会在链上工厂创建一个 NablaAccount,将其设为 TEST 账户中某项 grant 的受款人,并结算一笔 x402 支付,其受款人签名采用 PersonalSign 格式。MCP 测试会针对一个已提供服务的读取器运行 stdio 服务端,并将其输出与 GET /read 的结果进行比较。

x402

依赖最低版本为 @x402/* ≥ 2.23.0,这是 10 月 22 日 V12 披露问题的修复版本(客户端没有默认支出限额);本仓库在 packages/sdk/package.json 中固定了版本(2.28.0),支付限额由账户中的 grant 信封强制执行,而非由客户端执行。

来源

合约地址(src/generated/addresses.ts)和 ABI(abis/*.json)由固定的 nablaz-protocol 提交版本生成;每个生成文件的标头中都会记录该提交版本。读取器的 currentAccountImpl 沿袭关系、引导配置和 ProtocolConfig(packages/reader/src/generated/account-lineage.json) 复制自该提交版本及文件所记录的 blob 中的 script/expected/permanent-arbitrum.txt (packages/reader/scripts/gen-lineage.ts)。只有地址和 ABI 来自该文件:二者均已在链上公开。

许可证

MIT。请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

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

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