@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.
- package/README.md +65 -39
- package/dist/chain.js +1 -1
- package/dist/commands/fund.js +28 -14
- package/dist/commands/key.js +2 -2
- package/dist/commands/mandate.js +616 -142
- package/dist/commands/pay.js +86 -13
- package/dist/help.js +20 -19
- package/dist/index.js +40 -14
- package/dist/keystore.js +30 -18
- package/dist/mcp.js +273 -31
- package/package.json +6 -6
- package/skills/metal-agent/SKILL.md +93 -51
|
@@ -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
|
|
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 --
|
|
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.
|
|
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
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
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 ./
|
|
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
|
|
139
|
-
|
|
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
|
|
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 ./
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
195
|
-
not a `payment refused` line, such as `fetch failed`
|
|
196
|
-
from the seller, the payment may have settled. Do not
|
|
197
|
-
the user, with the `nonce` line `pay` printed; when the
|
|
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
|
-
|
|
212
|
-
`mandate.
|
|
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
|
|
218
|
-
|
|
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
|
|
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
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
`
|
|
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.
|
|
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
|
|
273
|
-
|
|
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
|
|
276
|
-
|
|
277
|
-
|
|
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
|