@metalntwx/metal-agent 0.2.0 → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: metal-agent
3
- description: "Set up and use the metal-agent CLI to pay x402 sellers on Metal: install it, create or import the agent's account, fund it, pay a URL that answers 402, pay under a mandate from an account the agent does not own, and look up a settlement. Use when a task needs an agent to pay for an HTTP resource in *USDZ on Metal, to pay with a mandate credential the user gives it, to set up metal-agent, or to check what a Metal payment settled."
3
+ description: "Set up and use the metal-agent CLI to pay x402 sellers on Metal: install it, create or import the agent's key, fund it, pay a URL that answers 402, pay under a mandate from an account the agent does not own, and look up a settlement. Use when a task needs an agent to pay for an HTTP resource in *USDZ on Metal, to pay with a mandate credential the user gives it, to set up metal-agent, or to check what a Metal payment settled."
4
4
  ---
5
5
 
6
6
  `metal-agent` is the CLI and MCP server of the `@metalntwx/metal-agent` npm
@@ -20,8 +20,8 @@ set, and pass it with `--rpc-url`. A user without one creates it as
20
20
  The key file defaults to `~/.metal-agent/key.json`. It holds the private key
21
21
  in the clear, owner-readable only; treat the file as the secret.
22
22
 
23
- If `metal-agent --help` runs and the user already has a key, go to the
24
- command you need. Otherwise start with Setup.
23
+ If `metal-agent --version` prints `0.3.1` and the user already has a key,
24
+ go to the command you need. Otherwise start with Setup.
25
25
 
26
26
  ## Setup
27
27
 
@@ -30,13 +30,15 @@ Run the steps in order. After each step, show the user its output.
30
30
  1. Check Node.js with `node --version`. If it is missing, tell the user to
31
31
  install Node.js, and stop.
32
32
 
33
- 2. Check for the CLI with `metal-agent --help`. If it is not found, install
34
- it:
33
+ 2. Install the CLI, or move an installed one to this version:
35
34
 
36
35
  ```bash
37
- npm install -g @metalntwx/metal-agent
36
+ npm install -g @metalntwx/metal-agent@0.3.1
38
37
  ```
39
38
 
39
+ Then `metal-agent --version` prints `0.3.1`. If it prints anything else,
40
+ another copy comes first on the `PATH`: tell the user, and stop.
41
+
40
42
  3. Install this skill, so that later sessions have it without fetching this
41
43
  page. Copy the directory
42
44
  `$(npm root -g)/@metalntwx/metal-agent/skills/metal-agent` into your
@@ -48,7 +50,7 @@ Run the steps in order. After each step, show the user its output.
48
50
  In Claude Code:
49
51
 
50
52
  ```bash
51
- claude mcp add metal-agent -- npx -y @metalntwx/metal-agent mcp
53
+ claude mcp add metal-agent -- npx -y @metalntwx/metal-agent@0.3.1 mcp
52
54
  ```
53
55
 
54
56
  In any other MCP host, add this server to its MCP configuration:
@@ -58,7 +60,7 @@ Run the steps in order. After each step, show the user its output.
58
60
  "mcpServers": {
59
61
  "metal-agent": {
60
62
  "command": "npx",
61
- "args": ["-y", "@metalntwx/metal-agent", "mcp"]
63
+ "args": ["-y", "@metalntwx/metal-agent@0.3.1", "mcp"]
62
64
  }
63
65
  }
64
66
  }
@@ -66,16 +68,22 @@ Run the steps in order. After each step, show the user its output.
66
68
 
67
69
  The server pays with the default key file. If the user's key is in
68
70
  another file, or the agent pays under a mandate, add `--key <file>` or
69
- `--mandate <credential>` after `mcp`.
71
+ `--mandate <credential>` after `mcp`. Under a mandate on testnet, also set
72
+ the user's endpoint in the server's environment, or in an `env` block in
73
+ another host's configuration:
74
+
75
+ ```bash
76
+ claude mcp add metal-agent -e METAL_RPC_URL=<endpoint> -- npx -y @metalntwx/metal-agent@0.3.1 mcp --mandate <credential>
77
+ ```
70
78
 
71
79
  The tools appear after the host reloads. If you cannot reload it, tell
72
80
  the user to, and carry on with the CLI.
73
81
 
