@absol-labs/agent 0.9.1 → 0.11.0

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.
Files changed (293) hide show
  1. package/README.md +184 -26
  2. package/dist/capability/invocation-capability.d.ts +18 -6
  3. package/dist/capability/invocation-capability.d.ts.map +1 -1
  4. package/dist/capability/invocation-capability.js.map +1 -1
  5. package/dist/cli/amounts.d.ts +26 -0
  6. package/dist/cli/amounts.d.ts.map +1 -0
  7. package/dist/cli/amounts.js +71 -0
  8. package/dist/cli/amounts.js.map +1 -0
  9. package/dist/cli/args.d.ts +32 -0
  10. package/dist/cli/args.d.ts.map +1 -0
  11. package/dist/cli/args.js +119 -0
  12. package/dist/cli/args.js.map +1 -0
  13. package/dist/cli/attesters.d.ts +51 -0
  14. package/dist/cli/attesters.d.ts.map +1 -0
  15. package/dist/cli/attesters.js +58 -0
  16. package/dist/cli/attesters.js.map +1 -0
  17. package/dist/cli/bin.d.ts +3 -0
  18. package/dist/cli/bin.d.ts.map +1 -0
  19. package/dist/cli/bin.js +5 -0
  20. package/dist/cli/bin.js.map +1 -0
  21. package/dist/cli/commands/claim.d.ts +13 -0
  22. package/dist/cli/commands/claim.d.ts.map +1 -0
  23. package/dist/cli/commands/claim.js +102 -0
  24. package/dist/cli/commands/claim.js.map +1 -0
  25. package/dist/cli/commands/close.d.ts +3 -0
  26. package/dist/cli/commands/close.d.ts.map +1 -0
  27. package/dist/cli/commands/close.js +55 -0
  28. package/dist/cli/commands/close.js.map +1 -0
  29. package/dist/cli/commands/discover.d.ts +3 -0
  30. package/dist/cli/commands/discover.d.ts.map +1 -0
  31. package/dist/cli/commands/discover.js +183 -0
  32. package/dist/cli/commands/discover.js.map +1 -0
  33. package/dist/cli/commands/invoke.d.ts +3 -0
  34. package/dist/cli/commands/invoke.d.ts.map +1 -0
  35. package/dist/cli/commands/invoke.js +142 -0
  36. package/dist/cli/commands/invoke.js.map +1 -0
  37. package/dist/cli/commands/mcp.d.ts +3 -0
  38. package/dist/cli/commands/mcp.d.ts.map +1 -0
  39. package/dist/cli/commands/mcp.js +113 -0
  40. package/dist/cli/commands/mcp.js.map +1 -0
  41. package/dist/cli/commands/open.d.ts +3 -0
  42. package/dist/cli/commands/open.d.ts.map +1 -0
  43. package/dist/cli/commands/open.js +331 -0
  44. package/dist/cli/commands/open.js.map +1 -0
  45. package/dist/cli/commands/reclaim-unverified.d.ts +3 -0
  46. package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -0
  47. package/dist/cli/commands/reclaim-unverified.js +172 -0
  48. package/dist/cli/commands/reclaim-unverified.js.map +1 -0
  49. package/dist/cli/commands/reclaim.d.ts +33 -0
  50. package/dist/cli/commands/reclaim.d.ts.map +1 -0
  51. package/dist/cli/commands/reclaim.js +308 -0
  52. package/dist/cli/commands/reclaim.js.map +1 -0
  53. package/dist/cli/commands/status.d.ts +3 -0
  54. package/dist/cli/commands/status.d.ts.map +1 -0
  55. package/dist/cli/commands/status.js +43 -0
  56. package/dist/cli/commands/status.js.map +1 -0
  57. package/dist/cli/commands/streams.d.ts +3 -0
  58. package/dist/cli/commands/streams.d.ts.map +1 -0
  59. package/dist/cli/commands/streams.js +257 -0
  60. package/dist/cli/commands/streams.js.map +1 -0
  61. package/dist/cli/commands/watch.d.ts +3 -0
  62. package/dist/cli/commands/watch.d.ts.map +1 -0
  63. package/dist/cli/commands/watch.js +55 -0
  64. package/dist/cli/commands/watch.js.map +1 -0
  65. package/dist/cli/config.d.ts +61 -0
  66. package/dist/cli/config.d.ts.map +1 -0
  67. package/dist/cli/config.js +140 -0
  68. package/dist/cli/config.js.map +1 -0
  69. package/dist/cli/context.d.ts +29 -0
  70. package/dist/cli/context.d.ts.map +1 -0
  71. package/dist/cli/context.js +2 -0
  72. package/dist/cli/context.js.map +1 -0
  73. package/dist/cli/deps.d.ts +191 -0
  74. package/dist/cli/deps.d.ts.map +1 -0
  75. package/dist/cli/deps.js +277 -0
  76. package/dist/cli/deps.js.map +1 -0
  77. package/dist/cli/descriptor.d.ts +61 -0
  78. package/dist/cli/descriptor.d.ts.map +1 -0
  79. package/dist/cli/descriptor.js +78 -0
  80. package/dist/cli/descriptor.js.map +1 -0
  81. package/dist/cli/errors.d.ts +48 -0
  82. package/dist/cli/errors.d.ts.map +1 -0
  83. package/dist/cli/errors.js +129 -0
  84. package/dist/cli/errors.js.map +1 -0
  85. package/dist/cli/escape-hatch.d.ts +50 -0
  86. package/dist/cli/escape-hatch.d.ts.map +1 -0
  87. package/dist/cli/escape-hatch.js +45 -0
  88. package/dist/cli/escape-hatch.js.map +1 -0
  89. package/dist/cli/index.d.ts +8 -0
  90. package/dist/cli/index.d.ts.map +1 -0
  91. package/dist/cli/index.js +7 -0
  92. package/dist/cli/index.js.map +1 -0
  93. package/dist/cli/listings.d.ts +15 -0
  94. package/dist/cli/listings.d.ts.map +1 -0
  95. package/dist/cli/listings.js +56 -0
  96. package/dist/cli/listings.js.map +1 -0
  97. package/dist/cli/mandate.d.ts +66 -0
  98. package/dist/cli/mandate.d.ts.map +1 -0
  99. package/dist/cli/mandate.js +61 -0
  100. package/dist/cli/mandate.js.map +1 -0
  101. package/dist/cli/output.d.ts +33 -0
  102. package/dist/cli/output.d.ts.map +1 -0
  103. package/dist/cli/output.js +34 -0
  104. package/dist/cli/output.js.map +1 -0
  105. package/dist/cli/preflight.d.ts +38 -0
  106. package/dist/cli/preflight.d.ts.map +1 -0
  107. package/dist/cli/preflight.js +72 -0
  108. package/dist/cli/preflight.js.map +1 -0
  109. package/dist/cli/privy.d.ts +83 -0
  110. package/dist/cli/privy.d.ts.map +1 -0
  111. package/dist/cli/privy.js +230 -0
  112. package/dist/cli/privy.js.map +1 -0
  113. package/dist/cli/progress.d.ts +36 -0
  114. package/dist/cli/progress.d.ts.map +1 -0
  115. package/dist/cli/progress.js +40 -0
  116. package/dist/cli/progress.js.map +1 -0
  117. package/dist/cli/run.d.ts +25 -0
  118. package/dist/cli/run.d.ts.map +1 -0
  119. package/dist/cli/run.js +173 -0
  120. package/dist/cli/run.js.map +1 -0
  121. package/dist/cli/scan-range.d.ts +55 -0
  122. package/dist/cli/scan-range.d.ts.map +1 -0
  123. package/dist/cli/scan-range.js +57 -0
  124. package/dist/cli/scan-range.js.map +1 -0
  125. package/dist/cli/spend-policy.d.ts +60 -0
  126. package/dist/cli/spend-policy.d.ts.map +1 -0
  127. package/dist/cli/spend-policy.js +65 -0
  128. package/dist/cli/spend-policy.js.map +1 -0
  129. package/dist/cli/status.d.ts +90 -0
  130. package/dist/cli/status.d.ts.map +1 -0
  131. package/dist/cli/status.js +252 -0
  132. package/dist/cli/status.js.map +1 -0
  133. package/dist/cli/timeout.d.ts +30 -0
  134. package/dist/cli/timeout.d.ts.map +1 -0
  135. package/dist/cli/timeout.js +55 -0
  136. package/dist/cli/timeout.js.map +1 -0
  137. package/dist/cli/version.d.ts +12 -0
  138. package/dist/cli/version.d.ts.map +1 -0
  139. package/dist/cli/version.js +22 -0
  140. package/dist/cli/version.js.map +1 -0
  141. package/dist/cli/wallet.d.ts +164 -0
  142. package/dist/cli/wallet.d.ts.map +1 -0
  143. package/dist/cli/wallet.js +234 -0
  144. package/dist/cli/wallet.js.map +1 -0
  145. package/dist/frameworks/crewai.d.ts +10 -0
  146. package/dist/frameworks/crewai.d.ts.map +1 -1
  147. package/dist/frameworks/crewai.js +12 -2
  148. package/dist/frameworks/crewai.js.map +1 -1
  149. package/dist/gateway/caller-auth-gateway.d.ts +38 -3
  150. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
  151. package/dist/gateway/caller-auth-gateway.js +25 -1
  152. package/dist/gateway/caller-auth-gateway.js.map +1 -1
  153. package/dist/gateway/http-server.d.ts +53 -0
  154. package/dist/gateway/http-server.d.ts.map +1 -1
  155. package/dist/gateway/http-server.js +189 -4
  156. package/dist/gateway/http-server.js.map +1 -1
  157. package/dist/gateway/server-entry.d.ts +1 -0
  158. package/dist/gateway/server-entry.js +1 -0
  159. package/dist/gateway/server-entry.js.map +1 -1
  160. package/dist/gateway/x402-mode.d.ts +123 -0
  161. package/dist/gateway/x402-mode.d.ts.map +1 -0
  162. package/dist/gateway/x402-mode.js +212 -0
  163. package/dist/gateway/x402-mode.js.map +1 -0
  164. package/dist/index.d.ts +6 -4
  165. package/dist/index.d.ts.map +1 -1
  166. package/dist/index.js +8 -3
  167. package/dist/index.js.map +1 -1
  168. package/dist/mandates/env.d.ts +3 -2
  169. package/dist/mandates/env.d.ts.map +1 -1
  170. package/dist/mandates/env.js +3 -2
  171. package/dist/mandates/env.js.map +1 -1
  172. package/dist/mcp/http-server.d.ts +1 -0
  173. package/dist/mcp/http-server.js +1 -0
  174. package/dist/mcp/http-server.js.map +1 -1
  175. package/dist/mcp/server.d.ts +49 -0
  176. package/dist/mcp/server.d.ts.map +1 -1
  177. package/dist/mcp/server.js +533 -25
  178. package/dist/mcp/server.js.map +1 -1
  179. package/dist/mcp/service-invoker.d.ts +97 -0
  180. package/dist/mcp/service-invoker.d.ts.map +1 -0
  181. package/dist/mcp/service-invoker.js +167 -0
  182. package/dist/mcp/service-invoker.js.map +1 -0
  183. package/dist/mcp/stdio.d.ts +1 -0
  184. package/dist/mcp/stdio.js +1 -0
  185. package/dist/mcp/stdio.js.map +1 -1
  186. package/dist/sdk/client.d.ts +25 -1
  187. package/dist/sdk/client.d.ts.map +1 -1
  188. package/dist/sdk/client.js +20 -1
  189. package/dist/sdk/client.js.map +1 -1
  190. package/dist/sdk/invoke.d.ts +19 -4
  191. package/dist/sdk/invoke.d.ts.map +1 -1
  192. package/dist/sdk/invoke.js +69 -5
  193. package/dist/sdk/invoke.js.map +1 -1
  194. package/dist/x402/delivery-oracle.d.ts +108 -0
  195. package/dist/x402/delivery-oracle.d.ts.map +1 -0
  196. package/dist/x402/delivery-oracle.js +174 -0
  197. package/dist/x402/delivery-oracle.js.map +1 -0
  198. package/dist/x402/facilitator-server-entry.d.ts +3 -0
  199. package/dist/x402/facilitator-server-entry.d.ts.map +1 -0
  200. package/dist/x402/facilitator-server-entry.js +27 -0
  201. package/dist/x402/facilitator-server-entry.js.map +1 -0
  202. package/dist/x402/facilitator-server.d.ts +73 -0
  203. package/dist/x402/facilitator-server.d.ts.map +1 -0
  204. package/dist/x402/facilitator-server.js +305 -0
  205. package/dist/x402/facilitator-server.js.map +1 -0
  206. package/dist/x402/facilitator.d.ts +69 -17
  207. package/dist/x402/facilitator.d.ts.map +1 -1
  208. package/dist/x402/facilitator.js +76 -33
  209. package/dist/x402/facilitator.js.map +1 -1
  210. package/dist/x402/payment-requirements.d.ts +106 -0
  211. package/dist/x402/payment-requirements.d.ts.map +1 -0
  212. package/dist/x402/payment-requirements.js +138 -0
  213. package/dist/x402/payment-requirements.js.map +1 -0
  214. package/dist/x402/relayer.d.ts +41 -0
  215. package/dist/x402/relayer.d.ts.map +1 -0
  216. package/dist/x402/relayer.js +64 -0
  217. package/dist/x402/relayer.js.map +1 -0
  218. package/dist/x402/resource-index.d.ts +75 -0
  219. package/dist/x402/resource-index.d.ts.map +1 -0
  220. package/dist/x402/resource-index.js +126 -0
  221. package/dist/x402/resource-index.js.map +1 -0
  222. package/dist/x402/verified-delivery-facilitator.d.ts +285 -0
  223. package/dist/x402/verified-delivery-facilitator.d.ts.map +1 -0
  224. package/dist/x402/verified-delivery-facilitator.js +423 -0
  225. package/dist/x402/verified-delivery-facilitator.js.map +1 -0
  226. package/dist/zktls/t2-delivery-proof.d.ts +6 -6
  227. package/docs/agent-layer.md +14 -9
  228. package/docs/cli.md +705 -0
  229. package/docs/crewai.md +6 -2
  230. package/docs/eliza.md +6 -1
  231. package/docs/mcp-hosted.md +7 -5
  232. package/docs/mcp-reference.md +175 -0
  233. package/docs/quickstart.md +36 -9
  234. package/docs/threat-model.md +4 -3
  235. package/docs/x402.md +648 -0
  236. package/package.json +33 -10
  237. package/src/capability/invocation-capability.ts +17 -1
  238. package/src/cli/amounts.ts +102 -0
  239. package/src/cli/args.ts +150 -0
  240. package/src/cli/attesters.ts +86 -0
  241. package/src/cli/bin.ts +5 -0
  242. package/src/cli/commands/claim.ts +126 -0
  243. package/src/cli/commands/close.ts +69 -0
  244. package/src/cli/commands/discover.ts +228 -0
  245. package/src/cli/commands/invoke.ts +178 -0
  246. package/src/cli/commands/mcp.ts +135 -0
  247. package/src/cli/commands/open.ts +397 -0
  248. package/src/cli/commands/reclaim-unverified.ts +218 -0
  249. package/src/cli/commands/reclaim.ts +377 -0
  250. package/src/cli/commands/status.ts +56 -0
  251. package/src/cli/commands/streams.ts +344 -0
  252. package/src/cli/commands/watch.ts +70 -0
  253. package/src/cli/config.ts +208 -0
  254. package/src/cli/context.ts +30 -0
  255. package/src/cli/deps.ts +528 -0
  256. package/src/cli/descriptor.ts +133 -0
  257. package/src/cli/errors.ts +162 -0
  258. package/src/cli/escape-hatch.ts +92 -0
  259. package/src/cli/index.ts +27 -0
  260. package/src/cli/listings.ts +77 -0
  261. package/src/cli/mandate.ts +126 -0
  262. package/src/cli/output.ts +63 -0
  263. package/src/cli/preflight.ts +88 -0
  264. package/src/cli/privy.ts +396 -0
  265. package/src/cli/progress.ts +75 -0
  266. package/src/cli/run.ts +209 -0
  267. package/src/cli/scan-range.ts +76 -0
  268. package/src/cli/spend-policy.ts +139 -0
  269. package/src/cli/status.ts +381 -0
  270. package/src/cli/timeout.ts +64 -0
  271. package/src/cli/version.ts +21 -0
  272. package/src/cli/wallet.ts +372 -0
  273. package/src/frameworks/crewai.ts +13 -2
  274. package/src/gateway/caller-auth-gateway.ts +77 -6
  275. package/src/gateway/http-server.ts +280 -6
  276. package/src/gateway/server-entry.ts +1 -0
  277. package/src/gateway/x402-mode.ts +350 -0
  278. package/src/index.ts +40 -5
  279. package/src/mandates/env.ts +3 -2
  280. package/src/mcp/http-server.ts +1 -0
  281. package/src/mcp/server.ts +706 -30
  282. package/src/mcp/service-invoker.ts +285 -0
  283. package/src/mcp/stdio.ts +1 -0
  284. package/src/sdk/client.ts +33 -1
  285. package/src/sdk/invoke.ts +90 -12
  286. package/src/x402/delivery-oracle.ts +285 -0
  287. package/src/x402/facilitator-server-entry.ts +35 -0
  288. package/src/x402/facilitator-server.ts +445 -0
  289. package/src/x402/facilitator.ts +125 -46
  290. package/src/x402/payment-requirements.ts +231 -0
  291. package/src/x402/relayer.ts +122 -0
  292. package/src/x402/resource-index.ts +228 -0
  293. package/src/x402/verified-delivery-facilitator.ts +744 -0
