@absol-labs/agent 0.11.0 → 0.12.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -51
- package/dist/capability/invocation-capability.d.ts +2 -2
- package/dist/capability/probe-capability.d.ts +225 -0
- package/dist/capability/probe-capability.d.ts.map +1 -0
- package/dist/capability/probe-capability.js +248 -0
- package/dist/capability/probe-capability.js.map +1 -0
- package/dist/cli/args.d.ts +11 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +23 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/claim.d.ts +32 -0
- package/dist/cli/commands/claim.d.ts.map +1 -1
- package/dist/cli/commands/claim.js +116 -28
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts.map +1 -1
- package/dist/cli/commands/close.js +35 -3
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/invoke.d.ts +2 -0
- package/dist/cli/commands/invoke.d.ts.map +1 -1
- package/dist/cli/commands/invoke.js +2 -2
- package/dist/cli/commands/invoke.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +15 -2
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/open.d.ts.map +1 -1
- package/dist/cli/commands/open.js +58 -4
- package/dist/cli/commands/open.js.map +1 -1
- package/dist/cli/commands/pay.d.ts +34 -0
- package/dist/cli/commands/pay.d.ts.map +1 -0
- package/dist/cli/commands/pay.js +479 -0
- package/dist/cli/commands/pay.js.map +1 -0
- package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
- package/dist/cli/commands/reclaim-unverified.js +3 -2
- package/dist/cli/commands/reclaim-unverified.js.map +1 -1
- package/dist/cli/commands/reclaim.d.ts +23 -2
- package/dist/cli/commands/reclaim.d.ts.map +1 -1
- package/dist/cli/commands/reclaim.js +204 -20
- package/dist/cli/commands/reclaim.js.map +1 -1
- package/dist/cli/commands/refund.d.ts +31 -0
- package/dist/cli/commands/refund.d.ts.map +1 -0
- package/dist/cli/commands/refund.js +397 -0
- package/dist/cli/commands/refund.js.map +1 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +21 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/streams.js +8 -12
- package/dist/cli/commands/streams.js.map +1 -1
- package/dist/cli/commands/watch.d.ts.map +1 -1
- package/dist/cli/commands/watch.js +4 -1
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/cli/config.d.ts +44 -26
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +88 -38
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/context.d.ts +19 -0
- package/dist/cli/context.d.ts.map +1 -1
- package/dist/cli/deps.d.ts +53 -0
- package/dist/cli/deps.d.ts.map +1 -1
- package/dist/cli/deps.js +51 -1
- package/dist/cli/deps.js.map +1 -1
- package/dist/cli/errors.d.ts.map +1 -1
- package/dist/cli/errors.js +21 -1
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/escape-hatch.d.ts +6 -4
- package/dist/cli/escape-hatch.d.ts.map +1 -1
- package/dist/cli/escape-hatch.js +6 -2
- package/dist/cli/escape-hatch.js.map +1 -1
- package/dist/cli/listings.d.ts +18 -0
- package/dist/cli/listings.d.ts.map +1 -1
- package/dist/cli/listings.js +22 -12
- package/dist/cli/listings.js.map +1 -1
- package/dist/cli/preflight.d.ts +20 -14
- package/dist/cli/preflight.d.ts.map +1 -1
- package/dist/cli/preflight.js +34 -20
- package/dist/cli/preflight.js.map +1 -1
- package/dist/cli/privy.d.ts.map +1 -1
- package/dist/cli/privy.js +4 -2
- package/dist/cli/privy.js.map +1 -1
- package/dist/cli/progress.d.ts +13 -1
- package/dist/cli/progress.d.ts.map +1 -1
- package/dist/cli/progress.js +7 -1
- package/dist/cli/progress.js.map +1 -1
- package/dist/cli/reclaimability.d.ts +82 -0
- package/dist/cli/reclaimability.d.ts.map +1 -0
- package/dist/cli/reclaimability.js +80 -0
- package/dist/cli/reclaimability.js.map +1 -0
- package/dist/cli/run.d.ts +2 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +62 -21
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/scan-range.d.ts +2 -2
- package/dist/cli/scan-range.js +2 -2
- package/dist/cli/status.d.ts +106 -1
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +325 -44
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/wallet.d.ts +2 -2
- package/dist/cli/wallet.d.ts.map +1 -1
- package/dist/cli/wallet.js +29 -5
- package/dist/cli/wallet.js.map +1 -1
- package/dist/discovery/rate-band.d.ts +74 -0
- package/dist/discovery/rate-band.d.ts.map +1 -0
- package/dist/discovery/rate-band.js +114 -0
- package/dist/discovery/rate-band.js.map +1 -0
- package/dist/escrow-generation.d.ts +81 -0
- package/dist/escrow-generation.d.ts.map +1 -0
- package/dist/escrow-generation.js +76 -0
- package/dist/escrow-generation.js.map +1 -0
- package/dist/frameworks/agentkit.d.ts +8 -4
- package/dist/frameworks/agentkit.d.ts.map +1 -1
- package/dist/frameworks/agentkit.js +27 -10
- package/dist/frameworks/agentkit.js.map +1 -1
- package/dist/frameworks/eliza.d.ts +3 -3
- package/dist/frameworks/eliza.d.ts.map +1 -1
- package/dist/frameworks/eliza.js +15 -6
- package/dist/frameworks/eliza.js.map +1 -1
- package/dist/frameworks/langchain.d.ts.map +1 -1
- package/dist/frameworks/langchain.js +8 -0
- package/dist/frameworks/langchain.js.map +1 -1
- package/dist/gateway/caller-auth-gateway.d.ts +83 -31
- package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
- package/dist/gateway/caller-auth-gateway.js +180 -27
- package/dist/gateway/caller-auth-gateway.js.map +1 -1
- package/dist/gateway/http-server.d.ts +128 -44
- package/dist/gateway/http-server.d.ts.map +1 -1
- package/dist/gateway/http-server.js +506 -155
- package/dist/gateway/http-server.js.map +1 -1
- package/dist/gateway/probe-auth.d.ts +112 -0
- package/dist/gateway/probe-auth.d.ts.map +1 -0
- package/dist/gateway/probe-auth.js +127 -0
- package/dist/gateway/probe-auth.js.map +1 -0
- package/dist/gateway/signed-rate-bounds.d.ts +51 -0
- package/dist/gateway/signed-rate-bounds.d.ts.map +1 -0
- package/dist/gateway/signed-rate-bounds.js +94 -0
- package/dist/gateway/signed-rate-bounds.js.map +1 -0
- package/dist/gateway/x402-opener-mode.d.ts +252 -0
- package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
- package/dist/gateway/x402-opener-mode.js +772 -0
- package/dist/gateway/x402-opener-mode.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +64 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +247 -37
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/x402-tools.d.ts +109 -0
- package/dist/mcp/x402-tools.d.ts.map +1 -0
- package/dist/mcp/x402-tools.js +554 -0
- package/dist/mcp/x402-tools.js.map +1 -0
- package/dist/network.d.ts +119 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +199 -0
- package/dist/network.js.map +1 -0
- package/dist/sdk/client.d.ts +13 -0
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/client.js +15 -0
- package/dist/sdk/client.js.map +1 -1
- package/dist/sdk/invoke.d.ts +4 -0
- package/dist/sdk/invoke.d.ts.map +1 -1
- package/dist/sdk/invoke.js +2 -5
- package/dist/sdk/invoke.js.map +1 -1
- package/dist/wallet/autonomous-wallet-broker.d.ts +3 -0
- package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet-broker.js +27 -23
- package/dist/wallet/autonomous-wallet-broker.js.map +1 -1
- package/dist/wallet/autonomous-wallet-protocol.d.ts +8 -2
- package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet-protocol.js +9 -2
- package/dist/wallet/autonomous-wallet-protocol.js.map +1 -1
- package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
- package/dist/wallet/autonomous-wallet.js +3 -2
- package/dist/wallet/autonomous-wallet.js.map +1 -1
- package/dist/wallet/broker-escrows.d.ts +222 -0
- package/dist/wallet/broker-escrows.d.ts.map +1 -0
- package/dist/wallet/broker-escrows.js +36 -0
- package/dist/wallet/broker-escrows.js.map +1 -0
- package/dist/wallet/lifecycle.d.ts +21 -5
- package/dist/wallet/lifecycle.d.ts.map +1 -1
- package/dist/wallet/lifecycle.js +32 -12
- package/dist/wallet/lifecycle.js.map +1 -1
- package/dist/wallet/privy-broker-server.d.ts.map +1 -1
- package/dist/wallet/privy-broker-server.js +31 -26
- package/dist/wallet/privy-broker-server.js.map +1 -1
- package/dist/wallet/privy-session-broker.d.ts +14 -5
- package/dist/wallet/privy-session-broker.d.ts.map +1 -1
- package/dist/wallet/privy-session-broker.js +29 -17
- package/dist/wallet/privy-session-broker.js.map +1 -1
- package/dist/wallet/privy-session-provider.d.ts +3 -1
- package/dist/wallet/privy-session-provider.d.ts.map +1 -1
- package/dist/wallet/privy-session-provider.js +5 -3
- package/dist/wallet/privy-session-provider.js.map +1 -1
- package/dist/wallet/provider.d.ts.map +1 -1
- package/dist/wallet/provider.js +15 -8
- package/dist/wallet/provider.js.map +1 -1
- package/dist/x402/facilitator.d.ts +3 -30
- package/dist/x402/facilitator.d.ts.map +1 -1
- package/dist/x402/facilitator.js +0 -27
- package/dist/x402/facilitator.js.map +1 -1
- package/dist/x402-buyer/guarded-fetch.d.ts +51 -0
- package/dist/x402-buyer/guarded-fetch.d.ts.map +1 -0
- package/dist/x402-buyer/guarded-fetch.js +147 -0
- package/dist/x402-buyer/guarded-fetch.js.map +1 -0
- package/dist/x402-buyer/index.d.ts +10 -0
- package/dist/x402-buyer/index.d.ts.map +1 -0
- package/dist/x402-buyer/index.js +10 -0
- package/dist/x402-buyer/index.js.map +1 -0
- package/dist/x402-buyer/pay.d.ts +157 -0
- package/dist/x402-buyer/pay.d.ts.map +1 -0
- package/dist/x402-buyer/pay.js +366 -0
- package/dist/x402-buyer/pay.js.map +1 -0
- package/dist/x402-opener/abi.d.ts +684 -0
- package/dist/x402-opener/abi.d.ts.map +1 -0
- package/dist/x402-opener/abi.js +880 -0
- package/dist/x402-opener/abi.js.map +1 -0
- package/dist/x402-opener/facilitator-entry.d.ts +3 -0
- package/dist/x402-opener/facilitator-entry.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-entry.js +40 -0
- package/dist/x402-opener/facilitator-entry.js.map +1 -0
- package/dist/x402-opener/facilitator-server.d.ts +209 -0
- package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-server.js +762 -0
- package/dist/x402-opener/facilitator-server.js.map +1 -0
- package/dist/x402-opener/index.d.ts +14 -0
- package/dist/x402-opener/index.d.ts.map +1 -0
- package/dist/x402-opener/index.js +14 -0
- package/dist/x402-opener/index.js.map +1 -0
- package/dist/x402-opener/listing-resolver.d.ts +55 -0
- package/dist/x402-opener/listing-resolver.d.ts.map +1 -0
- package/dist/x402-opener/listing-resolver.js +125 -0
- package/dist/x402-opener/listing-resolver.js.map +1 -0
- package/dist/x402-opener/refund-relay.d.ts +266 -0
- package/dist/x402-opener/refund-relay.d.ts.map +1 -0
- package/dist/x402-opener/refund-relay.js +1341 -0
- package/dist/x402-opener/refund-relay.js.map +1 -0
- package/dist/x402-opener/relayer-queue.d.ts +14 -0
- package/dist/x402-opener/relayer-queue.d.ts.map +1 -0
- package/dist/x402-opener/relayer-queue.js +18 -0
- package/dist/x402-opener/relayer-queue.js.map +1 -0
- package/dist/x402-opener/scheme.d.ts +296 -0
- package/dist/x402-opener/scheme.d.ts.map +1 -0
- package/dist/x402-opener/scheme.js +1035 -0
- package/dist/x402-opener/scheme.js.map +1 -0
- package/dist/x402-opener/terms.d.ts +165 -0
- package/dist/x402-opener/terms.d.ts.map +1 -0
- package/dist/x402-opener/terms.js +304 -0
- package/dist/x402-opener/terms.js.map +1 -0
- package/dist/zktls/reclaim.d.ts +2 -2
- package/dist/zktls/t2-delivery-proof.d.ts +6 -6
- package/docs/agent-layer.md +3 -2
- package/docs/autonomous-privy-wallet.md +188 -0
- package/docs/cli.md +265 -34
- package/docs/langchain.md +5 -0
- package/docs/mcp-reference.md +91 -5
- package/docs/probe-capability.md +191 -0
- package/docs/quickstart.md +39 -4
- package/docs/threat-model.md +20 -0
- package/docs/x402.md +766 -593
- package/package.json +19 -17
- package/src/capability/probe-capability.ts +355 -0
- package/src/cli/args.ts +29 -0
- package/src/cli/commands/claim.ts +168 -33
- package/src/cli/commands/close.ts +36 -3
- package/src/cli/commands/invoke.ts +5 -2
- package/src/cli/commands/mcp.ts +18 -2
- package/src/cli/commands/open.ts +75 -4
- package/src/cli/commands/pay.ts +584 -0
- package/src/cli/commands/reclaim-unverified.ts +8 -2
- package/src/cli/commands/reclaim.ts +277 -19
- package/src/cli/commands/refund.ts +475 -0
- package/src/cli/commands/status.ts +28 -2
- package/src/cli/commands/streams.ts +10 -14
- package/src/cli/commands/watch.ts +11 -1
- package/src/cli/config.ts +139 -52
- package/src/cli/context.ts +16 -0
- package/src/cli/deps.ts +111 -1
- package/src/cli/errors.ts +24 -1
- package/src/cli/escape-hatch.ts +19 -5
- package/src/cli/listings.ts +43 -10
- package/src/cli/preflight.ts +36 -21
- package/src/cli/privy.ts +4 -2
- package/src/cli/progress.ts +21 -2
- package/src/cli/reclaimability.ts +154 -0
- package/src/cli/run.ts +77 -21
- package/src/cli/scan-range.ts +2 -2
- package/src/cli/status.ts +454 -44
- package/src/cli/wallet.ts +45 -8
- package/src/discovery/rate-band.ts +172 -0
- package/src/escrow-generation.ts +135 -0
- package/src/frameworks/agentkit.ts +45 -11
- package/src/frameworks/eliza.ts +27 -5
- package/src/frameworks/langchain.ts +14 -0
- package/src/gateway/caller-auth-gateway.ts +320 -68
- package/src/gateway/http-server.ts +717 -220
- package/src/gateway/probe-auth.ts +191 -0
- package/src/gateway/signed-rate-bounds.ts +164 -0
- package/src/gateway/x402-opener-mode.ts +1171 -0
- package/src/index.ts +82 -19
- package/src/mcp/server.ts +351 -42
- package/src/mcp/x402-tools.ts +785 -0
- package/src/network.ts +302 -0
- package/src/sdk/client.ts +25 -0
- package/src/sdk/invoke.ts +6 -5
- package/src/wallet/autonomous-wallet-broker.ts +46 -20
- package/src/wallet/autonomous-wallet-protocol.ts +11 -2
- package/src/wallet/autonomous-wallet.ts +4 -2
- package/src/wallet/broker-escrows.ts +66 -0
- package/src/wallet/lifecycle.ts +53 -18
- package/src/wallet/privy-broker-server.ts +35 -25
- package/src/wallet/privy-session-broker.ts +58 -25
- package/src/wallet/privy-session-provider.ts +7 -3
- package/src/wallet/provider.ts +20 -15
- package/src/x402/facilitator.ts +3 -43
- package/src/x402-buyer/guarded-fetch.ts +213 -0
- package/src/x402-buyer/index.ts +9 -0
- package/src/x402-buyer/pay.ts +555 -0
- package/src/x402-opener/abi.ts +881 -0
- package/src/x402-opener/facilitator-entry.ts +48 -0
- package/src/x402-opener/facilitator-server.ts +1114 -0
- package/src/x402-opener/index.ts +13 -0
- package/src/x402-opener/listing-resolver.ts +202 -0
- package/src/x402-opener/refund-relay.ts +1873 -0
- package/src/x402-opener/relayer-queue.ts +18 -0
- package/src/x402-opener/scheme.ts +1551 -0
- package/src/x402-opener/terms.ts +453 -0
- package/dist/gateway/x402-mode.d.ts +0 -123
- package/dist/gateway/x402-mode.d.ts.map +0 -1
- package/dist/gateway/x402-mode.js +0 -212
- package/dist/gateway/x402-mode.js.map +0 -1
- package/dist/x402/delivery-oracle.d.ts +0 -108
- package/dist/x402/delivery-oracle.d.ts.map +0 -1
- package/dist/x402/delivery-oracle.js +0 -174
- package/dist/x402/delivery-oracle.js.map +0 -1
- package/dist/x402/facilitator-server-entry.d.ts +0 -3
- package/dist/x402/facilitator-server-entry.d.ts.map +0 -1
- package/dist/x402/facilitator-server-entry.js +0 -27
- package/dist/x402/facilitator-server-entry.js.map +0 -1
- package/dist/x402/facilitator-server.d.ts +0 -73
- package/dist/x402/facilitator-server.d.ts.map +0 -1
- package/dist/x402/facilitator-server.js +0 -305
- package/dist/x402/facilitator-server.js.map +0 -1
- package/dist/x402/payment-requirements.d.ts +0 -106
- package/dist/x402/payment-requirements.d.ts.map +0 -1
- package/dist/x402/payment-requirements.js +0 -138
- package/dist/x402/payment-requirements.js.map +0 -1
- package/dist/x402/relayer.d.ts +0 -41
- package/dist/x402/relayer.d.ts.map +0 -1
- package/dist/x402/relayer.js +0 -64
- package/dist/x402/relayer.js.map +0 -1
- package/dist/x402/resource-index.d.ts +0 -75
- package/dist/x402/resource-index.d.ts.map +0 -1
- package/dist/x402/resource-index.js +0 -126
- package/dist/x402/resource-index.js.map +0 -1
- package/dist/x402/verified-delivery-facilitator.d.ts +0 -285
- package/dist/x402/verified-delivery-facilitator.d.ts.map +0 -1
- package/dist/x402/verified-delivery-facilitator.js +0 -423
- package/dist/x402/verified-delivery-facilitator.js.map +0 -1
- package/src/gateway/x402-mode.ts +0 -350
- package/src/x402/delivery-oracle.ts +0 -285
- package/src/x402/facilitator-server-entry.ts +0 -35
- package/src/x402/facilitator-server.ts +0 -445
- package/src/x402/payment-requirements.ts +0 -231
- package/src/x402/relayer.ts +0 -122
- package/src/x402/resource-index.ts +0 -228
- package/src/x402/verified-delivery-facilitator.ts +0 -744
package/src/mcp/server.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { MetrikNetwork } from "@absol-labs/sdk";
|
|
5
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
7
|
import { privateKeyToAccount } from "viem/accounts";
|
|
8
8
|
import { http, isAddress, isHex, type Chain } from "viem";
|
|
9
|
-
import { baseSepolia } from "viem/chains";
|
|
10
9
|
import { z } from "zod";
|
|
11
10
|
|
|
12
11
|
import {
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
type DiscoverServicesOptions,
|
|
15
14
|
type ServiceListing,
|
|
16
15
|
} from "../discovery/registry.js";
|
|
16
|
+
import { checkListedRateBand } from "../discovery/rate-band.js";
|
|
17
17
|
import { checkMandate, type SignedSpendMandate } from "../mandates/mandate.js";
|
|
18
18
|
import {
|
|
19
19
|
parseServerMandateCapsEnv,
|
|
@@ -60,6 +60,19 @@ import {
|
|
|
60
60
|
type ServiceInvocationResult,
|
|
61
61
|
type ServiceInvoker,
|
|
62
62
|
} from "./service-invoker.js";
|
|
63
|
+
import {
|
|
64
|
+
defaultNetwork,
|
|
65
|
+
readOnlyMetrikClient,
|
|
66
|
+
registeredDeployment,
|
|
67
|
+
resolveAgentNetwork,
|
|
68
|
+
} from "../network.js";
|
|
69
|
+
import {
|
|
70
|
+
REFUND_STATUS_TOOL_DESCRIPTION,
|
|
71
|
+
REFUND_TOOL_DESCRIPTION,
|
|
72
|
+
X402_PAY_TOOL_DESCRIPTION,
|
|
73
|
+
registerX402Tools,
|
|
74
|
+
type McpX402Options,
|
|
75
|
+
} from "./x402-tools.js";
|
|
63
76
|
|
|
64
77
|
/**
|
|
65
78
|
* MCP server for the agent lane.
|
|
@@ -223,19 +236,26 @@ const metrikAgentEnvSchema = z.object({
|
|
|
223
236
|
METRIK_AGENT_REGISTRY_URL: z.string().url().optional(),
|
|
224
237
|
METRIK_AGENT_REGISTRY_APIKEY: z.string().optional(),
|
|
225
238
|
METRIK_AGENT_ALLOW_UNVERIFIED_OPERATOR: z.string().optional(),
|
|
239
|
+
METRIK_AGENT_ALLOW_UNREGISTERED_ESCROW: z.string().optional(),
|
|
240
|
+
METRIK_NETWORK: z.string().optional(),
|
|
241
|
+
METRIK_AGENT_X402: z.string().optional(),
|
|
242
|
+
METRIK_AGENT_X402_ALLOWED_HOSTS: z.string().optional(),
|
|
226
243
|
});
|
|
227
244
|
|
|
228
245
|
/**
|
|
229
|
-
*
|
|
246
|
+
* Opt in to an escrow that is NOT the network's registered `StreamEscrowV2`.
|
|
230
247
|
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
* `METRIK_AGENT_ESCROW`
|
|
248
|
+
* Off by default, because a wrong escrow does not fail at read time: the
|
|
249
|
+
* retired V1 escrow's `getStream` returns a tuple that diverges from V2's from
|
|
250
|
+
* index 5 onward, so a V2 decoder pointed at it does not revert — it decodes
|
|
251
|
+
* other fields into correctly-named ones and reports a confident wrong answer
|
|
252
|
+
* about someone's money. This repository's own shipped docs pointed
|
|
253
|
+
* `METRIK_AGENT_ESCROW` at V1 as recently as 0.10.0. Requiring the escrow to be
|
|
254
|
+
* the one the SDK network registry records for the chain refuses V1 (and any
|
|
255
|
+
* other stray address) without naming it in code. Operator-set input only.
|
|
237
256
|
*/
|
|
238
|
-
const
|
|
257
|
+
export const ALLOW_UNREGISTERED_ESCROW_ENV =
|
|
258
|
+
"METRIK_AGENT_ALLOW_UNREGISTERED_ESCROW";
|
|
239
259
|
|
|
240
260
|
/**
|
|
241
261
|
* Opt out of the operator/serviceRef cross-check on hire. Operator-set input
|
|
@@ -255,7 +275,7 @@ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" as const;
|
|
|
255
275
|
* generation has to be a stated fact that can be wrong out loud, rather than an
|
|
256
276
|
* assumption buried in one constructor argument.
|
|
257
277
|
*/
|
|
258
|
-
export type EscrowGeneration = "v2";
|
|
278
|
+
export type EscrowGeneration = "v2" | "v3";
|
|
259
279
|
|
|
260
280
|
export interface McpToolSpec {
|
|
261
281
|
name: string;
|
|
@@ -317,6 +337,21 @@ export const METRIK_MCP_TOOLS: readonly McpToolSpec[] = [
|
|
|
317
337
|
"Generate a buyer-side zkTLS proof of an HTTPS response from a stream's verified service origin. PUBLIC listings only: the proof is fetched by a third-party Reclaim attestor, which cannot present this stream's caller-auth capability, so a GATED listing answers the attestor with a 403 and the tool fails closed rather than proving a rejection. This is an L2 delivery signal (consumer zkTLS) and must be cross-checked with oracle/L1 evidence; it is not a substitute for it.",
|
|
318
338
|
movesFunds: false,
|
|
319
339
|
},
|
|
340
|
+
{
|
|
341
|
+
name: "x402_pay",
|
|
342
|
+
description: X402_PAY_TOOL_DESCRIPTION,
|
|
343
|
+
movesFunds: true,
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: "refund_status",
|
|
347
|
+
description: REFUND_STATUS_TOOL_DESCRIPTION,
|
|
348
|
+
movesFunds: false,
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
name: "refund",
|
|
352
|
+
description: REFUND_TOOL_DESCRIPTION,
|
|
353
|
+
movesFunds: true,
|
|
354
|
+
},
|
|
320
355
|
] as const;
|
|
321
356
|
|
|
322
357
|
/** @deprecated Renamed to METRIK_MCP_TOOLS; retained for back-compat. */
|
|
@@ -332,12 +367,40 @@ export interface StoredStreamRecord {
|
|
|
332
367
|
readonly maxDurationSeconds: number;
|
|
333
368
|
readonly openedAtSeconds: number;
|
|
334
369
|
readonly mandateId: `0x${string}`;
|
|
370
|
+
/** x402 streams only: the seller's refund relay URL for this stream. */
|
|
371
|
+
readonly refundUrl?: string;
|
|
372
|
+
/** x402 streams only: the X402StreamOpener that bought the stream. */
|
|
373
|
+
readonly opener?: `0x${string}`;
|
|
374
|
+
/**
|
|
375
|
+
* An x402 payment approved and signed whose stream is not (yet) known. It
|
|
376
|
+
* counts against the cumulative cap exactly like a stream; `streamId` is a
|
|
377
|
+
* reservation key, not an escrow stream id.
|
|
378
|
+
*/
|
|
379
|
+
readonly x402Reservation?: boolean;
|
|
380
|
+
/**
|
|
381
|
+
* NOT a stream: a settled x402 upfront-only charge (an upfront opener with
|
|
382
|
+
* `upfrontAmount == price` opens no stream). It counts against the
|
|
383
|
+
* cumulative cap like any spend and has nothing to refund; `streamId` is a
|
|
384
|
+
* charge key, not an escrow stream id.
|
|
385
|
+
*/
|
|
386
|
+
readonly x402Charge?: "upfront-only";
|
|
387
|
+
/**
|
|
388
|
+
* x402 upfront openers: the NON-REFUNDABLE part of `budgetUsdc` (paid to the
|
|
389
|
+
* seller at settlement). Informational: `budgetUsdc` always counts it.
|
|
390
|
+
*/
|
|
391
|
+
readonly nonRefundableUsdc?: bigint;
|
|
335
392
|
}
|
|
336
393
|
|
|
337
394
|
export interface StreamRegistry {
|
|
338
395
|
put(record: StoredStreamRecord): Promise<void>;
|
|
339
396
|
get(streamId: `0x${string}`): Promise<StoredStreamRecord | null>;
|
|
340
397
|
list(): Promise<readonly StoredStreamRecord[]>;
|
|
398
|
+
/**
|
|
399
|
+
* Remove a record. Used ONLY to release an x402 spend reservation that
|
|
400
|
+
* provably never moved money, or one superseded by its real stream. A
|
|
401
|
+
* registry without it keeps reservations (they over-count: buyer-favouring).
|
|
402
|
+
*/
|
|
403
|
+
delete?(streamId: `0x${string}`): Promise<void>;
|
|
341
404
|
}
|
|
342
405
|
|
|
343
406
|
export class InMemoryStreamRegistry implements StreamRegistry {
|
|
@@ -354,6 +417,10 @@ export class InMemoryStreamRegistry implements StreamRegistry {
|
|
|
354
417
|
async list(): Promise<readonly StoredStreamRecord[]> {
|
|
355
418
|
return Array.from(this.records.values());
|
|
356
419
|
}
|
|
420
|
+
|
|
421
|
+
async delete(streamId: `0x${string}`): Promise<void> {
|
|
422
|
+
this.records.delete(streamId);
|
|
423
|
+
}
|
|
357
424
|
}
|
|
358
425
|
|
|
359
426
|
export class FileStreamRegistry implements StreamRegistry {
|
|
@@ -374,6 +441,11 @@ export class FileStreamRegistry implements StreamRegistry {
|
|
|
374
441
|
return Array.from((await this.readAll()).values());
|
|
375
442
|
}
|
|
376
443
|
|
|
444
|
+
async delete(streamId: `0x${string}`): Promise<void> {
|
|
445
|
+
const records = await this.readAll();
|
|
446
|
+
if (records.delete(streamId)) await this.writeAll(records);
|
|
447
|
+
}
|
|
448
|
+
|
|
377
449
|
private async readAll(): Promise<Map<`0x${string}`, StoredStreamRecord>> {
|
|
378
450
|
const contents = await fs.readFile(this.filePath, "utf8").catch((error) => {
|
|
379
451
|
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
@@ -393,6 +465,11 @@ export class FileStreamRegistry implements StreamRegistry {
|
|
|
393
465
|
maxDurationSeconds: z.number().int().positive(),
|
|
394
466
|
openedAtSeconds: z.number().int().nonnegative(),
|
|
395
467
|
mandateId: bytes32Schema,
|
|
468
|
+
refundUrl: z.string().url().optional(),
|
|
469
|
+
opener: addressSchema.optional(),
|
|
470
|
+
x402Reservation: z.boolean().optional(),
|
|
471
|
+
x402Charge: z.literal("upfront-only").optional(),
|
|
472
|
+
nonRefundableUsdc: decimalStringSchema.optional(),
|
|
396
473
|
}),
|
|
397
474
|
)
|
|
398
475
|
.parse(JSON.parse(contents));
|
|
@@ -410,6 +487,19 @@ export class FileStreamRegistry implements StreamRegistry {
|
|
|
410
487
|
maxDurationSeconds: record.maxDurationSeconds,
|
|
411
488
|
openedAtSeconds: record.openedAtSeconds,
|
|
412
489
|
mandateId: record.mandateId as `0x${string}`,
|
|
490
|
+
...(record.refundUrl === undefined
|
|
491
|
+
? {}
|
|
492
|
+
: { refundUrl: record.refundUrl }),
|
|
493
|
+
...(record.opener === undefined
|
|
494
|
+
? {}
|
|
495
|
+
: { opener: record.opener as `0x${string}` }),
|
|
496
|
+
...(record.x402Reservation === true ? { x402Reservation: true } : {}),
|
|
497
|
+
...(record.x402Charge === undefined
|
|
498
|
+
? {}
|
|
499
|
+
: { x402Charge: record.x402Charge }),
|
|
500
|
+
...(record.nonRefundableUsdc === undefined
|
|
501
|
+
? {}
|
|
502
|
+
: { nonRefundableUsdc: BigInt(record.nonRefundableUsdc) }),
|
|
413
503
|
},
|
|
414
504
|
]),
|
|
415
505
|
);
|
|
@@ -426,6 +516,9 @@ export class FileStreamRegistry implements StreamRegistry {
|
|
|
426
516
|
...record,
|
|
427
517
|
budgetUsdc: record.budgetUsdc.toString(),
|
|
428
518
|
ratePerSecondUsdc: record.ratePerSecondUsdc.toString(),
|
|
519
|
+
...(record.nonRefundableUsdc === undefined
|
|
520
|
+
? {}
|
|
521
|
+
: { nonRefundableUsdc: record.nonRefundableUsdc.toString() }),
|
|
429
522
|
})),
|
|
430
523
|
null,
|
|
431
524
|
2,
|
|
@@ -494,6 +587,12 @@ export interface VerifiedStreamMcpServerOptions {
|
|
|
494
587
|
* the registry URL/apikey come from env inside `discoverServices`.
|
|
495
588
|
*/
|
|
496
589
|
readonly discoverServices?: DiscoverServicesFn;
|
|
590
|
+
/**
|
|
591
|
+
* The buyer side of x402. When set, `x402_pay`, `refund_status` and `refund`
|
|
592
|
+
* are registered (mandate-gated like `hire_verified_service`); unset, the
|
|
593
|
+
* tool surface is exactly as before.
|
|
594
|
+
*/
|
|
595
|
+
readonly x402?: McpX402Options;
|
|
497
596
|
readonly serverInfo?: {
|
|
498
597
|
readonly name: string;
|
|
499
598
|
readonly version: string;
|
|
@@ -512,6 +611,12 @@ export interface ParsedMetrikAgentEnv {
|
|
|
512
611
|
readonly escrow: `0x${string}`;
|
|
513
612
|
/** Which escrow generation {@link escrow} is, as CONFIGURED (never probed). */
|
|
514
613
|
readonly escrowGeneration: EscrowGeneration;
|
|
614
|
+
/**
|
|
615
|
+
* True when `escrow` is NOT a registered deployment and the operator opted
|
|
616
|
+
* in (`METRIK_AGENT_ALLOW_UNREGISTERED_ESCROW=true` + an explicit
|
|
617
|
+
* `METRIK_AGENT_ESCROW_GENERATION`); the SDK then skips its code-hash pin.
|
|
618
|
+
*/
|
|
619
|
+
readonly unregisteredEscrow: boolean;
|
|
515
620
|
/** Registry the invocation origin is verified against. Undefined = the public default. */
|
|
516
621
|
readonly registryUrl?: string;
|
|
517
622
|
readonly registryApiKey?: string;
|
|
@@ -519,6 +624,12 @@ export interface ParsedMetrikAgentEnv {
|
|
|
519
624
|
readonly allowUnverifiedOperatorPairing: boolean;
|
|
520
625
|
readonly usdc: `0x${string}`;
|
|
521
626
|
readonly chain: Chain;
|
|
627
|
+
/** The registered network this server settles on (SDK network registry). */
|
|
628
|
+
readonly network: MetrikNetwork;
|
|
629
|
+
/** `METRIK_AGENT_X402`: register the x402 tools. OPT-IN: only `1`/`true`/`yes`/`on`. */
|
|
630
|
+
readonly x402Enabled: boolean;
|
|
631
|
+
/** `METRIK_AGENT_X402_ALLOWED_HOSTS`, comma-separated; empty = any public host. */
|
|
632
|
+
readonly x402AllowedHosts: readonly string[];
|
|
522
633
|
readonly stateFile?: string;
|
|
523
634
|
readonly wallet: AgentWalletInput;
|
|
524
635
|
}
|
|
@@ -755,6 +866,30 @@ export function createVerifiedStreamMcpServer(
|
|
|
755
866
|
}
|
|
756
867
|
}
|
|
757
868
|
|
|
869
|
+
// Is the rate inside the band the operator SIGNED? The escrow accepts
|
|
870
|
+
// any non-zero rate, but the seller's capability gateway answers every
|
|
871
|
+
// request on an out-of-band stream with 403
|
|
872
|
+
// `stream-rate-out-of-bounds`, so such a hire escrows the buyer's USDC
|
|
873
|
+
// into a stream that can never be served. Checked against the verified
|
|
874
|
+
// listing the pairing check just resolved — no second registry read,
|
|
875
|
+
// and no tool argument can widen the band. A descriptor that does not
|
|
876
|
+
// verify is a refusal, never "no band". Only an unverified pairing
|
|
877
|
+
// (which already needed the operator-set override above) has no listing
|
|
878
|
+
// to check, and its success result says so.
|
|
879
|
+
if (pairing.verdict === "verified") {
|
|
880
|
+
const band = await checkListedRateBand(
|
|
881
|
+
async () => [pairing.listing],
|
|
882
|
+
args.serviceRef,
|
|
883
|
+
request.ratePerSecondUsdc,
|
|
884
|
+
"ratePerSecondUsdc",
|
|
885
|
+
);
|
|
886
|
+
if (!band.ok) {
|
|
887
|
+
return errorResult(
|
|
888
|
+
`${band.message} Pick a ratePerSecondUsdc inside the band (discover_services reports it as ratePerSecondBand).`,
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
758
893
|
// Serialize per owner: the spent-so-far read, cap check, open, and
|
|
759
894
|
// registry write must be atomic, or concurrent hires could both pass
|
|
760
895
|
// the cumulative-cap check on stale spend and overshoot maxTotalUsdc.
|
|
@@ -811,7 +946,7 @@ export function createVerifiedStreamMcpServer(
|
|
|
811
946
|
: request.ratePerSecondUsdc * BigInt(request.maxDurationSeconds);
|
|
812
947
|
|
|
813
948
|
return successResult(
|
|
814
|
-
`opened verified stream ${result.streamId} on chain ${result.handle.chainId}.${pairing.verdict === "verified" ? "" : ` WARNING: the operator/serviceRef pairing was NOT verified (${pairing.verdict}) and this server is configured to escrow anyway via ${ALLOW_UNVERIFIED_OPERATOR_ENV}. The operator is the wallet that gets paid and nothing proved it owns this service.`} The meter is running from now at ${request.ratePerSecondUsdc} USDC base units per VERIFIED second, whether or not you call the service. Call it with invoke_service; stop the meter with reclaim_unspent.`,
|
|
949
|
+
`opened verified stream ${result.streamId} on chain ${result.handle.chainId}.${pairing.verdict === "verified" ? "" : ` WARNING: the operator/serviceRef pairing was NOT verified (${pairing.verdict}) and this server is configured to escrow anyway via ${ALLOW_UNVERIFIED_OPERATOR_ENV}. The operator is the wallet that gets paid and nothing proved it owns this service, and the operator-signed rate band could not be checked either: if this rate is outside it, the service's gateway refuses every request while the deposit stays escrowed.`} The meter is running from now at ${request.ratePerSecondUsdc} USDC base units per VERIFIED second, whether or not you call the service. Call it with invoke_service; stop the meter with reclaim_unspent.`,
|
|
815
950
|
{
|
|
816
951
|
streamId: result.streamId,
|
|
817
952
|
txHash: result.txHash,
|
|
@@ -1014,13 +1149,30 @@ export function createVerifiedStreamMcpServer(
|
|
|
1014
1149
|
const records = await registry.list();
|
|
1015
1150
|
const entries = await Promise.all(
|
|
1016
1151
|
records.map(async (record) => {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
.
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1152
|
+
// A reservation key is not an escrow stream: report it as what it
|
|
1153
|
+
// is instead of reading a stream that does not exist.
|
|
1154
|
+
const status =
|
|
1155
|
+
record.x402Charge === "upfront-only"
|
|
1156
|
+
? {
|
|
1157
|
+
streamId: record.streamId,
|
|
1158
|
+
x402Charge:
|
|
1159
|
+
"a settled x402 upfront-only charge: the whole price was a non-refundable per-call charge, no stream exists and there is nothing to refund; its amount counts against the spend mandate",
|
|
1160
|
+
}
|
|
1161
|
+
: record.x402Reservation === true
|
|
1162
|
+
? {
|
|
1163
|
+
streamId: record.streamId,
|
|
1164
|
+
x402Reservation:
|
|
1165
|
+
"an x402 payment was signed but its stream could not be confirmed; its amount stays counted against the spend mandate",
|
|
1166
|
+
}
|
|
1167
|
+
: await options.agentClient
|
|
1168
|
+
.getStreamStatus(record.streamId)
|
|
1169
|
+
.then((value) =>
|
|
1170
|
+
serializeStreamStatus(value, record.streamId),
|
|
1171
|
+
)
|
|
1172
|
+
.catch((error) => ({
|
|
1173
|
+
streamId: record.streamId,
|
|
1174
|
+
statusError: asErrorMessage(error),
|
|
1175
|
+
}));
|
|
1024
1176
|
return {
|
|
1025
1177
|
streamId: record.streamId,
|
|
1026
1178
|
buyer: record.buyer,
|
|
@@ -1031,6 +1183,9 @@ export function createVerifiedStreamMcpServer(
|
|
|
1031
1183
|
maxDurationSeconds: record.maxDurationSeconds,
|
|
1032
1184
|
openedAtSeconds: record.openedAtSeconds,
|
|
1033
1185
|
mandateId: record.mandateId,
|
|
1186
|
+
...(record.nonRefundableUsdc === undefined
|
|
1187
|
+
? {}
|
|
1188
|
+
: { nonRefundableUsdc: record.nonRefundableUsdc.toString() }),
|
|
1034
1189
|
status,
|
|
1035
1190
|
};
|
|
1036
1191
|
}),
|
|
@@ -1046,6 +1201,34 @@ export function createVerifiedStreamMcpServer(
|
|
|
1046
1201
|
},
|
|
1047
1202
|
);
|
|
1048
1203
|
|
|
1204
|
+
if (options.x402 !== undefined) {
|
|
1205
|
+
registerX402Tools(mcpServer, {
|
|
1206
|
+
x402: options.x402,
|
|
1207
|
+
resolveMandate,
|
|
1208
|
+
getSpentSoFarUsdc: (owner) => resolver.getSpentSoFarUsdc(owner),
|
|
1209
|
+
getRevokedMandateIds: (owner) => resolver.getRevokedMandateIds(owner),
|
|
1210
|
+
// The SAME per-owner chain as hire_verified_service: a hire and an x402
|
|
1211
|
+
// payment from one owner can never both pass the cumulative cap on
|
|
1212
|
+
// stale spend.
|
|
1213
|
+
serialize: serializeHire,
|
|
1214
|
+
recordStream: async (record) => {
|
|
1215
|
+
await registry.put(record);
|
|
1216
|
+
},
|
|
1217
|
+
...(registry.delete === undefined
|
|
1218
|
+
? {}
|
|
1219
|
+
: {
|
|
1220
|
+
removeStream: async (streamId: `0x${string}`) => {
|
|
1221
|
+
await registry.delete?.(streamId);
|
|
1222
|
+
},
|
|
1223
|
+
}),
|
|
1224
|
+
findStream: async (streamId) => await registry.get(streamId),
|
|
1225
|
+
now,
|
|
1226
|
+
ok: successResult,
|
|
1227
|
+
fail: errorResult,
|
|
1228
|
+
unexpected: safeToolError,
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1049
1232
|
if (options.deliveryProofService !== undefined) {
|
|
1050
1233
|
const deliveryProofService = options.deliveryProofService;
|
|
1051
1234
|
mcpServer.registerTool(
|
|
@@ -1187,41 +1370,76 @@ export function parseMetrikAgentEnv(
|
|
|
1187
1370
|
// so that array was the ONLY thing an operator ever saw — a correct failure
|
|
1188
1371
|
// rendered as noise. Name the variables instead.
|
|
1189
1372
|
throw new Error(
|
|
1190
|
-
`metrik-mcp is not configured: ${describeEnvIssues(result.error)}. Set METRIK_AGENT_RPC_URL (an http(s) URL), METRIK_AGENT_ESCROW and METRIK_AGENT_USDC (EVM addresses), plus a wallet (METRIK_AGENT_PRIVATE_KEY, or the CDP
|
|
1373
|
+
`metrik-mcp is not configured: ${describeEnvIssues(result.error)}. Set METRIK_AGENT_RPC_URL (an http(s) URL), METRIK_AGENT_ESCROW and METRIK_AGENT_USDC (EVM addresses), plus a wallet (METRIK_AGENT_PRIVATE_KEY, or the CDP variables — a Privy wallet is a CLI-only source and is not resolved here). METRIK_NETWORK (or METRIK_AGENT_CHAIN_ID) defaults to the registry's default network (${defaultNetwork().name}).`,
|
|
1191
1374
|
);
|
|
1192
1375
|
}
|
|
1193
1376
|
const parsed = result.data;
|
|
1194
|
-
|
|
1195
|
-
if (
|
|
1196
|
-
|
|
1377
|
+
let chainId: number | undefined;
|
|
1378
|
+
if (parsed.METRIK_AGENT_CHAIN_ID !== undefined) {
|
|
1379
|
+
chainId = Number(parsed.METRIK_AGENT_CHAIN_ID);
|
|
1380
|
+
if (!Number.isInteger(chainId) || chainId <= 0) {
|
|
1381
|
+
throw new Error("METRIK_AGENT_CHAIN_ID must be a positive integer");
|
|
1382
|
+
}
|
|
1197
1383
|
}
|
|
1198
|
-
|
|
1384
|
+
// "Is this a network the registry knows and the build allows": a registered
|
|
1385
|
+
// TESTNET. This server signs with a key from the environment and moves funds.
|
|
1386
|
+
let network: MetrikNetwork;
|
|
1387
|
+
try {
|
|
1388
|
+
network = resolveAgentNetwork(
|
|
1389
|
+
parsed.METRIK_NETWORK !== undefined &&
|
|
1390
|
+
parsed.METRIK_NETWORK.trim().length > 0
|
|
1391
|
+
? parsed.METRIK_NETWORK
|
|
1392
|
+
: chainId,
|
|
1393
|
+
{ testnetOnly: true },
|
|
1394
|
+
);
|
|
1395
|
+
} catch (error) {
|
|
1199
1396
|
throw new Error(
|
|
1200
|
-
`unsupported METRIK_AGENT_CHAIN_ID ${
|
|
1397
|
+
`unsupported METRIK_NETWORK / METRIK_AGENT_CHAIN_ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
1201
1398
|
);
|
|
1202
1399
|
}
|
|
1203
|
-
|
|
1204
|
-
// Generation is CONFIGURED. `v2` is the only generation the checkpoint escrow
|
|
1205
|
-
// semantics this server implements apply to, so anything else is refused up
|
|
1206
|
-
// front instead of silently mis-decoded (see RETIRED_V1_ESCROW).
|
|
1207
|
-
const generation = (
|
|
1208
|
-
parsed.METRIK_AGENT_ESCROW_GENERATION ?? "v2"
|
|
1209
|
-
).toLowerCase();
|
|
1210
|
-
if (generation !== "v2") {
|
|
1400
|
+
if (chainId !== undefined && chainId !== network.chain.id) {
|
|
1211
1401
|
throw new Error(
|
|
1212
|
-
`
|
|
1402
|
+
`METRIK_AGENT_CHAIN_ID ${chainId} does not match METRIK_NETWORK ${network.id} (chain ${network.chain.id})`,
|
|
1213
1403
|
);
|
|
1214
1404
|
}
|
|
1215
|
-
|
|
1405
|
+
|
|
1406
|
+
// Generation: a registered deployment's comes from the registry (a
|
|
1407
|
+
// contradicting env value is refused); an unregistered escrow needs it
|
|
1408
|
+
// DECLARED. Only the checkpoint-settled generations (v2, v3) are served.
|
|
1409
|
+
const declared = parsed.METRIK_AGENT_ESCROW_GENERATION?.trim().toLowerCase();
|
|
1410
|
+
if (declared !== undefined && declared !== "v2" && declared !== "v3") {
|
|
1216
1411
|
throw new Error(
|
|
1217
|
-
`
|
|
1412
|
+
`unsupported METRIK_AGENT_ESCROW_GENERATION "${parsed.METRIK_AGENT_ESCROW_GENERATION}": this server reads the checkpoint-settled StreamEscrowV2/V3 only. Leave it unset for a registered escrow.`,
|
|
1218
1413
|
);
|
|
1219
1414
|
}
|
|
1415
|
+
const deployment = registeredDeployment(network, parsed.METRIK_AGENT_ESCROW);
|
|
1416
|
+
let generation: EscrowGeneration;
|
|
1417
|
+
if (deployment !== undefined) {
|
|
1418
|
+
generation = deployment.escrow.generation;
|
|
1419
|
+
if (declared !== undefined && declared !== generation) {
|
|
1420
|
+
throw new Error(
|
|
1421
|
+
`METRIK_AGENT_ESCROW_GENERATION "${declared}" contradicts the registry: ${parsed.METRIK_AGENT_ESCROW} is ${network.name}'s ${generation} escrow`,
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
} else {
|
|
1425
|
+
if (parsed.METRIK_AGENT_ALLOW_UNREGISTERED_ESCROW !== "true") {
|
|
1426
|
+
throw new Error(
|
|
1427
|
+
`METRIK_AGENT_ESCROW (${parsed.METRIK_AGENT_ESCROW}) is not a registered escrow of ${network.name} (current ${network.escrow.address}${network.legacy.length === 0 ? "" : `; legacy ${network.legacy.map((d) => d.escrow.address).join(", ")}`}). A wrong escrow does not fail at read time — the retired V1 escrow's stream tuple decodes into confident nonsense with the checkpoint decoder this server uses. Point it at a registered escrow, or set ${ALLOW_UNREGISTERED_ESCROW_ENV}=true and METRIK_AGENT_ESCROW_GENERATION for a deliberate private deployment.`,
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
if (declared === undefined) {
|
|
1431
|
+
throw new Error(
|
|
1432
|
+
`${ALLOW_UNREGISTERED_ESCROW_ENV}=true also needs METRIK_AGENT_ESCROW_GENERATION ("v2" | "v3"): an unregistered escrow's generation cannot be read from the registry`,
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
generation = declared;
|
|
1436
|
+
}
|
|
1220
1437
|
|
|
1221
1438
|
return {
|
|
1222
1439
|
rpcUrl: parsed.METRIK_AGENT_RPC_URL,
|
|
1223
1440
|
escrow: parsed.METRIK_AGENT_ESCROW as `0x${string}`,
|
|
1224
|
-
escrowGeneration:
|
|
1441
|
+
escrowGeneration: generation,
|
|
1442
|
+
unregisteredEscrow: deployment === undefined,
|
|
1225
1443
|
// Opt-IN only: any value but the exact string "true" leaves the check on.
|
|
1226
1444
|
allowUnverifiedOperatorPairing:
|
|
1227
1445
|
parsed.METRIK_AGENT_ALLOW_UNVERIFIED_OPERATOR === "true",
|
|
@@ -1233,9 +1451,19 @@ export function parseMetrikAgentEnv(
|
|
|
1233
1451
|
: { registryApiKey: parsed.METRIK_AGENT_REGISTRY_APIKEY }),
|
|
1234
1452
|
usdc: parsed.METRIK_AGENT_USDC as `0x${string}`,
|
|
1235
1453
|
chain: {
|
|
1236
|
-
...
|
|
1237
|
-
name: parsed.METRIK_AGENT_CHAIN_NAME ??
|
|
1454
|
+
...network.chain,
|
|
1455
|
+
name: parsed.METRIK_AGENT_CHAIN_NAME ?? network.chain.name,
|
|
1238
1456
|
},
|
|
1457
|
+
network,
|
|
1458
|
+
// Opt-IN: a fund-moving tool family whose URL the MODEL picks is never
|
|
1459
|
+
// switched on by default or by an unrecognised value.
|
|
1460
|
+
x402Enabled: ["1", "true", "yes", "on"].includes(
|
|
1461
|
+
(parsed.METRIK_AGENT_X402 ?? "").trim().toLowerCase(),
|
|
1462
|
+
),
|
|
1463
|
+
x402AllowedHosts: (parsed.METRIK_AGENT_X402_ALLOWED_HOSTS ?? "")
|
|
1464
|
+
.split(",")
|
|
1465
|
+
.map((entry) => entry.trim())
|
|
1466
|
+
.filter((entry) => entry.length > 0),
|
|
1239
1467
|
...(parsed.METRIK_AGENT_MCP_STATE_FILE === undefined
|
|
1240
1468
|
? {}
|
|
1241
1469
|
: {
|
|
@@ -1281,7 +1509,15 @@ export async function createVerifiedStreamMcpServerOptionsFromEnv(
|
|
|
1281
1509
|
// SDK treats the client as V1 and routes claimable()/reclaimable() to the
|
|
1282
1510
|
// legacy ABI, which reverts against StreamEscrowV2: the checkpoint escrow
|
|
1283
1511
|
// replaced those one-argument views with proof-carrying ones.
|
|
1284
|
-
|
|
1512
|
+
escrowV2: parsed.escrow,
|
|
1513
|
+
// An unregistered escrow was opted into by the operator: the SDK skips
|
|
1514
|
+
// its code-hash pin only with both flags (see parseMetrikAgentEnv).
|
|
1515
|
+
...(parsed.unregisteredEscrow
|
|
1516
|
+
? {
|
|
1517
|
+
allowUnregisteredEscrow: true,
|
|
1518
|
+
escrowGeneration: parsed.escrowGeneration,
|
|
1519
|
+
}
|
|
1520
|
+
: {}),
|
|
1285
1521
|
usdc: parsed.usdc,
|
|
1286
1522
|
settlementTarget: {
|
|
1287
1523
|
chainId: parsed.chain.id,
|
|
@@ -1319,6 +1555,10 @@ export async function createVerifiedStreamMcpServerOptionsFromEnv(
|
|
|
1319
1555
|
streamReader: createSdkInvokeStreamReader({
|
|
1320
1556
|
escrowAddress: parsed.escrow,
|
|
1321
1557
|
rpcUrl: parsed.rpcUrl,
|
|
1558
|
+
chainId: parsed.chain.id,
|
|
1559
|
+
...(parsed.unregisteredEscrow
|
|
1560
|
+
? { unregisteredEscrowGeneration: parsed.escrowGeneration }
|
|
1561
|
+
: {}),
|
|
1322
1562
|
}),
|
|
1323
1563
|
buyer: requireCapabilitySigner(wallet.account),
|
|
1324
1564
|
domain: { chainId, verifyingContract: parsed.escrow },
|
|
@@ -1346,6 +1586,39 @@ export async function createVerifiedStreamMcpServerOptionsFromEnv(
|
|
|
1346
1586
|
: new FileStreamRegistry(parsed.stateFile),
|
|
1347
1587
|
allowUnverifiedOperatorPairing: parsed.allowUnverifiedOperatorPairing,
|
|
1348
1588
|
serviceInvoker,
|
|
1589
|
+
...(parsed.x402Enabled
|
|
1590
|
+
? {
|
|
1591
|
+
x402: {
|
|
1592
|
+
signer: requireCapabilitySigner(
|
|
1593
|
+
wallet.account,
|
|
1594
|
+
) as unknown as McpX402Options["signer"],
|
|
1595
|
+
network: parsed.network,
|
|
1596
|
+
// The SDK's on-chain quote checks (factory.predict) read through
|
|
1597
|
+
// this server's own RPC.
|
|
1598
|
+
sdkOptions: { transport: http(parsed.rpcUrl) },
|
|
1599
|
+
...(parsed.x402AllowedHosts.length === 0
|
|
1600
|
+
? {}
|
|
1601
|
+
: { allowedHosts: parsed.x402AllowedHosts }),
|
|
1602
|
+
refundClient: async (target) => {
|
|
1603
|
+
const { refundClient } = await import("@absol-labs/sdk/x402");
|
|
1604
|
+
return refundClient(target.refundUrl, {
|
|
1605
|
+
streamId: target.streamId,
|
|
1606
|
+
...(target.opener === undefined
|
|
1607
|
+
? {}
|
|
1608
|
+
: { opener: target.opener }),
|
|
1609
|
+
...(target.fetch === undefined ? {} : { fetch: target.fetch }),
|
|
1610
|
+
// Every relay "success" is checked against the receipt.
|
|
1611
|
+
verifyWith: readOnlyMetrikClient({
|
|
1612
|
+
escrowAddress: parsed.escrow,
|
|
1613
|
+
rpcUrl: parsed.rpcUrl,
|
|
1614
|
+
chainId: parsed.chain.id,
|
|
1615
|
+
}),
|
|
1616
|
+
expectedChainId: parsed.chain.id,
|
|
1617
|
+
});
|
|
1618
|
+
},
|
|
1619
|
+
} satisfies McpX402Options,
|
|
1620
|
+
}
|
|
1621
|
+
: {}),
|
|
1349
1622
|
...(deliveryProofService === null ? {} : { deliveryProofService }),
|
|
1350
1623
|
};
|
|
1351
1624
|
}
|
|
@@ -1395,6 +1668,42 @@ function serializeServiceListing(
|
|
|
1395
1668
|
...(listing.targetMetadata === undefined
|
|
1396
1669
|
? {}
|
|
1397
1670
|
: { targetMetadata: listing.targetMetadata }),
|
|
1671
|
+
...signedRateBandField(listing),
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/**
|
|
1676
|
+
* The operator-signed rate band, in USDC atomic units per second, so an agent
|
|
1677
|
+
* can pick a `ratePerSecondUsdc` that hire_verified_service will accept. Read
|
|
1678
|
+
* from the record discovery already verified; omitted when none was signed.
|
|
1679
|
+
* hire_verified_service re-verifies it before enforcing it.
|
|
1680
|
+
*/
|
|
1681
|
+
function signedRateBandField(listing: ServiceListing): {
|
|
1682
|
+
readonly ratePerSecondBand?: Record<string, string | null>;
|
|
1683
|
+
} {
|
|
1684
|
+
const commercial = (
|
|
1685
|
+
listing.signed as
|
|
1686
|
+
| {
|
|
1687
|
+
readonly descriptor?: {
|
|
1688
|
+
readonly commercial?: {
|
|
1689
|
+
readonly minRatePerSecond?: string;
|
|
1690
|
+
readonly maxRatePerSecond?: string;
|
|
1691
|
+
};
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
| undefined
|
|
1695
|
+
)?.descriptor?.commercial;
|
|
1696
|
+
if (
|
|
1697
|
+
commercial?.minRatePerSecond === undefined &&
|
|
1698
|
+
commercial?.maxRatePerSecond === undefined
|
|
1699
|
+
) {
|
|
1700
|
+
return {};
|
|
1701
|
+
}
|
|
1702
|
+
return {
|
|
1703
|
+
ratePerSecondBand: {
|
|
1704
|
+
minRatePerSecondUsdc: commercial.minRatePerSecond ?? null,
|
|
1705
|
+
maxRatePerSecondUsdc: commercial.maxRatePerSecond ?? null,
|
|
1706
|
+
},
|
|
1398
1707
|
};
|
|
1399
1708
|
}
|
|
1400
1709
|
|
|
@@ -1481,7 +1790,7 @@ function hasForbiddenPathCharacter(value: string): boolean {
|
|
|
1481
1790
|
|
|
1482
1791
|
/** Lower-cases header names so duplicate/odd-cased keys collapse to one. */
|
|
1483
1792
|
type OperatorPairing =
|
|
1484
|
-
| { readonly verdict: "verified" }
|
|
1793
|
+
| { readonly verdict: "verified"; readonly listing: ServiceListing }
|
|
1485
1794
|
| { readonly verdict: "mismatch"; readonly listedOperator: `0x${string}` }
|
|
1486
1795
|
| { readonly verdict: "unlisted" }
|
|
1487
1796
|
| {
|
|
@@ -1531,7 +1840,7 @@ async function checkOperatorPairing(
|
|
|
1531
1840
|
if (listing.operator.toLowerCase() !== operator.toLowerCase()) {
|
|
1532
1841
|
return { verdict: "mismatch", listedOperator: listing.operator };
|
|
1533
1842
|
}
|
|
1534
|
-
return { verdict: "verified" };
|
|
1843
|
+
return { verdict: "verified", listing };
|
|
1535
1844
|
}
|
|
1536
1845
|
|
|
1537
1846
|
/**
|