74
- 5. Get the agent's account. Ask the user whether they have a funded key file. If they do,
82
+ 5. Get the agent's key. Ask the user whether they have a funded key file. If they do,
75
83
  ask for its path and run `metal-agent key import <path>`. Otherwise run
76
- `metal-agent key create`. Tell the user the address. If `key create`
77
- answers that the key file already holds a key, keep that key and ask the
78
- user for its address.
84
+ `metal-agent key create`. Tell the user the address. If either answers
85
+ that the key file already holds a key, tell the user the address in its
86
+ `address` field, and ask whether to pay with that key.
79
87
 
80
88
  6. Fund the key from the testnet faucet, unless the user said it is funded,
81
89
  and show the user the `transaction` and `explorer` lines:
@@ -112,12 +120,12 @@ the user; the limits bind you only while it is not.
112
120
 
113
121
  ## key create
114
122
 
115
- Generate the agent's account and write its key file. Prints the address
123
+ Generate the agent's key and write its key file. Prints the address
116
124
  and the key file's path. It does not overwrite an existing key file; `--out` writes
117
125
  another.
118
126
 
119
127
  ```bash
120
- metal-agent key create --out ./agent-key.json
128
+ metal-agent key create --out ./key.json
121
129
  ```
122
130
 
123
131
  ## key import
@@ -135,11 +143,13 @@ Ask the public faucet for `*USDZ`; the faucet sets the amount.
135
143
  An address that already holds a full grant is reported as funded. A grant
136
144
  prints `transaction <hash>` and `explorer <url>`, the transaction's page on
137
145
  the block explorer. The faucet limits how often one client can ask: on a
138
- `client_rate_limited` error, wait the seconds it names; on a daily-limit
139
- error, load a pre-funded key with `key import`.
146
+ `client_rate_limited` error, wait the seconds it names; on
147
+ `client_daily_limit_reached`, fund the address from the Faucet page in the
148
+ Metal console the error names; on either daily-limit error, load a
149
+ pre-funded key with `key import`.
140
150
 
141
151
  ```bash
142
- metal-agent fund 0x40daBEc53aA45faC6d0eaCCA5713fac49d8d213c --network testnet
152
+ metal-agent fund <address> --network testnet
143
153
  ```
144
154
 
145
155
  ## pay
@@ -149,7 +159,7 @@ named network, sign the authorization with the key file, retry, and print
149
159
  the settlement, the response headers and the body.
150
160
 
151
161
  ```bash
152
- metal-agent pay https://x402-demo-testnet.metalntwx.com/quote --network testnet --key ./agent-key.json
162
+ metal-agent pay https://x402-demo-testnet.metalntwx.com/quote --network testnet --key ./key.json
153
163
  ```
154
164
 
155
165
  Read `transaction <hash>` from the output for the settlement,
@@ -168,10 +178,11 @@ metal-agent pay https://example.com/report --network testnet --max 5
168
178
  For a request other than GET, pass `--method` (POST when there is a body),
169
179
  `--body` (sent as `application/json` unless a `--header` names a content
170
180
  type) and repeated `--header 'name: value'`; `pay` sends them again with the
171
- payment. To buy RPC over x402, POST the JSON-RPC call to the RPC URL:
181
+ payment. To buy RPC over x402, POST the JSON-RPC call to
182
+ `https://rpc-testnet.metalntwx.com/v1`:
172
183
 
173
184
  ```bash
174
- metal-agent pay <rpc url> --network testnet --method POST --body '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
185
+ metal-agent pay https://rpc-testnet.metalntwx.com/v1 --network testnet --method POST --body '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
175
186
  ```
176
187
 
177
188
  The output's `header rpc-aas-endpoint: <url>` is the endpoint that payment
@@ -187,15 +198,16 @@ A refusal exits 1 with the reason:
187
198
  `offer signs for the EIP-712 domain …` means the offer asks for something
188
199
  other than `*USDZ`. Tell the user; a larger `--max` does not change it.
189
200
  - `error: payment refused: <reason>` means the facilitator refused at
190
- verification, or the seller's own check refused.
201
+ verification, or the seller's own check refused; nothing was paid.
191
202
  - `error: payment refused at settlement: <reason>` means the facilitator
192
- refused at settlement, with the transaction hash when there is one. On
203
+ refused at settlement for a reason that moves nothing, with the
204
+ transaction hash when there is one; nothing was paid. On
193
205
  `daily_limit_reached`, retry later.