package/docs/crewai.md CHANGED
@@ -33,9 +33,13 @@ from crewai import Agent, Crew, Task
33
33
  from crewai.mcp import MCPServerStdio
34
34
  from crewai.mcp.filters import create_static_tool_filter
35
35
 
36
+ # `metrik-mcp` is the executable this package publishes. It resolves anywhere
37
+ # `@absol-labs/agent` is installed (npm/pnpm link it into node_modules/.bin) and
38
+ # via `npx --package @absol-labs/agent metrik-mcp`. The old default was
39
+ # `pnpm mcp:stdio`, which only ever resolved inside the agent repository.
36
40
  metrik_mcp = MCPServerStdio(
37
- command="pnpm",
38
- args=["mcp:stdio"],
41
+ command="metrik-mcp",
42
+ args=[],
39
43
  env={
40
44
  "METRIK_AGENT_RPC_URL": "https://base-sepolia.example.invalid",
41
45
  "METRIK_AGENT_ESCROW": "0x0000000000000000000000000000000000000000",
package/docs/eliza.md CHANGED
@@ -50,6 +50,7 @@ runnable-shaped example lives in
50
50
 
51
51
  ```ts
52
52
  import { http } from "viem";
53
+ import { privateKeyToAccount } from "viem/accounts";
53
54
  import { baseSepolia } from "viem/chains";
54
55
  import { createMetrikElizaPlugin } from "@absol-labs/agent/eliza";
55
56
  import { createWalletBackedAgentClient } from "@absol-labs/agent";
@@ -65,7 +66,11 @@ const { agentClient } = await createWalletBackedAgentClient(
65
66
  escrow: process.env.METRIK_AGENT_ESCROW! as `0x${string}`,
66
67
  },
67
68
  },
68
- { privateKey: process.env.METRIK_AGENT_PRIVATE_KEY as `0x${string}` },
69
+ {
70
+ injectedAccount: privateKeyToAccount(
71
+ process.env.METRIK_AGENT_PRIVATE_KEY as `0x${string}`,
72
+ ),
73
+ },
69
74
  );
70
75
 
71
76
  const metrikPlugin = createMetrikElizaPlugin({ agentClient });
@@ -1,11 +1,13 @@
1
1
  # Hosted MCP over Streamable HTTP
2
2
 
3
3
  The agent lane ships two MCP transports over the **same** tool set
4
- (`hire_verified_service`, `check_stream_status`, `reclaim_unspent`, `list_streams`,
5
- and the optional `prove_https_response`):
4
+ (`discover_services`, `hire_verified_service`, `invoke_service`,
5
+ `check_stream_status`, `reclaim_unspent`, `list_streams`, and the optional
6
+ `prove_https_response` — see [`mcp-reference.md`](./mcp-reference.md)):
6
7
 
7
- - **stdio** (`src/mcp/stdio.ts`, `pnpm mcp:stdio`) — local dev, one process per
8
- caller. Unchanged.
8
+ - **stdio** (`src/mcp/stdio.ts`) — local dev, one process per caller. Started with
9
+ the published `metrik-mcp` executable (`npx --package @absol-labs/agent metrik-mcp`),
10
+ or `pnpm mcp:stdio` inside this repository.
9
11
  - **Streamable HTTP** (`src/mcp/http.ts` + `src/mcp/http-server.ts`,
10
12
  `pnpm mcp:http`) — a hosted, **multi-tenant**, per-caller-authenticated
11
13
  endpoint suitable for deployment. This document covers the HTTP transport.
@@ -78,7 +80,7 @@ network but need distinct wallets override only the wallet vars in their `env`.
78
80
 
79
81
  ```bash
80
82
  export METRIK_AGENT_RPC_URL="https://base-sepolia.example/rpc"
81
- export METRIK_AGENT_ESCROW="0x21948a5E6AE8d9A3D1050791AB6138657Fb54286"
83
+ export METRIK_AGENT_ESCROW="0x0f09f36Ccc05A7c9882F438721C08De314dFd46C" # StreamEscrowV2 — NOT the retired V1 escrow
82
84
  export METRIK_AGENT_USDC="0x036CbD53842c5426634e7929541eC2318f3dCF7e"
83
85
  # ... wallet vars (private key or CDP) ...
84
86
  export METRIK_MCP_TENANTS='[{"id":"acme","token":"REPLACE_WITH_SECRET"}]'
@@ -0,0 +1,175 @@
1
+ # MCP tool reference
2
+
3
+ The canonical description of what `@absol-labs/agent`'s MCP server offers an
4
+ agent, what each tool costs, and what it refuses to do. Both transports — stdio
5
+ (`metrik-mcp`) and hosted Streamable HTTP (`metrik-mcp-http`, see
6
+ [`mcp-hosted.md`](./mcp-hosted.md)) — serve exactly this set.
7
+
8
+ The names and descriptions here are the ones in `METRIK_MCP_TOOLS`
9
+ (`src/mcp/server.ts`); a clean-install check asserts the published `metrik-mcp`
10
+ binary really offers them (`scripts/check-packed-package.mjs`).
11
+
12
+ ## What you are buying: TIME, not calls
13
+
14
+ A stream rents an endpoint that the oracle keeps probing. **The meter runs on
15
+ availability that VERIFIED, not on the requests you send.** Cost is
16
+ `ratePerSecondUsdc x verified seconds`, capped at the escrowed budget. One
17
+ request and a thousand requests cost the same second, and the clock keeps
18
+ running while you send none.
19
+
20
+ A reviewer who opened a stream, made a single `invoke_service` call and was
21
+ billed for 302 seconds was billed exactly as designed. `reclaim_unspent` stops
22
+ the clock; nothing else does, and **nothing pushes money back on its own**.
23
+
24
+ The escrow proves _delivery_, not _correctness_. An endpoint that answers, on
25
+ time, in the right shape, is what gets paid — whether its answer is any good is
26
+ an economic question, not a cryptographic one.
27
+
28
+ ## The tools
29
+
30
+ | Tool | Moves funds | What it does |
31
+ | ----------------------- | ----------- | ------------------------------------------------------------------------------- |
32
+ | `discover_services` | no | Lists marketplace services whose operator signature verifies. |
33
+ | `hire_verified_service` | **yes** | Escrows USDC and opens a per-second stream. **Starts the meter.** |
34
+ | `invoke_service` | no | Calls the service the stream is paying for. Adds no cost. |
35
+ | `check_stream_status` | no | Reads live status, settled amount, claimable/reclaimable. |
36
+ | `reclaim_unspent` | **yes** | Closes the stream (**stops the meter**) and returns unspent USDC to the buyer. |
37
+ | `list_streams` | no | Lists the streams this server opened. |
38
+ | `prove_https_response` | no | Buyer-side zkTLS proof of a response. Registered only with Reclaim credentials. |
39
+
40
+ ### `discover_services`
41
+
42
+ `category?`, `limit?`. Returns `serviceRef`, `operator`, `publicUrl`, `access`,
43
+ `accessUrl` per listing.
44
+
45
+ The registry is an **untrusted transport**: every `serviceRef` is re-derived
46
+ from the signed record and the operator's signature recovered, so a compromised
47
+ registry can neither invent an operator to pay nor redirect an invocation. Rows
48
+ that fail verification are dropped. An unreachable registry is an **error**, not
49
+ an empty list — "zero services" and "could not reach the marketplace" must never
50
+ read the same.
51
+
52
+ ### `hire_verified_service`
53
+
54
+ `operator`, `serviceRef`, `budgetUsdc`, `ratePerSecondUsdc`, `durationSeconds?`.
55
+ All USDC amounts are **atomic 6-decimal units** (`1 USDC = "1000000"`).
56
+
57
+ Bounded by the server's own signed spend mandate (per-stream, cumulative, rate,
58
+ duration, operator allowlist, expiry), configured through
59
+ `METRIK_AGENT_MANDATE_*`. An MCP caller cannot produce an EIP-712 signature, so
60
+ the mandate is never a tool argument — the server holds it and fails closed
61
+ without one.
62
+
63
+ `operator` is the wallet that gets paid, and it arrives as a separate argument
64
+ from `serviceRef`. The pair is cross-checked against the verified registry, and
65
+ the check **fails closed**: the hire proceeds only on a positive match.
66
+
67
+ A contradicted pairing escrows a buyer's USDC to a stranger for someone else's
68
+ service, and nothing downstream catches it — the escrow does not know who owns a
69
+ `serviceRef`, and the oracle verifies the real endpoint while the money accrues
70
+ elsewhere. A registry read that fails is no evidence the pairing is sound:
71
+ settlement does not depend on that HTTP endpoint being reachable from the MCP
72
+ host, so during an outage the bug would be fully live. An unlisted `serviceRef`
73
+ is refused for the same reason — a hostile registry cannot forge a match, but it
74
+ can suppress a row, which would otherwise downgrade a contradiction into a pass.
75
+
76
+ Refusing strands nothing: no USDC has moved and the same call succeeds once the
77
+ registry answers. If you must accept that risk,
78
+ `METRIK_AGENT_ALLOW_UNVERIFIED_OPERATOR=true` downgrades "could not verify" to a
79
+ warning on the result. It is operator-set input only — never a tool argument,
80
+ because the caller being asked to relax a fund-safety check is the LLM the check
81
+ exists to constrain — and it never overrides a positive contradiction.
82
+
83
+ The result carries a `metering` block: the rate, the budget, the maximum this
84
+ stream can ever spend, and what starts and stops the clock.
85
+
86
+ ### `invoke_service`
87
+
88
+ `streamId`, `path?` (default `/`), `method?` (default `GET`), `headers?`,
89
+ `body?`, `ttlSeconds?` (default 60, max 300).
90
+
91
+ Signs a single-use EIP-712 `InvocationCapability` as the stream's buyer — scoped
92
+ to exactly this method and path — and calls the service through the operator's
93
+ caller-auth gateway.
94
+
95
+ - **The origin is not a parameter.** It is resolved from the operator-signed
96
+ listing for the stream's own `serviceRef`. An LLM-chosen base URL is precisely
97
+ the injection this refuses; there is no override.
98
+ - **The path cannot leave that origin.** The URL is resolved first and the
99
+ result is then proven to carry the signed origin and stay under the signed
100
+ base path — a prefix check on the raw path is not sufficient, because the URL
101
+ parser reads a backslash as a host separator for http(s). Backslashes and
102
+ control characters are rejected outright as well. Resolution happens **before**
103
+ the capability is signed, so a path that escapes never causes a buyer-signed
104
+ credential to exist.
105
+ - **Fails closed before any network call** if the stream is not active, has
106
+ expired, or does not belong to this server's wallet — each with an error that
107
+ names the next step.
108
+ - A gateway rejection is surfaced with its machine-readable reason
109
+ (`stream-not-funded`, `capability-expired`, `nonce-replayed`, …) and a next
110
+ step, rather than a bare `403`.
111
+ - Responses are capped at 64 KiB with `bodyTruncated` reported explicitly.
112
+ - It signs no transaction and moves no funds.
113
+
114
+ ### `check_stream_status`
115
+
116
+ `streamId`. Returns the stream, `claimable`, `reclaimable`, and a `metering`
117
+ block. A stream id that does not exist on the configured escrow is reported as
118
+ such rather than as "closed" — an unset escrow slot decodes as an all-zero
119
+ struct instead of reverting.
120
+
121
+ ### `reclaim_unspent`
122
+
123
+ `streamId`, `closeFirst?`. Closing is what stops the meter.
124
+
125
+ Authorized on the mandate owner's signature **alone** — never gated by mandate
126
+ expiry, revocation, or caps, because those must never strand a buyer's own
127
+ funds. It also works for a stream this server has no local record of (the
128
+ escrow itself enforces buyer-only recovery), so losing in-memory state cannot
129
+ stand between a buyer and their escrow.
130
+
131
+ ### `list_streams`
132
+
133
+ No arguments. Every active stream listed is still accruing cost per verified
134
+ second, whether or not it is being invoked.
135
+
136
+ ### `prove_https_response`
137
+
138
+ Registered **only** when Reclaim credentials are configured
139
+ (`RECLAIM_APP_ID` + `RECLAIM_APP_SECRET`). Generates a buyer-side zkTLS proof of an HTTPS response.
140
+
141
+ **Public listings only.** The Reclaim attestor fetches the URL itself, from its
142
+ own network position, and cannot carry this stream's single-use caller-auth
143
+ capability — so against a gated listing the only thing it could prove is its own
144
+ `403`. The tool says that instead of producing one. Use `invoke_service` for
145
+ gated services; that delivery is covered by the oracle's own verification.
146
+
147
+ The proof target is pinned to the stream's verified listing origin. A proof of
148
+ some other origin, stamped with this stream's delivery binding, would be
149
+ evidence of a delivery that did not happen here.
150
+
151
+ This is an L2 signal to be cross-checked with oracle/L1 evidence — not a
152
+ substitute for it.
153
+
154
+ ## Configuration
155
+
156
+ `metrik mcp --print-config` prints the `mcpServers` block to paste into an MCP
157
+ client, already carrying every variable the server fails closed without. Secrets
158
+ in it are placeholders by design.
159
+
160
+ | Variable | Required | Meaning |
161
+ | ---------------------------------------- | -------- | ----------------------------------------------------------------------------------------------- |
162
+ | `METRIK_AGENT_RPC_URL` | **yes** | Base Sepolia RPC. |
163
+ | `METRIK_AGENT_ESCROW` | **yes** | The **StreamEscrowV2** address. The retired V1 escrow is refused. |
164
+ | `METRIK_AGENT_USDC` | **yes** | Settlement token. |
165
+ | `METRIK_AGENT_ESCROW_GENERATION` | no | `v2` (default, and the only supported value). Declared, not probed. |
166
+ | `METRIK_AGENT_CHAIN_ID` | no | Defaults to `84532`; nothing else is accepted. |
167
+ | `METRIK_AGENT_REGISTRY_URL` | no | Registry the invocation origin is verified against. |
168
+ | `METRIK_AGENT_ALLOW_UNVERIFIED_OPERATOR` | no | `true` downgrades an unverifiable operator pairing from a refusal to a warning. Off by default. |
169
+ | `METRIK_AGENT_MCP_STATE_FILE` | no | Persists the stream registry across restarts. |
170
+ | `METRIK_AGENT_MANDATE_*` | **yes** | The four spend ceilings. No ceiling, no server. |
171
+ | wallet vars | **yes** | `METRIK_AGENT_PRIVATE_KEY`, or the CDP/Privy set. |
172
+
173
+ The escrow generation is a **declared fact, not an inference**: the server
174
+ refuses the retired V1 address by name, because a wrong-generation read does not
175
+ revert — it returns confident nonsense about someone's money.
@@ -16,9 +16,15 @@ Base Sepolia constants used throughout (chainId **84532**):
16
16
 
17
17
  | Thing | Address |
18
18
  | ------ | -------------------------------------------- |
19
- | Escrow | `0x21948a5E6AE8d9A3D1050791AB6138657Fb54286` |
19
+ | Escrow | `0x0f09f36Ccc05A7c9882F438721C08De314dFd46C` |
20
20
  | USDC | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` |
21
21
 
22
+ The escrow above is **StreamEscrowV2**, the checkpoint-settled contract the
23
+ oracle and the dApp actually settle against. The retired V1 metered escrow
24
+ (`0x21948a5E…`) is not a valid target: its stream tuple diverges from V2's at
25
+ index 5, so a V2 read of it does not revert — it decodes other fields into
26
+ correctly-named ones and reports a confident wrong answer.
27
+
22
28
  A complete, runnable version of this journey lives in
23
29
  [`scripts/e2e-cdp.ts`](../scripts/e2e-cdp.ts) (the live CI E2E, metrik-agent#32) — treat
24
30
  it as the working reference.
@@ -34,8 +40,8 @@ pnpm add @absol-labs/agent
34
40
  `@absol-labs/agent` and its `@absol-labs/*` dependencies are published to the **public
35
41
  npm registry** — no `.npmrc`, scope registry, or auth token is required to install.
36
42
 
37
- **Runtime:** Node **20.x** (the package pins `engines.node` to `>=20 <21`; 20.19+
38
- recommended). The Coinbase AgentKit action reads decorator metadata via
43
+ **Runtime:** Node **20.19+, 22 LTS or 24** (the package pins `engines.node` to
44
+ `>=20.19 <25`). The Coinbase AgentKit action reads decorator metadata via
39
45
  `reflect-metadata`, which only exists in the **built** output (`tsc` emits decorator
40
46
  metadata; `tsx`/esbuild does not) — so `import "reflect-metadata"` **before** importing
41
47
  the package, and for the AgentKit path import from the built package, not raw `.ts`.
@@ -209,7 +215,10 @@ const sdkConfig: StreamProofClientConfig = {
209
215
  chain: baseSepolia,
210
216
  transport: http("https://sepolia.base.org"),
211
217
  account,
212
- escrow: "0x21948a5E6AE8d9A3D1050791AB6138657Fb54286",
218
+ escrow: "0x0f09f36Ccc05A7c9882F438721C08De314dFd46C",
219
+ // Selects the checkpoint decoder. Without it the SDK reads through the legacy
220
+ // V1 ABI, and `claimable()`/`reclaimable()` revert against StreamEscrowV2.
221
+ escrowV2: "0x0f09f36Ccc05A7c9882F438721C08De314dFd46C",
213
222
  usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
214
223
  };
215
224
 
@@ -286,11 +295,23 @@ funds exactly.
286
295
 
287
296
  ---
288
297
 
289
- ## 8. Four ways to integrate
298
+ ## 8. Five ways to integrate
290
299
 
291
- Pick the surface that matches your stack — all four sit on the **same** mandate-gated
300
+ Pick the surface that matches your stack — all five sit on the **same** mandate-gated
292
301
  client and business logic.
293
302
 
303
+ **(a0) The `metrik` CLI** — no code at all, and the only surface that runs the whole
304
+ loop (`discover -> open -> invoke -> watch -> close -> reclaim`):
305
+
306
+ ```bash
307
+ npx --package @absol-labs/agent metrik discover --min-tier 2
308
+ npx --package @absol-labs/agent metrik open --service <serviceRef> \
309
+ --rate 0.000001 --budget 0.27 --duration 1h --dry-run
310
+ ```
311
+
312
+ Testnet-only, key read from `METRIK_AGENT_PRIVATE_KEY`, `--json` for scripting. Full
313
+ reference: [`docs/cli.md`](./cli.md).
314
+
294
315
  **(a) SDK client directly** — the path used above:
295
316
 
296
317
  ```ts
@@ -319,12 +340,18 @@ const agentKit = await createMetrikAgentKit({
319
340
  **(c) MCP** — local stdio for dev, hosted HTTP for deployment:
320
341
 
321
342
  ```bash
322
- pnpm mcp:stdio # local: one process per caller (src/mcp/stdio.ts)
343
+ metrik-mcp # local: one process per caller — the published executable
344
+ pnpm mcp:stdio # same server, from inside this repository (src/mcp/stdio.ts)
323
345
  pnpm mcp:http # hosted: multi-tenant Streamable HTTP, per-caller bearer auth
324
346
  ```
325
347
 
326
- Tools: `discover_services`, `hire_verified_service`, `check_stream_status`, `reclaim_unspent`,
327
- `list_streams` (+ `prove_https_response` when Reclaim creds are set). Env is read via
348
+ Tools: `discover_services`, `hire_verified_service`, `invoke_service`,
349
+ `check_stream_status`, `reclaim_unspent`, `list_streams` (+ `prove_https_response` when
350
+ Reclaim creds are set) — full reference in [`docs/mcp-reference.md`](./mcp-reference.md).
351
+ `invoke_service` is the "use" half: it signs a stream-scoped capability and calls the
352
+ operator-signed origin, so an agent never needs an out-of-band credential. Note the meter
353
+ runs on verified SECONDS, not on calls — invoking more often is free, and invoking never
354
+ costs the same. Env is read via
328
355
  `parseMetrikAgentEnv` (`METRIK_AGENT_RPC_URL` / `_ESCROW` / `_USDC` + wallet vars). The
329
356
  hosted endpoint requires `Authorization: Bearer <token>` before anything runs — see
330
357
  [`docs/mcp-hosted.md`](./mcp-hosted.md).
@@ -20,7 +20,8 @@ In scope:
20
20
 
21
21
  - signed spend mandates in [`src/mandates/mandate.ts`](../src/mandates/mandate.ts)
22
22
  - the mandate-gated SDK wrapper in [`src/sdk/client.ts`](../src/sdk/client.ts)
23
- - x402 verified-stream opens in [`src/x402/facilitator.ts`](../src/x402/facilitator.ts)
23
+ - Metrik `402` verified-stream opens in [`src/x402/facilitator.ts`](../src/x402/facilitator.ts)
24
+ (a Metrik-native challenge flow, not the x402 protocol — see [docs/x402.md](./x402.md))
24
25
  - MCP fund-moving tools in [`src/mcp/server.ts`](../src/mcp/server.ts)
25
26
  - zkTLS consumer delivery proofs in [`src/zktls/reclaim.ts`](../src/zktls/reclaim.ts)
26
27
  - wallet custody in [`src/wallet/provider.ts`](../src/wallet/provider.ts)
@@ -38,7 +39,7 @@ Out of scope:
38
39
  | Runaway spend | A prompt or tool call opens streams beyond the owner's intent. | Every autonomous fund-moving path calls `checkMandate()` before the SDK can write: `openVerifiedStream()`, `claimStream()`, `closeStream()`, `reclaimStream()`, MCP `hire_verified_service`, and MCP `reclaim_unspent`. Mandates cap per-stream, cumulative spend, rate, duration, and operator. Denial is a hard stop. | [`test/mandate.test.ts`](../test/mandate.test.ts), [`test/sdk-client.test.ts`](../test/sdk-client.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts), [`test/x402.int.test.ts`](../test/x402.int.test.ts) | `spentSoFarUsdc` and revocation data are resolver inputs. If an integrator provides stale values, the agent still fails closed on signature/expiry/operator checks, but cumulative-cap freshness depends on the integrator's state source. |
39
40
  | Mandate bypass | A caller skips the mandate layer and reaches the SDK write path directly from the agent layer. | The agent wrapper no longer exposes ungated autonomous write helpers. Existing-stream actions re-read the stream and authorize against the actual operator before `claim`, `close`, or `reclaim`. MCP also prechecks before dispatch. | [`src/sdk/client.ts`](../src/sdk/client.ts), [`test/sdk-client.test.ts`](../test/sdk-client.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts) | A caller can still use `@absol-labs/sdk` directly outside this repo. That is expected; this document only claims the agent layer itself is mandate-gated. |
40
41
  | Key exposure | The agent leaks a private key through logs, env parsing, tool args, or local persistence. | No MCP tool accepts a raw key. Wallet selection is explicit: injected viem account, CDP Server Wallet v2, or an authenticated Privy embedded EOA provider. CDP/Privy paths remote-sign and never export private keys into Metrik code. `.env.example` contains names only. | [`src/wallet/provider.ts`](../src/wallet/provider.ts), [`test/wallet.test.ts`](../test/wallet.test.ts), [`test/privy-wallet.test.ts`](../test/privy-wallet.test.ts), [`README.md`](../README.md) | Injected-key mode is still as safe as the caller's own host. Privy authentication/session revocation remains the host/provider's responsibility. |
41
- | Prompt-injection-driven spend | A hostile response or tool output tries to coerce the agent into paying a different operator or budget. | Structured inputs are validated, x402 settlement targets must match the configured chain/escrow, and any spend still must satisfy the owner's signed mandate. | [`src/x402/facilitator.ts`](../src/x402/facilitator.ts), [`test/x402.test.ts`](../test/x402.test.ts), [`test/sdk-client.test.ts`](../test/sdk-client.test.ts) | Prompt injection can still trigger tool invocation attempts. The safety claim is not "the prompt cannot be attacked"; it is "the attack cannot exceed the mandate or redirect settlement silently." |
42
+ | Prompt-injection-driven spend | A hostile response or tool output tries to coerce the agent into paying a different operator or budget. | Structured inputs are validated, challenge settlement targets must match the configured chain/escrow, and any spend still must satisfy the owner's signed mandate. | [`src/x402/facilitator.ts`](../src/x402/facilitator.ts), [`test/x402.test.ts`](../test/x402.test.ts), [`test/sdk-client.test.ts`](../test/sdk-client.test.ts) | Prompt injection can still trigger tool invocation attempts. The safety claim is not "the prompt cannot be attacked"; it is "the attack cannot exceed the mandate or redirect settlement silently." |
42
43
  | Mandate replay | A previously valid signed mandate is replayed after revocation or outside the intended lifetime. | Mandates are EIP-712 signed over `mandateId`, `owner`, `chainId`, `issuedAt`, expiry, and policy hashes. `checkMandate()` verifies signature, revocation, expiry, then policy. Integrators can revoke by `mandateId` and track cumulative spend. | [`src/mandates/mandate.ts`](../src/mandates/mandate.ts), [`test/mandate.test.ts`](../test/mandate.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts) | Replay protection is only as strong as revocation and cumulative-spend state freshness. The signed payload itself is bound to one chain and one owner, but revocation is local state today. |
43
44
  | False or weak delivery evidence | A consumer submits a proof that is validly signed by the zkTLS system but not bound to the intended request or stream context. | The Reclaim adapter re-verifies every proof locally against the exact URL/method/body/match/redaction spec supplied by the caller, and binds the proof context to buyer/stream metadata before returning it. MCP only exposes the public-request subset so secrets do not leak through tool arguments. | [`src/zktls/reclaim.ts`](../src/zktls/reclaim.ts), [`src/x402/facilitator.ts`](../src/x402/facilitator.ts), [`src/mcp/server.ts`](../src/mcp/server.ts), [`test/reclaim.test.ts`](../test/reclaim.test.ts), [`test/x402.test.ts`](../test/x402.test.ts), [`test/mcp.test.ts`](../test/mcp.test.ts) | L2 is still consumer-supplied evidence. A malicious consumer can withhold proofs, and settlement must still treat L1/oracle evidence as authoritative on failure, ambiguity, and expiry. |
44
45
 
@@ -52,7 +53,7 @@ These are the autonomous fund-moving paths in the current agent layer:
52
53
  4. `VerifiedStreamAgentClient.reclaimStream()`
53
54
  5. MCP `hire_verified_service`
54
55
  6. MCP `reclaim_unspent`
55
- 7. x402 `open()` via `VerifiedStreamX402Facilitator`
56
+ 7. Metrik `402` `open()` via `VerifiedStreamFacilitator`
56
57
 
57
58
  All of them now pass a signed mandate check before the SDK can send a write.
58
59