Novi Corpus について
Novi Corpusは、AIエージェントをオンチェーンの法的主体として登録し、トレジャリーやガーディアン制御を管理するTypeScriptバックエンドとAPIです。MCPインターフェースからClaudeとCursorで主体を登録・管理でき、オプションのHederaテストネット経路では有料の法的状態確認に対応します。
主な機能
- 01エージェントを法的主体として登録
- 02ID登録とエージェントウォレットの紐付け
- 03主体情報とUSDCトレジャリーの管理
- 04SIWEによるテナント認証
- 05オプションのHederaテストネット決済経路
活用シーン
- 01法的主体の作成とエージェントの紐付け
- 02テナントが所有する主体の確認
- 03主体のトレジャリーへの資金追加
- 04有料照会による法的状態の確認
MCP 対応
APIはClaudeとCursor向けのMCPエンドポイントも提供し、テナント確認、エージェント登録、主体の一覧・取得、トレジャリーへの資金追加を行うツールを公開します。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 バックエンドです。Arc 上のオンチェーン法主体に AI エージェントを登録します。 運営契約の生成 → ERC-8004 アイデンティティの登録 → Factory を介した LegalManager と AgentTreasury のデプロイおよび接続(1 回のアトミックなトランザクション)→ エージェントウォレットの紐付け → 永続化。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 のガス代を消費)
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 = エージェントの支出用キー。EIP-712 の
AgentWalletSetに署名します(agentWalletとして紐付けられます)。 v1 ではOPERATOR_PRIVATE_KEY(LocalKeySigner)、本番環境では Turnkey エンクレーブキー(TurnkeySigner、M4.3)を使用します。
operator が紐付けに署名し、manager がトランザクションを送信します。operator のキーがガス代を送信することはありません。
Arc テストネットのライブ E2E — 実行手順
PLATFORM_PRIVATE_KEYは Factory の所有者のキーでなければなりません(createEntityはonlyOwnerです)。また、Arc テストネットの USDC で資金を補充してください(Arc では USDC がガストークンです)。デプロイ済みの所有者は../addresses.arc-testnet.jsonに記録されています。フォーセット:https://faucet.circle.com。OPERATOR_PRIVATE_KEYには使い捨てのキーを使用できます。署名のみを行い、ガス代を送信せず、資金も保有しません。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)
ウェブウィザード用のマルチテナント登録 API です。テナント = コントローラーウォレット(SIWE ログイン)。
認証(SIWE → Bearer JWT)
GET /auth/nonce→{ nonce }- nonce を含む EIP-4361 メッセージを作成し、ウォレットで署名します。
POST /auth/verify { message, signature }→{ token, address, expiresAt }- 保護されたルートでは
Authorization: Bearer <token>を送信します。有効期限が切れたら再認証してください。
設定キー
| キー | デフォルト | 備考 |
|---|---|---|
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 | あり | 1 件の 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)は Model Context Protocol サーバーとして /mcp も提供し、Claude/Cursor からエージェントのオンボーディングと管理を行うツールを公開します。
セットアップ
-
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をコピーしてください(一度だけ表示されます)
-
ブラウザーでガーディアンのパスキーを登録します。
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 | (なし) | 呼び出し元が所有するすべてのエージェントの法人を一覧表示します |
get_entity | id(冪等性キー) | エンティティを 1 件取得します。onboard_agent の実行後、ステータスが bound になるまでポーリングします |
onboard_agent | spec(オブジェクト)、passkeyId(手順 3 で取得したハンドル)、idempotencyKey?(任意) | エージェントの法人を作成します。ガーディアンは呼び出し元に自動設定されます |
fund_treasury | id(冪等性キー)、amount(最小単位の USDC、小数点以下 6 桁の文字列) | bound 状態のエンティティのトレジャリーに資金を追加します |
リソース
| リソース | URI | 説明 |
|---|---|---|
agent-spec | schema://agent-spec | onboard_agent の spec 引数用 JSON Schema |
使用例
schema://agent-specを読み、必要なエンティティ構造を確認します- エージェントの
specとガーディアンのパスキーハンドルを指定してonboard_agentを呼び出します →{ id, status: "pending" }が返されます - 返された
idを指定してget_entityをポーリング(約 2~3 秒間隔)し、statusがbound(またはfailed)になるまで確認します idと金額を指定してfund_treasuryを呼び出し、トレジャリーに資金を追加します(最小単位の USDC)list_entitiesを呼び出して、所有するすべての法人を確認します
Hedera レール(ETHOnline 2026)
Novi Corpus は、ETHGlobal ETHOnline 2026 の「Hedera における AI とエージェント決済」トラックに向けて、Hedera テストネット上にフラグで有効化する第 2 の決済レールを追加します。Circle 経由で決済する Arc レールに対し、Hedera レールでは、有料の法的有効性チェックである GET /verify/:publicId の料金を HTS USDC で設定し、x402 v2 と Blocky402 ファシリテーター経由で決済します。Arc レールには変更を加えていません。フラグがオフの場合、このセクションの機能は実行時に一切存在しません。
カストディは、制約付きのセルフカストディです。エージェントのランタイムは独自の Hedera キーを保持し、すべての支払いにローカルで署名します。Novi Corpus サーバーがそのキーを保持したり、参照したりすることはありません。人間のガーディアンは 1-of-2 キーリストを通じてフロート口座を共同所有するため、いつでもエージェントのキーを無効化できます(revoke)。ポリシーゲートはサーバーではなく、クライアントとフロートによって適用されます。支払いの前にクライアントが check_policy を呼び出し、拒否された場合は、署名が行われる前に支払いが停止されます。
有効にする
HEDERA_ENABLED=1 と、残りの設定ブロック(.env.example 内のコメントアウトされた HEDERA_* 行)を設定します。このブロックはすべて設定する必要があります。必須変数が 1 つでも欠けている場合、サーバーは設定が不完全な状態で起動せず、起動を拒否します。
| 変数 | 値 | 備考 |
|---|---|---|
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 1 回あたりの料金です。 |
MCP ツール(spend 機能を持つ API キーが必要です)
| ツール | 入力 | 説明 |
|---|---|---|
link_hedera_account | id、accountId、publicKey | エンティティのフロート口座を登録します。サーバーはミラーノードから口座情報を読み取り、2 つの ECDSA キーで構成される 1-of-2 キーリストのみを受け付けます。そのうち 1 つは publicKey と一致する必要があり、もう 1 つはガーディアンキーとして記録されます。 |
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 で拒否されます。支払いヘッダーなしでリクエストすると、価格と支払い要件が PAYMENT-REQUIRED ヘッダーに含まれた 402 が返されます。クライアントが自身の Hedera キーで支払いに署名して再送信すると、ファシリテーターが Hedera テストネット上で USDC の送金を検証して決済し、ネットワーク手数料を負担するため、フロートアカウントに HBAR は不要です。ファシリテーターによる決済が成功すると、このルートはアテステーション本文(subject、standing、formation、controller フラグ、operating-agreement ハッシュとバージョン、issuedAt、expiresAt)を返し、成功しなかった場合は本文なしの 402 を返します。Novi Corpus は帳簿の処理において、ファシリテーターの応答だけを信頼することはありません。クライアントの report_payment が、両方の取引レッグで指定された USDC トークンを使ってミラーノードからトランザクションを読み取った後に限り、台帳の行が決済済みとして記録されます(network = hedera:testnet、batch_ref = <mirror transaction id>)。NOVI_ATTESTATION_KEY が設定されている場合、本文に署名が付与されます。「署名付きアテステーション」を参照してください。
署名付きアテステーション(プルリクエスト 3)
NOVI_ATTESTATION_KEY が設定されている場合、/verify の本文には attestor(キーのアドレス。/metadata/:publicId では hedera.attestor としても公開されます)と EIP-712 の signature が含まれます。ドメインは { name: "Novi Corpus Attestation", version: "1" } で、チェーン ID と検証コントラクトはありません。プライマリ型は LegalBodyAttestation ひとつで、次の 12 個のフィールドがこの順序で並びます。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 形式の 2 つの値を読み取ってください。 - null のマッピングは、署名時と検証時で同じように適用されます。
oaHashが null の場合は0x+ 64 個のゼロ、manifestVersionが null の場合は0、uaidが null の場合は""、agentIdが null の場合は""、formationが null の場合は両方の formation フィールドに""、treasuryが空の場合はゼロアドレスになります。 subject.name、subject.registry、World クレデンシャル、およびformation.filed/formation.einIssuedのブール値は署名対象ではありません。署名済みのformationStatusから 2 つのブール値を導き出し(filed= ステータスがfiledまたはcomplete、einIssued= ステータスがcomplete)、それ以外は表示データとして扱ってください。- 16 進数の大文字・小文字は署名に影響しないため、
treasuryを小文字にしても検証できます。また、トップレベルに余分な JSON キーがあっても検証は失敗しません。署名対象の 12 個のフィールドだけを読み取ってください。 src/hedera/attestation.tsのverifyAttestation(body, attestor, signature)は、本文から型付きデータを再計算し、不正な入力に対して例外をスローせずfalseを返します。
V2 に関する注意:クライアントは 402 に記載された資産と金額に署名します。また、check_policy では資産を確認しません。自分が運用していないサーバーに接続する前に、クライアント側で資産を固定してください。
ポータブルなアイデンティティ(プルリクエスト 2)
Novi Corpus の各企業には、Hedera テストネット上の ERC-8004 アイデンティティとユニバーサルエージェント ID も付与されます。
scripts/hedera-register-identity.mtsは、プラットフォーム運営者のアカウントから Hedera アイデンティティレジストリ(0x8004A818BFB912233c491871b3d84c89A494BD9e、チェーン 296)に企業を登録し、 HCS-14 UAID を導出します。--from-prod <publicId>は、デプロイ済みバックエンドから企業の公開データを読み込みます。送信するには--execute --yesが必要です(再実行すると 2 つ目のアイデンティティが発行されます)。 デプロイ済みデータベースに結果を記録する--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は standards SDK の正規化処理をコピーしているため、@hashgraphonline/standards-sdkに依存せず、同 SDK が計算するものと同じ結果になります。 - 企業がリンクされると、
GET /metadata/:publicIdは両方の登録情報(Arc が先、Hedera が後)、uaid、 およびhederaブロック(float アカウント、verifyUrl、profileUrl)を一覧表示します。GET /metadata/:publicId/profileは HCS-11 プロファイルを提供します。
Hedera から Novi Corpus の企業を解決する方法。 UAID と float アカウントを結び付けるものは Hedera 上にはなく、Novi Corpus 自身だけがその役割を担います。つまり、ディスカバリーは Novi Corpus のリゾルバーによって行われます(設計 D23)。手順は 3 つです。UAID から nativeId を解析し、GET /legal-bodies/<treasury address> を呼び出し、その metadata リンクをたどって企業のプロファイルを取得します。float アカウントのメモは HTTPS 経由の hcs-11:<profile URL> です。これはブラウザーや HTTP クライアントがたどれる有効な HCS-11 参照です。standards SDK のリゾルバーがたどるのは hcs:// 参照だけなので、SDK ベースのエージェントは代わりにこの 3 段階の手順を使います。
クライアントを実行する
顧客側のコマンドは back/hedera-client(パッケージ @novicorpus/hedera-client、bin novi-hedera)にあります。シークレットを 1Password から子プロセスにのみ渡すため、op run --env-file=.env.tpl -- npx tsx src/cli.ts <command> として実行します(テンプレートには項目名のみが記載され、値は含まれません)。
provisionは float アカウントを作成し(guardian が USDC で資金を提供します)、アカウントがまだ hollow の間に 1-of-2 キーリストを設定し、アカウントのメモを設定します。--memo-onlyはメモを再設定します。linkはlink_hedera_accountを呼び出して、プロビジョニング済みのアカウントを Novi Corpus に記録します。revokeは guardian からエージェントのキーをローテーションして外します。これがオンチェーンのキルスイッチです。pay <url>はcheck_policyを呼び出して Novi Corpus の x402 ルートで支払い、決済結果を報告します。
実行記録、2026-09-12(テストネット)
計画(docs/plans/2026-09-10-hedera-rail.md、タスク 8)に記録された内容です。ローカルバックエンドに FormationE2E_1 の公開データを含むシード済みの行が 1 件ある状態で実施しました。
provisionは float アカウント0.0.10450558に 1-of-2 キーリストを設定し、linkはok: trueを返しました。/verify/9f8003f5-4c70-435a-9980-9a54625691b7へのpayは、初回の試行で 0.001 USDC を0.0.10412694に決済しました:HashScan [email protected]、CRYPTOTRANSFER SUCCESS、手数料はファシリテーターが支払い、report_payment -> settled。台帳の行はhedera:testnet|settled|0.0.7162784-1789178320-131369376|1000です。
デモ:5 つの段階
ETHOnline 2026 の録画の順序です。手順全体、認証情報、フォールバックについては、
../docs/runbooks/hedera-demo.md を参照してください。クライアントコマンドは
back/hedera-client から、ガーディアンスクリプトは 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 は、この決済レールが想定する 2 つの拒否であり、拒否される場所がそれぞれ異なります。
段階 3 はクライアントによる拒否です。check_policy が決済フック内で応答し、購入側はキーで署名する前に中止するため、トランザクションもリンクも発生しません(設計 D2)。段階 5 は
台帳による拒否です。エージェントのキーはすでにフロートアカウントに登録されていませんが、ファシリテーターはそのまま送金を送信するため、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 上のファクトリー読み取り)から、ローカルデータベースに 1 件の行を登録します。これにより、実データに触れずにローカルでマージ前チェックを実行できます。エンティティの作成元である本番ファクトリーにFACTORY_ADDRESSを設定してください。novi-hedera demo-buyer <uaid>は、ユニバーサルエージェント ID から Novi Corpus の企業を特定し、その/verifyルートに支払い、返された内容の EIP-712 署名を、本文で指定されたattestorに対してオフラインで検証します。3 つのホップ(/legal-bodies/:address、メタデータリンク、有料ルート)は、それぞれ→ GET …として出力されます。NOVI_API_BASEでベースを設定します。デフォルト値はありません。 デプロイ済みのバックエンドを対象とする場合でも、ガードされています。
v2 の強化
クラッシュセーフティ、並行処理、Turnkey など、本番環境向けの既知の強化項目はチームで管理しています。テストネットのデモを妨げるものはありません。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。