194
- - On `settlement_in_doubt`, or any error after the `nonce` line that is
195
- not a `payment refused` line, such as `fetch failed` or an HTTP status
196
- from the seller, the payment may have settled. Do not pay again. Tell
197
- the user, with the `nonce` line `pay` printed; when the error names a
198
- transaction hash, `status` on it shows whether it landed.
206
+ - On `error: payment in doubt at settlement: …`, or any error after the
207
+ `nonce` line that is not a `payment refused` line, such as `fetch failed`
208
+ or an HTTP status from the seller, the payment may have settled. Do not
209
+ pay again. Tell the user, with the `nonce` line `pay` printed; when the
210
+ error names a transaction hash, `status` on it shows whether it landed.
199
211
 
200
212
  ## `pay --mandate`
201
213
 
@@ -208,19 +220,21 @@ when the mandate names them, the payees.
208
220
  metal-agent pay https://example.com/report --mandate ./mandate.json --network testnet
209
221
  ```
210
222
 
211
- `--agent-key <file>` names your agent key when it is not the
212
- `mandate.agent-key.json` beside the credential; `--max` and `--key` do not
223
+ `pay` signs with the mandate key beside the credential, `mandate.key.json`
224
+ for `mandate.json`; `--mandate-key-file <file>` names it when it is
225
+ elsewhere. Never show the key file's contents. `--max` and `--key` do not
213
226
  apply. A payment outside the mandate exits 1 with
214
227
  `error: payment refused: <reason> (…)`, a reason starting `mandate_`. Tell
215
228
  the user which limit it was; only the owner can change a mandate. After
216
229
  `mandate_revoked`, ask the user for the credential that replaced it, and
217
- pay with that. If the error says there is no agent key, pass the
218
- `--agent-key` it names.
230
+ pay with that. If the error says no key beside the credential is this
231
+ mandate's, ask the user where the key file is, and pass it as
232
+ `--mandate-key-file`.
219
233
 
220
234
  A seller that asks for your signed order gets it with the payment, and
221
235
  `pay` prints it as `signed-offer <text>`. Keep it, and pass it to
222
- `mandate verify --issuer <file> --tx <hash> --signed-offer <text>` to check the two
223
- together.
236
+ `mandate verify --credential <file> --issuer <file> --tx <hash> --signed-offer <text> --network testnet --rpc-url <endpoint>`
237
+ to check the two together.
224
238
 
225
239
  `mandate status` shows what is left: read `spent <amount> of <budget>`,
226
240
  `revoked yes|no` and the `payee` lines.
@@ -229,22 +243,42 @@ together.
229
243
  metal-agent mandate status --credential ./mandate.json --network testnet --rpc-url <endpoint>
230
244
  ```
231
245
 
232
- `mandate pull` pays an address the mandate allows, with no seller. The gas
233
- key beside the credential, `mandate.gas-key.json`, submits it and pays the
234
- gas, so ask the user to fund its `gas-key-address` first. `outcome paid`, or `outcome refused, not sent` with `reason` and `recorded no` lines,
235
- says what happened; a pull refused when checked sends nothing and costs no gas. Pass
236
- `--record-refusal` only when the user asks for the refusal to be recorded
237
- on chain. If a pull fails after printing `transaction <hash>`, run
238
- `metal-agent status <hash>` before pulling again; it may have paid.
246
+ `mandate pull` pays an address the mandate allows, with no seller. The
247
+ facilitator submits it and pays the gas. Pass `--payment-id` with the id of
248
+ the payment it is for, such as the refund's or the invoice's: two payouts of
249
+ one amount to one payee, while the first is pending, are two payments
250
+ only under two ids. The `outcome`
251
+ line says what happened: `paid`, exit 0; `refused, not sent` with `reason`
252
+ and `recorded no`, for a pull refused when checked, which sends nothing;
253
+ `refused` with `reason`, for one the account refused and recorded;
254
+ `refused, not paid`, for a sent pull that can no longer land; `held`,
255
+ exit 4, for one the payee's receive policy holds in escrow, so the payee was
256
+ not paid and the amount counts against the budget: do not send it again;
257
+ the payee, or the authority its policy names, releases it; or `pending`,
258
+ exit 3. Refusals exit 1. Pass `--record-refusal`, with `--key` naming a
259
+ funded key to send it, only when the user asks for the refusal to be
260
+ recorded on chain. On `outcome pending`, run the same command again, on the
261
+ same machine, with the same credential, `--payment-id`, `--to` and
262
+ `--amount`: it sends the same pull, which pays at most once, or reports its
263
+ outcome. Never add, drop or change the payment id, or change the amount, to
264
+ pay a pending pull again. After `outcome refused`, nothing was paid, and the
265
+ same payment id may be sent with other values. `error: the pull was not
266
+ sent: …` names why, such as the facilitator's refusal; tell the user.
267
+ An error saying `the pull kept before may have been sent and can land until
268
+ …` means that pull can still land until then: tell the user, and never pay
269
+ it under another payment id. The same holds for an error naming an event the SDK
270
+ does not decode: the pull may have paid.
239
271
 
