@absol-labs/agent 0.11.0 → 0.12.0-rc.1
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 +42 -50
- 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.js +1 -1
- 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 +19 -0
- package/dist/cli/commands/pay.d.ts.map +1 -0
- package/dist/cli/commands/pay.js +355 -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 +184 -16
- package/dist/cli/commands/reclaim.js.map +1 -1
- package/dist/cli/commands/refund.d.ts +13 -0
- package/dist/cli/commands/refund.d.ts.map +1 -0
- package/dist/cli/commands/refund.js +224 -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 +10 -1
- 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 +2 -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/deps.d.ts +33 -0
- package/dist/cli/deps.d.ts.map +1 -1
- package/dist/cli/deps.js +37 -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/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 +40 -11
- 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 +3 -1
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +15 -3
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/wallet.d.ts +1 -1
- package/dist/cli/wallet.js +2 -2
- 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 +111 -44
- package/dist/gateway/http-server.d.ts.map +1 -1
- package/dist/gateway/http-server.js +439 -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 +215 -0
- package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
- package/dist/gateway/x402-opener-mode.js +639 -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 +52 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +228 -37
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/x402-tools.d.ts +104 -0
- package/dist/mcp/x402-tools.d.ts.map +1 -0
- package/dist/mcp/x402-tools.js +434 -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/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 +135 -0
- package/dist/x402-buyer/pay.d.ts.map +1 -0
- package/dist/x402-buyer/pay.js +336 -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 +37 -0
- package/dist/x402-opener/facilitator-entry.js.map +1 -0
- package/dist/x402-opener/facilitator-server.d.ts +180 -0
- package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
- package/dist/x402-opener/facilitator-server.js +696 -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 +240 -0
- package/dist/x402-opener/refund-relay.d.ts.map +1 -0
- package/dist/x402-opener/refund-relay.js +1240 -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 +217 -0
- package/dist/x402-opener/scheme.d.ts.map +1 -0
- package/dist/x402-opener/scheme.js +749 -0
- package/dist/x402-opener/scheme.js.map +1 -0
- package/dist/x402-opener/terms.d.ts +105 -0
- package/dist/x402-opener/terms.d.ts.map +1 -0
- package/dist/x402-opener/terms.js +212 -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 +184 -31
- package/docs/langchain.md +5 -0
- package/docs/mcp-reference.md +75 -5
- package/docs/probe-capability.md +191 -0
- package/docs/quickstart.md +36 -1
- package/docs/threat-model.md +20 -0
- package/docs/x402.md +628 -595
- 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 +1 -1
- 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 +442 -0
- package/src/cli/commands/reclaim-unverified.ts +8 -2
- package/src/cli/commands/reclaim.ts +252 -14
- package/src/cli/commands/refund.ts +277 -0
- package/src/cli/commands/status.ts +17 -1
- package/src/cli/commands/streams.ts +10 -14
- package/src/cli/commands/watch.ts +7 -1
- package/src/cli/config.ts +139 -52
- package/src/cli/deps.ts +74 -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/reclaimability.ts +154 -0
- package/src/cli/run.ts +54 -11
- package/src/cli/scan-range.ts +2 -2
- package/src/cli/status.ts +14 -1
- package/src/cli/wallet.ts +2 -2
- 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 +629 -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 +974 -0
- package/src/index.ts +82 -19
- package/src/mcp/server.ts +319 -42
- package/src/mcp/x402-tools.ts +621 -0
- package/src/network.ts +302 -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 +517 -0
- package/src/x402-opener/abi.ts +881 -0
- package/src/x402-opener/facilitator-entry.ts +45 -0
- package/src/x402-opener/facilitator-server.ts +1014 -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 +1743 -0
- package/src/x402-opener/relayer-queue.ts +18 -0
- package/src/x402-opener/scheme.ts +1133 -0
- package/src/x402-opener/terms.ts +300 -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,28 @@ 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;
|
|
335
380
|
}
|
|
336
381
|
|
|
337
382
|
export interface StreamRegistry {
|
|
338
383
|
put(record: StoredStreamRecord): Promise<void>;
|
|
339
384
|
get(streamId: `0x${string}`): Promise<StoredStreamRecord | null>;
|
|
340
385
|
list(): Promise<readonly StoredStreamRecord[]>;
|
|
386
|
+
/**
|
|
387
|
+
* Remove a record. Used ONLY to release an x402 spend reservation that
|
|
388
|
+
* provably never moved money, or one superseded by its real stream. A
|
|
389
|
+
* registry without it keeps reservations (they over-count: buyer-favouring).
|
|
390
|
+
*/
|
|
391
|
+
delete?(streamId: `0x${string}`): Promise<void>;
|
|
341
392
|
}
|
|
342
393
|
|
|
343
394
|
export class InMemoryStreamRegistry implements StreamRegistry {
|
|
@@ -354,6 +405,10 @@ export class InMemoryStreamRegistry implements StreamRegistry {
|
|
|
354
405
|
async list(): Promise<readonly StoredStreamRecord[]> {
|
|
355
406
|
return Array.from(this.records.values());
|
|
356
407
|
}
|
|
408
|
+
|
|
409
|
+
async delete(streamId: `0x${string}`): Promise<void> {
|
|
410
|
+
this.records.delete(streamId);
|
|
411
|
+
}
|
|
357
412
|
}
|
|
358
413
|
|
|
359
414
|
export class FileStreamRegistry implements StreamRegistry {
|
|
@@ -374,6 +429,11 @@ export class FileStreamRegistry implements StreamRegistry {
|
|
|
374
429
|
return Array.from((await this.readAll()).values());
|
|
375
430
|
}
|
|
376
431
|
|
|
432
|
+
async delete(streamId: `0x${string}`): Promise<void> {
|
|
433
|
+
const records = await this.readAll();
|
|
434
|
+
if (records.delete(streamId)) await this.writeAll(records);
|
|
435
|
+
}
|
|
436
|
+
|
|
377
437
|
private async readAll(): Promise<Map<`0x${string}`, StoredStreamRecord>> {
|
|
378
438
|
const contents = await fs.readFile(this.filePath, "utf8").catch((error) => {
|
|
379
439
|
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
@@ -393,6 +453,9 @@ export class FileStreamRegistry implements StreamRegistry {
|
|
|
393
453
|
maxDurationSeconds: z.number().int().positive(),
|
|
394
454
|
openedAtSeconds: z.number().int().nonnegative(),
|
|
395
455
|
mandateId: bytes32Schema,
|
|
456
|
+
refundUrl: z.string().url().optional(),
|
|
457
|
+
opener: addressSchema.optional(),
|
|
458
|
+
x402Reservation: z.boolean().optional(),
|
|
396
459
|
}),
|
|
397
460
|
)
|
|
398
461
|
.parse(JSON.parse(contents));
|
|
@@ -410,6 +473,13 @@ export class FileStreamRegistry implements StreamRegistry {
|
|
|
410
473
|
maxDurationSeconds: record.maxDurationSeconds,
|
|
411
474
|
openedAtSeconds: record.openedAtSeconds,
|
|
412
475
|
mandateId: record.mandateId as `0x${string}`,
|
|
476
|
+
...(record.refundUrl === undefined
|
|
477
|
+
? {}
|
|
478
|
+
: { refundUrl: record.refundUrl }),
|
|
479
|
+
...(record.opener === undefined
|
|
480
|
+
? {}
|
|
481
|
+
: { opener: record.opener as `0x${string}` }),
|
|
482
|
+
...(record.x402Reservation === true ? { x402Reservation: true } : {}),
|
|
413
483
|
},
|
|
414
484
|
]),
|
|
415
485
|
);
|
|
@@ -494,6 +564,12 @@ export interface VerifiedStreamMcpServerOptions {
|
|
|
494
564
|
* the registry URL/apikey come from env inside `discoverServices`.
|
|
495
565
|
*/
|
|
496
566
|
readonly discoverServices?: DiscoverServicesFn;
|
|
567
|
+
/**
|
|
568
|
+
* The buyer side of x402. When set, `x402_pay`, `refund_status` and `refund`
|
|
569
|
+
* are registered (mandate-gated like `hire_verified_service`); unset, the
|
|
570
|
+
* tool surface is exactly as before.
|
|
571
|
+
*/
|
|
572
|
+
readonly x402?: McpX402Options;
|
|
497
573
|
readonly serverInfo?: {
|
|
498
574
|
readonly name: string;
|
|
499
575
|
readonly version: string;
|
|
@@ -512,6 +588,12 @@ export interface ParsedMetrikAgentEnv {
|
|
|
512
588
|
readonly escrow: `0x${string}`;
|
|
513
589
|
/** Which escrow generation {@link escrow} is, as CONFIGURED (never probed). */
|
|
514
590
|
readonly escrowGeneration: EscrowGeneration;
|
|
591
|
+
/**
|
|
592
|
+
* True when `escrow` is NOT a registered deployment and the operator opted
|
|
593
|
+
* in (`METRIK_AGENT_ALLOW_UNREGISTERED_ESCROW=true` + an explicit
|
|
594
|
+
* `METRIK_AGENT_ESCROW_GENERATION`); the SDK then skips its code-hash pin.
|
|
595
|
+
*/
|
|
596
|
+
readonly unregisteredEscrow: boolean;
|
|
515
597
|
/** Registry the invocation origin is verified against. Undefined = the public default. */
|
|
516
598
|
readonly registryUrl?: string;
|
|
517
599
|
readonly registryApiKey?: string;
|
|
@@ -519,6 +601,12 @@ export interface ParsedMetrikAgentEnv {
|
|
|
519
601
|
readonly allowUnverifiedOperatorPairing: boolean;
|
|
520
602
|
readonly usdc: `0x${string}`;
|
|
521
603
|
readonly chain: Chain;
|
|
604
|
+
/** The registered network this server settles on (SDK network registry). */
|
|
605
|
+
readonly network: MetrikNetwork;
|
|
606
|
+
/** `METRIK_AGENT_X402`: register the x402 tools. OPT-IN: only `1`/`true`/`yes`/`on`. */
|
|
607
|
+
readonly x402Enabled: boolean;
|
|
608
|
+
/** `METRIK_AGENT_X402_ALLOWED_HOSTS`, comma-separated; empty = any public host. */
|
|
609
|
+
readonly x402AllowedHosts: readonly string[];
|
|
522
610
|
readonly stateFile?: string;
|
|
523
611
|
readonly wallet: AgentWalletInput;
|
|
524
612
|
}
|
|
@@ -755,6 +843,30 @@ export function createVerifiedStreamMcpServer(
|
|
|
755
843
|
}
|
|
756
844
|
}
|
|
757
845
|
|
|
846
|
+
// Is the rate inside the band the operator SIGNED? The escrow accepts
|
|
847
|
+
// any non-zero rate, but the seller's capability gateway answers every
|
|
848
|
+
// request on an out-of-band stream with 403
|
|
849
|
+
// `stream-rate-out-of-bounds`, so such a hire escrows the buyer's USDC
|
|
850
|
+
// into a stream that can never be served. Checked against the verified
|
|
851
|
+
// listing the pairing check just resolved — no second registry read,
|
|
852
|
+
// and no tool argument can widen the band. A descriptor that does not
|
|
853
|
+
// verify is a refusal, never "no band". Only an unverified pairing
|
|
854
|
+
// (which already needed the operator-set override above) has no listing
|
|
855
|
+
// to check, and its success result says so.
|
|
856
|
+
if (pairing.verdict === "verified") {
|
|
857
|
+
const band = await checkListedRateBand(
|
|
858
|
+
async () => [pairing.listing],
|
|
859
|
+
args.serviceRef,
|
|
860
|
+
request.ratePerSecondUsdc,
|
|
861
|
+
"ratePerSecondUsdc",
|
|
862
|
+
);
|
|
863
|
+
if (!band.ok) {
|
|
864
|
+
return errorResult(
|
|
865
|
+
`${band.message} Pick a ratePerSecondUsdc inside the band (discover_services reports it as ratePerSecondBand).`,
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
758
870
|
// Serialize per owner: the spent-so-far read, cap check, open, and
|
|
759
871
|
// registry write must be atomic, or concurrent hires could both pass
|
|
760
872
|
// the cumulative-cap check on stale spend and overshoot maxTotalUsdc.
|
|
@@ -811,7 +923,7 @@ export function createVerifiedStreamMcpServer(
|
|
|
811
923
|
: request.ratePerSecondUsdc * BigInt(request.maxDurationSeconds);
|
|
812
924
|
|
|
813
925
|
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.`,
|
|
926
|
+
`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
927
|
{
|
|
816
928
|
streamId: result.streamId,
|
|
817
929
|
txHash: result.txHash,
|
|
@@ -1014,13 +1126,24 @@ export function createVerifiedStreamMcpServer(
|
|
|
1014
1126
|
const records = await registry.list();
|
|
1015
1127
|
const entries = await Promise.all(
|
|
1016
1128
|
records.map(async (record) => {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
.
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1129
|
+
// A reservation key is not an escrow stream: report it as what it
|
|
1130
|
+
// is instead of reading a stream that does not exist.
|
|
1131
|
+
const status =
|
|
1132
|
+
record.x402Reservation === true
|
|
1133
|
+
? {
|
|
1134
|
+
streamId: record.streamId,
|
|
1135
|
+
x402Reservation:
|
|
1136
|
+
"an x402 payment was signed but its stream could not be confirmed; its amount stays counted against the spend mandate",
|
|
1137
|
+
}
|
|
1138
|
+
: await options.agentClient
|
|
1139
|
+
.getStreamStatus(record.streamId)
|
|
1140
|
+
.then((value) =>
|
|
1141
|
+
serializeStreamStatus(value, record.streamId),
|
|
1142
|
+
)
|
|
1143
|
+
.catch((error) => ({
|
|
1144
|
+
streamId: record.streamId,
|
|
1145
|
+
statusError: asErrorMessage(error),
|
|
1146
|
+
}));
|
|
1024
1147
|
return {
|
|
1025
1148
|
streamId: record.streamId,
|
|
1026
1149
|
buyer: record.buyer,
|
|
@@ -1046,6 +1169,34 @@ export function createVerifiedStreamMcpServer(
|
|
|
1046
1169
|
},
|
|
1047
1170
|
);
|
|
1048
1171
|
|
|
1172
|
+
if (options.x402 !== undefined) {
|
|
1173
|
+
registerX402Tools(mcpServer, {
|
|
1174
|
+
x402: options.x402,
|
|
1175
|
+
resolveMandate,
|
|
1176
|
+
getSpentSoFarUsdc: (owner) => resolver.getSpentSoFarUsdc(owner),
|
|
1177
|
+
getRevokedMandateIds: (owner) => resolver.getRevokedMandateIds(owner),
|
|
1178
|
+
// The SAME per-owner chain as hire_verified_service: a hire and an x402
|
|
1179
|
+
// payment from one owner can never both pass the cumulative cap on
|
|
1180
|
+
// stale spend.
|
|
1181
|
+
serialize: serializeHire,
|
|
1182
|
+
recordStream: async (record) => {
|
|
1183
|
+
await registry.put(record);
|
|
1184
|
+
},
|
|
1185
|
+
...(registry.delete === undefined
|
|
1186
|
+
? {}
|
|
1187
|
+
: {
|
|
1188
|
+
removeStream: async (streamId: `0x${string}`) => {
|
|
1189
|
+
await registry.delete?.(streamId);
|
|
1190
|
+
},
|
|
1191
|
+
}),
|
|
1192
|
+
findStream: async (streamId) => await registry.get(streamId),
|
|
1193
|
+
now,
|
|
1194
|
+
ok: successResult,
|
|
1195
|
+
fail: errorResult,
|
|
1196
|
+
unexpected: safeToolError,
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1049
1200
|
if (options.deliveryProofService !== undefined) {
|
|
1050
1201
|
const deliveryProofService = options.deliveryProofService;
|
|
1051
1202
|
mcpServer.registerTool(
|
|
@@ -1187,41 +1338,76 @@ export function parseMetrikAgentEnv(
|
|
|
1187
1338
|
// so that array was the ONLY thing an operator ever saw — a correct failure
|
|
1188
1339
|
// rendered as noise. Name the variables instead.
|
|
1189
1340
|
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
|
|
1341
|
+
`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
1342
|
);
|
|
1192
1343
|
}
|
|
1193
1344
|
const parsed = result.data;
|
|
1194
|
-
|
|
1195
|
-
if (
|
|
1196
|
-
|
|
1345
|
+
let chainId: number | undefined;
|
|
1346
|
+
if (parsed.METRIK_AGENT_CHAIN_ID !== undefined) {
|
|
1347
|
+
chainId = Number(parsed.METRIK_AGENT_CHAIN_ID);
|
|
1348
|
+
if (!Number.isInteger(chainId) || chainId <= 0) {
|
|
1349
|
+
throw new Error("METRIK_AGENT_CHAIN_ID must be a positive integer");
|
|
1350
|
+
}
|
|
1197
1351
|
}
|
|
1198
|
-
|
|
1352
|
+
// "Is this a network the registry knows and the build allows": a registered
|
|
1353
|
+
// TESTNET. This server signs with a key from the environment and moves funds.
|
|
1354
|
+
let network: MetrikNetwork;
|
|
1355
|
+
try {
|
|
1356
|
+
network = resolveAgentNetwork(
|
|
1357
|
+
parsed.METRIK_NETWORK !== undefined &&
|
|
1358
|
+
parsed.METRIK_NETWORK.trim().length > 0
|
|
1359
|
+
? parsed.METRIK_NETWORK
|
|
1360
|
+
: chainId,
|
|
1361
|
+
{ testnetOnly: true },
|
|
1362
|
+
);
|
|
1363
|
+
} catch (error) {
|
|
1199
1364
|
throw new Error(
|
|
1200
|
-
`unsupported METRIK_AGENT_CHAIN_ID ${
|
|
1365
|
+
`unsupported METRIK_NETWORK / METRIK_AGENT_CHAIN_ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
1201
1366
|
);
|
|
1202
1367
|
}
|
|
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") {
|
|
1368
|
+
if (chainId !== undefined && chainId !== network.chain.id) {
|
|
1211
1369
|
throw new Error(
|
|
1212
|
-
`
|
|
1370
|
+
`METRIK_AGENT_CHAIN_ID ${chainId} does not match METRIK_NETWORK ${network.id} (chain ${network.chain.id})`,
|
|
1213
1371
|
);
|
|
1214
1372
|
}
|
|
1215
|
-
|
|
1373
|
+
|
|
1374
|
+
// Generation: a registered deployment's comes from the registry (a
|
|
1375
|
+
// contradicting env value is refused); an unregistered escrow needs it
|
|
1376
|
+
// DECLARED. Only the checkpoint-settled generations (v2, v3) are served.
|
|
1377
|
+
const declared = parsed.METRIK_AGENT_ESCROW_GENERATION?.trim().toLowerCase();
|
|
1378
|
+
if (declared !== undefined && declared !== "v2" && declared !== "v3") {
|
|
1216
1379
|
throw new Error(
|
|
1217
|
-
`
|
|
1380
|
+
`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
1381
|
);
|
|
1219
1382
|
}
|
|
1383
|
+
const deployment = registeredDeployment(network, parsed.METRIK_AGENT_ESCROW);
|
|
1384
|
+
let generation: EscrowGeneration;
|
|
1385
|
+
if (deployment !== undefined) {
|
|
1386
|
+
generation = deployment.escrow.generation;
|
|
1387
|
+
if (declared !== undefined && declared !== generation) {
|
|
1388
|
+
throw new Error(
|
|
1389
|
+
`METRIK_AGENT_ESCROW_GENERATION "${declared}" contradicts the registry: ${parsed.METRIK_AGENT_ESCROW} is ${network.name}'s ${generation} escrow`,
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
} else {
|
|
1393
|
+
if (parsed.METRIK_AGENT_ALLOW_UNREGISTERED_ESCROW !== "true") {
|
|
1394
|
+
throw new Error(
|
|
1395
|
+
`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.`,
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
if (declared === undefined) {
|
|
1399
|
+
throw new Error(
|
|
1400
|
+
`${ALLOW_UNREGISTERED_ESCROW_ENV}=true also needs METRIK_AGENT_ESCROW_GENERATION ("v2" | "v3"): an unregistered escrow's generation cannot be read from the registry`,
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
generation = declared;
|
|
1404
|
+
}
|
|
1220
1405
|
|
|
1221
1406
|
return {
|
|
1222
1407
|
rpcUrl: parsed.METRIK_AGENT_RPC_URL,
|
|
1223
1408
|
escrow: parsed.METRIK_AGENT_ESCROW as `0x${string}`,
|
|
1224
|
-
escrowGeneration:
|
|
1409
|
+
escrowGeneration: generation,
|
|
1410
|
+
unregisteredEscrow: deployment === undefined,
|
|
1225
1411
|
// Opt-IN only: any value but the exact string "true" leaves the check on.
|
|
1226
1412
|
allowUnverifiedOperatorPairing:
|
|
1227
1413
|
parsed.METRIK_AGENT_ALLOW_UNVERIFIED_OPERATOR === "true",
|
|
@@ -1233,9 +1419,19 @@ export function parseMetrikAgentEnv(
|
|
|
1233
1419
|
: { registryApiKey: parsed.METRIK_AGENT_REGISTRY_APIKEY }),
|
|
1234
1420
|
usdc: parsed.METRIK_AGENT_USDC as `0x${string}`,
|
|
1235
1421
|
chain: {
|
|
1236
|
-
...
|
|
1237
|
-
name: parsed.METRIK_AGENT_CHAIN_NAME ??
|
|
1422
|
+
...network.chain,
|
|
1423
|
+
name: parsed.METRIK_AGENT_CHAIN_NAME ?? network.chain.name,
|
|
1238
1424
|
},
|
|
1425
|
+
network,
|
|
1426
|
+
// Opt-IN: a fund-moving tool family whose URL the MODEL picks is never
|
|
1427
|
+
// switched on by default or by an unrecognised value.
|
|
1428
|
+
x402Enabled: ["1", "true", "yes", "on"].includes(
|
|
1429
|
+
(parsed.METRIK_AGENT_X402 ?? "").trim().toLowerCase(),
|
|
1430
|
+
),
|
|
1431
|
+
x402AllowedHosts: (parsed.METRIK_AGENT_X402_ALLOWED_HOSTS ?? "")
|
|
1432
|
+
.split(",")
|
|
1433
|
+
.map((entry) => entry.trim())
|
|
1434
|
+
.filter((entry) => entry.length > 0),
|
|
1239
1435
|
...(parsed.METRIK_AGENT_MCP_STATE_FILE === undefined
|
|
1240
1436
|
? {}
|
|
1241
1437
|
: {
|
|
@@ -1281,7 +1477,15 @@ export async function createVerifiedStreamMcpServerOptionsFromEnv(
|
|
|
1281
1477
|
// SDK treats the client as V1 and routes claimable()/reclaimable() to the
|
|
1282
1478
|
// legacy ABI, which reverts against StreamEscrowV2: the checkpoint escrow
|
|
1283
1479
|
// replaced those one-argument views with proof-carrying ones.
|
|
1284
|
-
|
|
1480
|
+
escrowV2: parsed.escrow,
|
|
1481
|
+
// An unregistered escrow was opted into by the operator: the SDK skips
|
|
1482
|
+
// its code-hash pin only with both flags (see parseMetrikAgentEnv).
|
|
1483
|
+
...(parsed.unregisteredEscrow
|
|
1484
|
+
? {
|
|
1485
|
+
allowUnregisteredEscrow: true,
|
|
1486
|
+
escrowGeneration: parsed.escrowGeneration,
|
|
1487
|
+
}
|
|
1488
|
+
: {}),
|
|
1285
1489
|
usdc: parsed.usdc,
|
|
1286
1490
|
settlementTarget: {
|
|
1287
1491
|
chainId: parsed.chain.id,
|
|
@@ -1319,6 +1523,10 @@ export async function createVerifiedStreamMcpServerOptionsFromEnv(
|
|
|
1319
1523
|
streamReader: createSdkInvokeStreamReader({
|
|
1320
1524
|
escrowAddress: parsed.escrow,
|
|
1321
1525
|
rpcUrl: parsed.rpcUrl,
|
|
1526
|
+
chainId: parsed.chain.id,
|
|
1527
|
+
...(parsed.unregisteredEscrow
|
|
1528
|
+
? { unregisteredEscrowGeneration: parsed.escrowGeneration }
|
|
1529
|
+
: {}),
|
|
1322
1530
|
}),
|
|
1323
1531
|
buyer: requireCapabilitySigner(wallet.account),
|
|
1324
1532
|
domain: { chainId, verifyingContract: parsed.escrow },
|
|
@@ -1346,6 +1554,39 @@ export async function createVerifiedStreamMcpServerOptionsFromEnv(
|
|
|
1346
1554
|
: new FileStreamRegistry(parsed.stateFile),
|
|
1347
1555
|
allowUnverifiedOperatorPairing: parsed.allowUnverifiedOperatorPairing,
|
|
1348
1556
|
serviceInvoker,
|
|
1557
|
+
...(parsed.x402Enabled
|
|
1558
|
+
? {
|
|
1559
|
+
x402: {
|
|
1560
|
+
signer: requireCapabilitySigner(
|
|
1561
|
+
wallet.account,
|
|
1562
|
+
) as unknown as McpX402Options["signer"],
|
|
1563
|
+
network: parsed.network,
|
|
1564
|
+
// The SDK's on-chain quote checks (factory.predict) read through
|
|
1565
|
+
// this server's own RPC.
|
|
1566
|
+
sdkOptions: { transport: http(parsed.rpcUrl) },
|
|
1567
|
+
...(parsed.x402AllowedHosts.length === 0
|
|
1568
|
+
? {}
|
|
1569
|
+
: { allowedHosts: parsed.x402AllowedHosts }),
|
|
1570
|
+
refundClient: async (target) => {
|
|
1571
|
+
const { refundClient } = await import("@absol-labs/sdk/x402");
|
|
1572
|
+
return refundClient(target.refundUrl, {
|
|
1573
|
+
streamId: target.streamId,
|
|
1574
|
+
...(target.opener === undefined
|
|
1575
|
+
? {}
|
|
1576
|
+
: { opener: target.opener }),
|
|
1577
|
+
...(target.fetch === undefined ? {} : { fetch: target.fetch }),
|
|
1578
|
+
// Every relay "success" is checked against the receipt.
|
|
1579
|
+
verifyWith: readOnlyMetrikClient({
|
|
1580
|
+
escrowAddress: parsed.escrow,
|
|
1581
|
+
rpcUrl: parsed.rpcUrl,
|
|
1582
|
+
chainId: parsed.chain.id,
|
|
1583
|
+
}),
|
|
1584
|
+
expectedChainId: parsed.chain.id,
|
|
1585
|
+
});
|
|
1586
|
+
},
|
|
1587
|
+
} satisfies McpX402Options,
|
|
1588
|
+
}
|
|
1589
|
+
: {}),
|
|
1349
1590
|
...(deliveryProofService === null ? {} : { deliveryProofService }),
|
|
1350
1591
|
};
|
|
1351
1592
|
}
|
|
@@ -1395,6 +1636,42 @@ function serializeServiceListing(
|
|
|
1395
1636
|
...(listing.targetMetadata === undefined
|
|
1396
1637
|
? {}
|
|
1397
1638
|
: { targetMetadata: listing.targetMetadata }),
|
|
1639
|
+
...signedRateBandField(listing),
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
/**
|
|
1644
|
+
* The operator-signed rate band, in USDC atomic units per second, so an agent
|
|
1645
|
+
* can pick a `ratePerSecondUsdc` that hire_verified_service will accept. Read
|
|
1646
|
+
* from the record discovery already verified; omitted when none was signed.
|
|
1647
|
+
* hire_verified_service re-verifies it before enforcing it.
|
|
1648
|
+
*/
|
|
1649
|
+
function signedRateBandField(listing: ServiceListing): {
|
|
1650
|
+
readonly ratePerSecondBand?: Record<string, string | null>;
|
|
1651
|
+
} {
|
|
1652
|
+
const commercial = (
|
|
1653
|
+
listing.signed as
|
|
1654
|
+
| {
|
|
1655
|
+
readonly descriptor?: {
|
|
1656
|
+
readonly commercial?: {
|
|
1657
|
+
readonly minRatePerSecond?: string;
|
|
1658
|
+
readonly maxRatePerSecond?: string;
|
|
1659
|
+
};
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
| undefined
|
|
1663
|
+
)?.descriptor?.commercial;
|
|
1664
|
+
if (
|
|
1665
|
+
commercial?.minRatePerSecond === undefined &&
|
|
1666
|
+
commercial?.maxRatePerSecond === undefined
|
|
1667
|
+
) {
|
|
1668
|
+
return {};
|
|
1669
|
+
}
|
|
1670
|
+
return {
|
|
1671
|
+
ratePerSecondBand: {
|
|
1672
|
+
minRatePerSecondUsdc: commercial.minRatePerSecond ?? null,
|
|
1673
|
+
maxRatePerSecondUsdc: commercial.maxRatePerSecond ?? null,
|
|
1674
|
+
},
|
|
1398
1675
|
};
|
|
1399
1676
|
}
|
|
1400
1677
|
|
|
@@ -1481,7 +1758,7 @@ function hasForbiddenPathCharacter(value: string): boolean {
|
|
|
1481
1758
|
|
|
1482
1759
|
/** Lower-cases header names so duplicate/odd-cased keys collapse to one. */
|
|
1483
1760
|
type OperatorPairing =
|
|
1484
|
-
| { readonly verdict: "verified" }
|
|
1761
|
+
| { readonly verdict: "verified"; readonly listing: ServiceListing }
|
|
1485
1762
|
| { readonly verdict: "mismatch"; readonly listedOperator: `0x${string}` }
|
|
1486
1763
|
| { readonly verdict: "unlisted" }
|
|
1487
1764
|
| {
|
|
@@ -1531,7 +1808,7 @@ async function checkOperatorPairing(
|
|
|
1531
1808
|
if (listing.operator.toLowerCase() !== operator.toLowerCase()) {
|
|
1532
1809
|
return { verdict: "mismatch", listedOperator: listing.operator };
|
|
1533
1810
|
}
|
|
1534
|
-
return { verdict: "verified" };
|
|
1811
|
+
return { verdict: "verified", listing };
|
|
1535
1812
|
}
|
|
1536
1813
|
|
|
1537
1814
|
/**
|