关于 Novi Corpus
Novi Corpus 是一个 TypeScript 后端与 API,用于将 AI Agent 注册为链上法律实体,并管理金库和监护人控制。其 MCP 接口支持 Claude 和 Cursor 创建及管理实体;可选的 Hedera 测试网通道支持付费法律状态查询。
主要功能
- 01将 Agent 登记为法律实体
- 02注册身份并绑定 Agent 钱包
- 03管理实体记录与 USDC 金库
- 04通过 SIWE 验证租户
- 05支持可选的 Hedera 测试网支付通道
适用场景
- 01创建法律实体并绑定 Agent
- 02查看租户拥有的实体
- 03为实体金库注资
- 04通过付费验证查询法律状态
MCP 相关
API 同时提供供 Claude 和 Cursor 使用的 MCP 端点,可识别租户、创建 Agent、列出和查询实体并为金库注资。启用 Hedera 通道后,还提供账户关联、策略检查和支付报告工具。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://api.novicorpus.com/mcpclaude mcp add --transport http com-novicorpus-legal-body https://api.novicorpus.com/mcp{"mcpServers":{"com-novicorpus-legal-body":{"type":"http","url":"https://api.novicorpus.com/mcp"}}}在 Cursor 中打开{"servers":{"com-novicorpus-legal-body":{"type":"http","url":"https://api.novicorpus.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"com-novicorpus-legal-body":{"type":"http","url":"https://api.novicorpus.com/mcp"}}}{"mcpServers":{"com-novicorpus-legal-body":{"serverUrl":"https://api.novicorpus.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
https://api.novicorpus.com/mcp需要授权工具
详细介绍
Agent Legal Body — 后端(“大脑”)
与框架无关的 TypeScript 后端,用于将 AI Agent 接入 Arc 上的链上法律实体:生成运营协议 → 注册 ERC-8004 身份 → 通过 Factory 部署并连接 LegalManager + AgentTreasury(单笔原子交易)→ 绑定 Agent 钱包 → 持久化。由 CLI 驱动,已完成全面测试。
前置条件
- Node >= 22、npm。集成测试需要 Foundry(forge/anvil)位于 PATH 中。
- 合约已部署到 Arc 测试网(参见
../script/Deploy.s.sol和../addresses.arc-testnet.json)。
设置
cp .env.example .env # 填写 PLATFORM_PRIVATE_KEY、FACTORY_ADDRESS、GUARDIAN_ADDRESS、OPERATOR_PRIVATE_KEY
npm install
npm run gen:abis # 每次执行 `forge build` 后重新生成类型化 ABI
测试
npm test # 单元测试 + anvil 集成测试(跳过实时测试)
ARC_E2E=1 npx vitest run test/e2e.arc.live.test.ts # Arc 测试网实时测试(消耗 USDC 作为 Gas)
CLI
npm run cli -- create-entity --config agent.example.json --id agent-1
npm run cli -- create-entity --config agent.example.json --id agent-1 --fund 50.00
npm run cli -- get-entity agent-1
npm run cli -- list-entities
npm run cli -- fund-treasury agent-1 25.00
角色(v1)
- manager = 平台密钥(Factory 所有者;发送
createEntity+setAgentWallet)。PLATFORM_PRIVATE_KEY。 - guardian = 人类注册者地址(链上暂停/否决/救援)。
GUARDIAN_ADDRESS。 - operator = Agent 的支出密钥;签署 EIP-712
AgentWalletSet(绑定为agentWallet)。 v1 中使用OPERATOR_PRIVATE_KEY(LocalKeySigner);生产环境使用 Turnkey enclave 密钥(TurnkeySigner,M4.3)。
operator 签署绑定操作;manager 发送交易。operator 密钥绝不会发送 Gas。
Arc 测试网实时 E2E — 操作手册
PLATFORM_PRIVATE_KEY必须是 Factory 所有者密钥(createEntity是onlyOwner),且必须有 Arc 测试网 USDC 余额(USDC 是 Arc 上的 Gas 代币)。已部署的所有者记录在../addresses.arc-testnet.json中;水龙头:https://faucet.circle.com。OPERATOR_PRIVATE_KEY可以是临时密钥——它只负责签名,从不发送 Gas,也从不持有资金。GUARDIAN_ADDRESS可以是任何与 manager/operator 不同的地址。- 运行:
ARC_E2E=1 npx vitest run test/e2e.arc.live.test.ts(可选设置ARC_E2E_TAG=<label>,以使用稳定的幂等键)。断言实体状态变为bound,且getAgentWallet(agentId) == operator。
链下 EIP-712 域和 AgentWalletSet typehash 会与实时注册表进行验证,因此绑定签名可确保正确,不会出现“签名错误”的意外。
Wizard REST API(npm run api,默认 :8789)
面向 Web 向导的多租户接入 API。租户 = 控制器钱包(SIWE 登录)。
身份验证(SIWE → Bearer JWT)
GET /auth/nonce→{ nonce }- 使用 nonce 构建 EIP-4361 消息,并用钱包签名。
POST /auth/verify { message, signature }→{ token, address, expiresAt }- 在受保护的路由中发送
Authorization: Bearer <token>。过期后重新进行身份验证。
配置项
| Key | 默认值 | 说明 |
|---|---|---|
AUTH_JWT_SECRET | dev-insecure-secret-change-me-please | 最少 16 个字符。生产环境中请修改。 |
AUTH_JWT_TTL_SEC | 3600 | JWT 有效期,单位为秒 |
WEB_ORIGIN | * | CORS 允许的来源 |
SIWE_DOMAIN | localhost | EIP-4361 域名 |
PASSKEY_RP_ID | localhost | WebAuthn RP ID |
端点
| 方法 | 路径 | 身份验证 | 请求体 / 备注 |
|---|---|---|---|
| GET | /healthz | 否 | 存活状态 |
| GET | /schema/agent-spec.json | 否 | 用于入驻 spec 的 JSON Schema |
| GET | /auth/nonce | 否 | { nonce } |
| POST | /auth/verify | 否 | { message, signature } → JWT |
| GET | /passkey/challenge | 否 | 用于 WebAuthn 注册的 { challenge, rpId } |
| POST | /onboard | 是 | { spec, guardianPasskey, idempotencyKey? } → 202 { id, status }。guardian 会被强制设为调用者。 |
| GET | /entities | 是 | 租户的 EntityView[] |
| GET | /entities/:id | 是 | 单个 EntityView(若不属于调用者则返回 404) |
| POST | /entities/:id/fund | 是 | { amount }(最小单位的 USDC)→ 202 { id, status } |
轮询 GET /entities/:id(约每 2–3 秒一次),直到状态变为终态(bound / funded / failed)。
MCP 服务(Claude / Cursor)
API(npm run api)也会将 /mcp 作为模型上下文协议服务提供,用于向 Claude/Cursor 提供 Agent 入驻和管理工具。
设置
-
运行 API(同一服务,无需新增服务):
npm run api # listens on :8789 -
登录(SIWE)并创建 MCP 密钥:
GET /auth/nonce→{ nonce }- 使用你的钱包签署消息
POST /auth/verify { message, signature }→{ token, address, expiresAt }- 使用
Authorization: Bearer <JWT token>调用POST /api-keys→{ id, key, label }— 复制key(仅显示一次)
-
在浏览器中录入 guardian 通行密钥:
GET /passkey/challenge→{ challenge, rpId }— 使用这些信息进行 WebAuthn 注册- 在浏览器中完成 WebAuthn 流程
- 使用
Authorization: Bearer <JWT token>和证明数据调用POST /passkey→{ id }— 复制id(句柄)
-
将服务添加到 Claude/Cursor: 创建或编辑
~/.claude/mcp.json(Claude CLI)或.cursor/rules/mcp.json(Cursor):{ "mcpServers": { "project-alpha": { "url": "https://<your-host>/mcp", "headers": { "Authorization": "Bearer mcp_<your-key>" } } } }将
<your-host>替换为已部署或本地 URL,并将<your-key>替换为步骤 2 中的密钥。
工具
| 工具 | 输入 | 描述 |
|---|---|---|
whoami | (无) | 返回已验证身份的租户地址 |
list_entities | (无) | 列出调用者拥有的所有 Agent 法律主体 |
get_entity | id(幂等键) | 获取单个实体;调用 onboard_agent 后轮询,直到状态为 bound |
onboard_agent | spec(对象)、passkeyId(步骤 3 中的句柄)、idempotencyKey?(可选) | 创建 Agent 法律主体;guardian 会自动设为调用者 |
fund_treasury | id(幂等键)、amount(最小单位的 USDC,6 位小数字符串) | 为已绑定实体的金库充值 |
资源
| 资源 | URI | 描述 |
|---|---|---|
agent-spec | schema://agent-spec | onboard_agent 的 spec 参数所用的 JSON Schema |
示例流程
- 读取
schema://agent-spec,了解实体所需的结构 - 使用你的 Agent 规范和 guardian 通行密钥句柄调用
onboard_agent→ 返回{ id, status: "pending" } - 使用返回的
id轮询get_entity(约每 2–3 秒一次),直到status变为bound(或failed) - 使用
id和金额调用fund_treasury,为金库充值(最小单位的 USDC) - 调用
list_entities,查看所有自有法律主体
Hedera 通道(ETHOnline 2026)
Novi Corpus 为 Hedera 测试网新增了第二条由功能标志控制的支付通道,专为 ETHGlobal
ETHOnline 2026 的 “AI & Agentic Payments on Hedera” 赛道构建。Arc 通道通过
Circle 结算;Hedera 通道则以 HTS USDC 为 GET /verify/:publicId(一项付费的法律状态核查)定价,
并通过 x402 v2 和 Blocky402 促进器结算。Arc 通道不受影响;关闭功能标志时,本节中的所有内容在运行时都不存在。
托管采用自托管模式,但有所约束。你的 Agent 运行时持有自己的 Hedera 密钥,并在本地为每笔付款签名;Novi Corpus 服务从不持有或查看该密钥。人类监护人通过 1-of-2 密钥列表共同持有浮动账户,因此监护人可以随时轮换掉 Agent 密钥(revoke)。策略门由客户端和浮动账户执行,而非服务端:付款前,客户端会调用 check_policy;若被拒绝,付款就会在签名前停止。
启用
设置 HEDERA_ENABLED=1,并配置该区块中的其余变量(.env.example 中注释掉的 HEDERA_* 行)。该区块必须完整配置:如果缺少任何必需变量,服务将拒绝启动,而不会以半配置状态启动。
| 变量 | 值 | 说明 |
|---|---|---|
HEDERA_ENABLED | 1 或 true | 启用整个区块。 |
HEDERA_NETWORK | testnet | 唯一接受的值;此版本仅支持测试网。 |
HEDERA_FACILITATOR_URL | https://api.testnet.blocky402.com | Blocky402 测试网促进器。 |
HEDERA_MIRROR_URL | https://testnet.mirrornode.hedera.com | 只读结算确认。 |
HEDERA_USDC_TOKEN_ID | 0.0.429274 | HTS USDC,6 位小数。 |
HEDERA_PAYTO_ACCOUNT_ID | 你的收款账户 | /verify 付款的入账账户。必须关联 USDC 代币。 |
HEDERA_VERIFY_PRICE_USDC | 0.001(默认值) | 单次 /verify 调用的价格。 |
MCP 工具(需要具备 spend 能力的 API 密钥)
| 工具 | 输入 | 描述 |
|---|---|---|
link_hedera_account | id、accountId、publicKey | 记录实体的浮动账户。服务会从镜像节点读取账户,并且只接受由两个 ECDSA 密钥组成的 1-of-2 密钥列表,其中一个密钥必须与 publicKey 相同;另一个密钥会记录为监护人密钥。 |
check_policy | id、payee、amountUsdc、network | 根据浮动账户的 USDC 余额、实体限额、Arc 上的监护人暂停状态以及收款方允许列表,返回 { ok: true, available } 或 { ok: false, reason }(paused、over-cap、not-linked、legal-not-active 等)。允许列表会从 Arc 实时读取;若无法读取状态,则一律不允许。 |
report_payment | id、payee、amountUsdc、network、transactionId、idempotencyKey | 将已结算的交易转为账本记录。只有镜像节点显示两条转账路径上的 USDC 转账后,才返回 { status: settled };镜像节点数据滞后时返回 pending;否则返回带原因的 failed。 |
/verify 如何付费
GET /verify/:publicId 为公开且无需身份验证的接口,但需要付费。该路由仅响应 GET 请求:任何其他方法都会被拒绝,并返回 405 和 Allow: GET。请求未携带付款标头时,会返回 402,并在 PAYMENT-REQUIRED 标头中提供价格和付款要求。客户端使用自己的 Hedera 密钥签署付款并重新提交;facilitator 会在 Hedera 测试网上验证并结算 USDC 转账,同时支付网络费用,因此备用资金账户无需 HBAR。facilitator 成功结算后,该路由会提供证明正文(主体、状态、成立信息、控制方标记、运营协议哈希和版本、issuedAt、expiresAt);如果结算未成功,则返回不带正文的 402。Novi Corpus 不会仅凭 facilitator 的回复来记账:只有在客户端的 report_payment 从镜像节点读回交易,并确认两笔转账的 USDC 代币均匹配后,账本记录才会标记为已结算(network = hedera:testnet,batch_ref = <mirror transaction id>)。设置 NOVI_ATTESTATION_KEY 后,正文会带有签名;请参阅“已签名证明”。
已签名证明(拉取请求 3)
设置 NOVI_ATTESTATION_KEY 后,/verify 正文会包含 attestor(密钥地址,也会作为 hedera.attestor 发布在 /metadata/:publicId 中)和 EIP-712 signature。域为 { name: "Novi Corpus Attestation", version: "1" },不含链 ID,也不含验证合约。唯一的主要类型为 LegalBodyAttestation,包含以下按顺序排列的十二个字段:publicId string、agentId string、treasury address、uaid string、standing string、formationStatus string、formationEnvironment string、humanVerified bool、oaHash bytes32、manifestVersion uint256、issuedAt uint256、expiresAt uint256。每个字段均从所提供的正文中读取。
验证方必须了解以下内容:
- 签名中的时间戳为
issuedAtUnix和expiresAtUnix(Unix 秒)。ISO 格式的issuedAt和expiresAt字符串仅为方便阅读,不在签名范围内;请读取这对 Unix 时间戳。 - 空值映射在签名和验证时采用相同规则:
oaHash为 null →0x+ 64 个零,manifestVersion为 null →0,uaid为 null →"",agentId为 null →"",formation为 null → 两个成立信息字段均为"",treasury为空 → 零地址。 subject.name、subject.registry、World 凭证以及formation.filed/formation.einIssued布尔值均不在签名范围内。根据已签名的formationStatus推导这两个布尔值(filed= 状态为filed或complete;einIssued= 状态为complete),其余内容视为显示数据。- 十六进制大小写不影响签名(小写的
treasury仍可通过验证),额外的顶层 JSON 键也不会导致验证失败。只读取十二个已签名字段。 src/hedera/attestation.ts中的verifyAttestation(body, attestor, signature)会根据正文重新计算类型化数据;遇到任何格式错误的输入时会返回false,而不会抛出异常。
V2 说明:客户端会对 402 响应中指定的任何资产和金额进行签名,而 check_policy 不会检查资产。在将客户端指向非自营服务前,请先固定资产。
可移植身份(拉取请求 2)
每家 Novi Corpus 公司都会在 Hedera 测试网上获得一个 ERC-8004 身份和一个通用 Agent ID。
scripts/hedera-register-identity.mts使用平台运营方账户,在 Hedera 身份注册表 (0x8004A818BFB912233c491871b3d84c89A494BD9e,链 ID 为 296)上注册公司, 并推导其 HCS-14 UAID。--from-prod <publicId>会从已部署的后端读取公司的公开数据, 发送交易需要使用--execute --yes(重复运行会铸造第二个身份); 它会打印--record命令,将结果写入已部署的数据库,而不调用链。--record会从数据库行重新推导 UAID, 并拒绝不匹配的命令行。- UAID 通过推导得出,绝不索引:
uaid:aid:<sha384-base58>;uid=<Arc agent id>;registry=novicorpus;proto=mcp;nativeId=eip155:<Arc chain>:<treasury>。src/hedera/uaid.ts复制了标准 SDK 的规范化逻辑,因此结果与@hashgraphonline/standards-sdk的计算结果一致,同时不依赖该 SDK。 - 公司关联后,
GET /metadata/:publicId会列出两项注册信息(先 Arc,后 Hedera)、uaid,以及 一个hedera区块(float 账户、verifyUrl、profileUrl)。GET /metadata/:publicId/profile会提供 HCS-11 配置文件。
从 Hedera 解析 Novi Corpus 公司。 除了 Novi Corpus 自身,Hedera 上没有任何内容能将 UAID 与 float 账户关联;发现流程由 Novi Corpus 解析器负责,设计文档 D23 对此有明确说明。分为三步:
从 UAID 中解析出 nativeId,调用 GET /legal-bodies/<treasury address>,再根据其
metadata 链接找到公司的配置文件。float 账户的备注为 hcs-11:<profile URL>,通过 HTTPS 提供,
这是浏览器和 HTTP 客户端都能跟进的有效 HCS-11 引用;标准 SDK 解析器只跟进
hcs:// 引用,因此基于 SDK 的 Agent 需要使用上述三步流程。
运行客户端
面向客户的命令位于 back/hedera-client(包 @novicorpus/hedera-client,
可执行文件 novi-hedera)。使用 op run --env-file=.env.tpl -- npx tsx src/cli.ts <command> 运行,
这样密钥只会从 1Password 注入子进程(模板列出项目标题,不包含值)。
provision会创建 float 账户(由 guardian 使用 USDC 为其注资),在账户仍为空壳时设置其 1-of-2 密钥 列表,并设置账户备注。--memo-only会重新设置备注。link会通过调用link_hedera_account,在 Novi Corpus 中记录已配置的账户。revoke会从 guardian 中轮换移除 Agent 的密钥,即链上紧急停用开关。pay <url>会调用check_policy,支付 Novi Corpus x402 路由,并报告结算结果。
实际运行记录,2026-09-12(测试网)
记录在计划文档中(docs/plans/2026-09-10-hedera-rail.md,任务 8),针对运行在本地后端、
包含一条 FormationE2E_1 公开数据种子记录的环境:
provision在 float 账户0.0.10450558上设置了 1-of-2 密钥列表;link返回ok: true。- 首次尝试时,
pay成功结算了/verify/9f8003f5-4c70-435a-9980-9a54625691b7上的付款,将 0.001 USDC 支付至0.0.10412694: HashScan [email protected],CRYPTOTRANSFER SUCCESS,手续费由服务商支付;report_payment -> settled;账本记录hedera:testnet|settled|0.0.7162784-1789178320-131369376|1000。
演示:五个环节
ETHOnline 2026 录制流程,按顺序进行。完整流程、凭据和备用方案:
../docs/runbooks/hedera-demo.md。客户端命令在
back/hedera-client 中运行,guardian 脚本在 back/backend 中运行,所有操作均针对生产环境
(https://www.novicorpus.com/backend),使用测试网资金。
| # | 命令 | 预期最后一行 |
|---|---|---|
| 1 | demo-buyer <uaid> | settlement: OK https://hashscan.io/testnet/transaction/<tx>,其上方为 signature valid: true |
| 2 | guardian-pause.mts pause --treasury <treasury> | paused: true |
| 3 | demo-buyer <uaid> | policy denied: paused,退出码为 2,没有 HashScan 链接 |
| 4 | guardian-pause.mts unpause --treasury <treasury>,然后执行 revoke | paused: false,然后是 SUCCESS 和 after: key ECDSA_SECP256K1 |
| 5 | demo-buyer <uaid> | HTTP 402 和 PAYMENT-RESPONSE transaction_failed <hashscan>,退出码为 1 |
环节 3 和 5 是该支付通道旨在处理的两种拒绝情形,且拒绝发生在不同位置。
环节 3 是客户端拒绝:check_policy 在支付钩子中作出响应,买方在其密钥签署任何内容之前就中止,因此不会产生交易,也不会有链接(设计 D2)。环节 5 是账本拒绝:Agent 的密钥已不在浮动账户上,促进器仍会提交转账,而 Hedera 会以 CRYPTOTRANSFER INVALID_SIGNATURE 拒绝该转账。
仅用于演示,请勿在生产环境中运行
这些功能仅供 ETHOnline 2026 演示使用。除非设置了 HEDERA_DEMO_LOCAL=1,否则都会拒绝运行;当 NODE_ENV=production 时会直接拒绝运行,并将 DEMO ONLY 作为第一行输出。
scripts/demo/seed-public-entity.mts --from-prod <publicId> --tenant <address>会根据生产实体的公开数据(/transparency以及在 Arc 上读取的工厂数据),在本地数据库中写入一条记录,以便在不触及真实数据的情况下进行合并前检查。将FACTORY_ADDRESS设置为创建该实体时使用的生产工厂地址。novi-hedera demo-buyer <uaid>根据通用 Agent ID 解析 Novi Corpus 公司,向其/verify路由付款,并在离线状态下使用响应内容中指定的attestor,检查返回内容中的 EIP-712 签名。该过程包含三次跳转(/legal-bodies/:address、元数据链接、付费路由),每次都会打印为→ GET …。NOVI_API_BASE用于设置基础地址,且没有默认值。虽然目标是已部署的后端,仍受保护。
v2 加固
团队正在跟踪已知的生产环境加固事项(崩溃安全性、并发、Turnkey 等)。 这些事项均不会阻碍测试网演示。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。