240
272
  ```bash
241
- metal-agent mandate pull --credential ./mandate.json --to <payee address> --amount 2.50 --network testnet --rpc-url <endpoint>
273
+ metal-agent mandate pull --credential ./mandate.json --to <payee address> --amount 2.50 --payment-id <payment id> --network testnet --rpc-url <endpoint>
242
274
  ```
243
275
 
244
276
  `mandate verify` checks the mandate and every payment under it from the
245
277
  chain alone, or one `--tx <hash>`, and exits 1 when a check fails. Run it
246
278
  when the user asks whether a payment was within the mandate; read
247
- `verified yes|no`, and a failed `step` line names what differs. It needs
279
+ `verified yes|no`, and a failed `step` line names what differs. A failure
280
+ that names a topic the SDK does not decode means metal-agent and the
281
+ account may be different versions; tell the user. It needs
248
282
  the issuer's public key file, the `issuer-public-file` that `credential
249
283
  create` printed; ask the user for it.
250
284
 
@@ -252,9 +286,6 @@ create` printed; ask the user for it.
252
286
  metal-agent mandate verify --credential ./mandate.json --issuer <issuer public key file> --network testnet --rpc-url <endpoint>
253
287
  ```
254
288
 
255
- `--issuer` is the issuer's public key file the user gave you with the
256
- credential; ask for it if you do not have it.
257
-
258
289
  ## status
259
290
 
260
291
  Show a settlement from chain data: status, block, submitter, gas paid in
@@ -269,12 +300,23 @@ metal-agent status <transaction hash> --network testnet --rpc-url <endpoint>
269
300
  ## mcp
270
301
 
271
302
  Serve `pay`, `fund` and `status` as MCP tools, each taking a `network`, over
272
- stdio for an MCP host. What `pay` spends is fixed when the server starts,
273
- by its key and `--max`, or by one mandate; `pay` takes the request as
303
+ stdio for an MCP host; under a mandate, `mandate_pull`, `mandate_status` and
304
+ `mandate_verify` as well. What `pay` and `mandate_pull` spend is set when
305
+ the server starts, by whoever starts it: a key file and `--max`, or one
306
+ mandate's credential file, which each call reads. `pay` takes the request as
274
307
  optional `method`, `body` and `headers`, and under a key a `max` that can
275
- only lower the server's limit. `status` takes the endpoint as `rpcUrl`, which testnet
276
- needs unless the server's environment sets `METAL_RPC_URL`. No tool chooses a key, a mandate or a higher limit, and none
277
- sets or changes a mandate.
308
+ only lower the server's limit, and ends a refusal after signing, or a
309
+ payment that may have settled, with a `next:` line. `fund` and `status`
310
+ take the endpoint as `rpcUrl`, which
311
+ `status` on testnet needs unless the server's environment sets
312
+ `METAL_RPC_URL`. With the server's `METAL_RPC_URL`, `fund` asks the testnet
313
+ faucet nothing for an address that already holds about a full grant. The
314
+ mandate tools take no `rpcUrl`: they read the chain through the server's
315
+ `METAL_RPC_URL`, or devnet's default endpoint, and fail naming a chain other
316
+ than the network's. `mandate_pull` takes `to`, `amount` and a `paymentId`,
317
+ one per payment, and ends any outcome but `paid` with a `next:` line;
318
+ `mandate_verify` takes the `issuers` to trust. No tool chooses a key, a
319
+ mandate or a higher limit, and none sets or changes a mandate.
278
320
 
279
321
  ```bash
280
322
  metal-agent mcp