@aifinpay/mcp 2.10.0 → 2.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -10
- package/bin/aifinpay-mcp.js +149 -42
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +17 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/payable-fetch.d.ts.map +1 -1
- package/dist/tools/payable-fetch.js +10 -4
- package/dist/tools/payable-fetch.js.map +1 -1
- package/dist/tools/payment-setup-status.d.ts +99 -0
- package/dist/tools/payment-setup-status.d.ts.map +1 -0
- package/dist/tools/payment-setup-status.js +251 -0
- package/dist/tools/payment-setup-status.js.map +1 -0
- package/dist/tools/production-control.d.ts.map +1 -1
- package/dist/tools/production-control.js +106 -6
- package/dist/tools/production-control.js.map +1 -1
- package/package.json +2 -2
- package/skills/SKILL.md +75 -20
package/README.md
CHANGED
|
@@ -4,16 +4,61 @@ AiFinPay MCP server for persistent agent identity, Agent Passport resolution,
|
|
|
4
4
|
route discovery and non-signing settlement invoices. Canonical domain:
|
|
5
5
|
**aifinpay.io**.
|
|
6
6
|
|
|
7
|
-
Version **2.
|
|
8
|
-
|
|
9
|
-
lock refreshed) and canonical skill 2.9.0. The separate canonical producer's final immutable
|
|
7
|
+
Version **2.11.2** is prepared in this checkout, on the published agent 2.8.0
|
|
8
|
+
and canonical skill 2.10.1 (AiFinPay/skill b8d2309, published 2026-10-19). The separate canonical producer's final immutable
|
|
10
9
|
source pin is a required handoff, not a moving-branch substitution.
|
|
11
10
|
The published baseline checked2026-10-04 was MCP2.5.0. Package publication and
|
|
12
11
|
real registry dependency/lock refresh remain release gates; a source-cohort
|
|
13
12
|
build does not prove those steps. Owner-enabled v1.4 purchases with `payable_fetch` are
|
|
14
13
|
released: on Polygon since 2.2.0, on Base (ETH or USDC) since 2.5.0; site-wide
|
|
15
|
-
batches with `scope: "merchant"` since 2.4.1. Without payment configuration the server
|
|
16
|
-
|
|
14
|
+
batches with `scope: "merchant"` since 2.4.1. Without payment configuration the server
|
|
15
|
+
lists every tool, including `payable_fetch`, but signs nothing: `payable_fetch`
|
|
16
|
+
and `payment_setup_status` answer with the setup checklist instead.
|
|
17
|
+
|
|
18
|
+
## First payment in five steps
|
|
19
|
+
|
|
20
|
+
Each step is one command or one tool call. Signing happens only in step 5,
|
|
21
|
+
and only once the owner has set every limit in step 4.
|
|
22
|
+
|
|
23
|
+
1. **Read the price.** `GET` the resource. The `402` names the merchant
|
|
24
|
+
(`merchant_id`), the price per request and the smallest batch (`$0.10` for
|
|
25
|
+
200 standard requests).
|
|
26
|
+
2. **Check the setup.** Call `payment_setup_status`. It returns the wallet
|
|
27
|
+
(persistent or ephemeral), whether payments are enabled, which owner limits
|
|
28
|
+
are set, the balance when the RPC answers, and `next_step`: the first thing
|
|
29
|
+
still missing.
|
|
30
|
+
3. **Persistent wallet.** If `wallet.persistent` is false, run
|
|
31
|
+
`npx @aifinpay/mcp init`. Without a terminal it prints one JSON document;
|
|
32
|
+
copy its `env` (the passphrase is only there) into the `aifinpay` server
|
|
33
|
+
entry of the MCP client config, reconnect the server, then call
|
|
34
|
+
`agent_reload`. Never fund an ephemeral address.
|
|
35
|
+
4. **Fund and enable.** Tell the owner `addresses.evm` and the amount: the
|
|
36
|
+
batch price in POL plus the gas cap, so about `0.5 POL` for one `$0.10`
|
|
37
|
+
batch at `$0.20`/POL plus up to `0.3 POL` gas (the SDK refuses before
|
|
38
|
+
signing if the worst-case fee exceeds the cap). When the owner confirms
|
|
39
|
+
funding, they add the payment settings to the same `env` and restart the
|
|
40
|
+
aifinpay MCP server in the client (`agent_reload` does not read env):
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"AIFINPAY_PAYMENTS_ENABLED": "1",
|
|
45
|
+
"AIFINPAY_GATEWAY_ORIGINS": "https://dev.ratersapp.com",
|
|
46
|
+
"AIFINPAY_GATEWAY_PATH_MODE": "direct",
|
|
47
|
+
"AIFINPAY_MAX_USD": "0.15",
|
|
48
|
+
"AIFINPAY_DAILY_USD": "1.00",
|
|
49
|
+
"AIFINPAY_MAX_GAS_POL": "0.3"
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`payment_setup_status` then reports `ready: true`.
|
|
54
|
+
|
|
55
|
+
5. **Pay.** `payable_fetch({"url": "https://dev.ratersapp.com/api/agent/genres/list"})`
|
|
56
|
+
buys the batch on Polygon (splitter v1.4) and returns the content and the
|
|
57
|
+
receipt summary. Later requests reuse the batch.
|
|
58
|
+
|
|
59
|
+
Polygon and Base are served on v1.4 today; `settlement_routes` lists them
|
|
60
|
+
first, with `live: true`. Its `legacy_v13` section describes the older
|
|
61
|
+
splitter v1.3 routes, which `payable_fetch` does not use.
|
|
17
62
|
|
|
18
63
|
## Enable native paid GET requests
|
|
19
64
|
|
|
@@ -171,16 +216,19 @@ state file in chat. Unconfirmed payments consume the budget conservatively.
|
|
|
171
216
|
| `agent_reload` | Reload local wallet files in the current MCP connection. |
|
|
172
217
|
| `agent_quota` | Read the agent's quota. |
|
|
173
218
|
| `agent_passport_resolve` | Resolve the global Agent Passport identity. |
|
|
174
|
-
| `
|
|
219
|
+
| `payment_setup_status` | Read-only setup checklist with the one `next_step`. |
|
|
220
|
+
| `settlement_routes` | Splitter v1.4 routes (live now) first, then legacy v1.3. |
|
|
175
221
|
| `settlement_invoice` | Prepare a non-signing settlement invoice. |
|
|
176
222
|
| `agent_history` | Read indexed settlements or retained receipt batches. |
|
|
177
223
|
| `settlement_solana` | Build a non-signing Solana settlement invoice. |
|
|
178
224
|
| `settlement_casper` | Build a non-signing Casper settlement invoice. |
|
|
179
225
|
| `deployment_info` | Read deployments: addresses, assets, settlement status. |
|
|
180
226
|
|
|
181
|
-
`payable_fetch` is
|
|
182
|
-
|
|
183
|
-
|
|
227
|
+
`payable_fetch` is always listed. It signs only with a persistent wallet,
|
|
228
|
+
`AIFINPAY_PAYMENTS_ENABLED=1` and every owner limit; before that it returns the
|
|
229
|
+
`payment_setup_status` checklist as a tool error and contacts nothing. With
|
|
230
|
+
payments enabled and any owner limit missing or invalid, the server refuses to
|
|
231
|
+
start rather than hiding the tool. It accepts
|
|
184
232
|
only `url`, `max_amount_usd`, `scope` and `expected_merchant_id`; `max_amount_usd`
|
|
185
233
|
can lower the owner's per-payment cap for one call, never raise it.
|
|
186
234
|
|
|
@@ -267,7 +315,39 @@ AIFINPAY_WALLET_PASSPHRASE='<a long passphrase>' npx @aifinpay/mcp init
|
|
|
267
315
|
The keystore is encrypted at rest and the MCP server needs the same
|
|
268
316
|
`AIFINPAY_WALLET_PASSPHRASE` to load it. For a disposable test wallet only,
|
|
269
317
|
`npx @aifinpay/mcp init --plaintext` writes it unencrypted (mode 600); without
|
|
270
|
-
either, `init` refuses rather than create an unencrypted wallet
|
|
318
|
+
either, `init` on a terminal refuses rather than create an unencrypted wallet
|
|
319
|
+
you might fund.
|
|
320
|
+
|
|
321
|
+
Without a terminal on stdin (an agent's subprocess), or with
|
|
322
|
+
`AIFINPAY_NONINTERACTIVE=1`, `init` never prompts. It generates a 192-bit
|
|
323
|
+
passphrase, encrypts the keystore and prints one JSON document:
|
|
324
|
+
|
|
325
|
+
```json
|
|
326
|
+
{
|
|
327
|
+
"keystore": "/home/me/.aifinpay/agent.json",
|
|
328
|
+
"created": true,
|
|
329
|
+
"encrypted": true,
|
|
330
|
+
"source": "legacy-keystore",
|
|
331
|
+
"addresses": { "evm": "0x…", "solana": "…", "casper": "account-hash-…" },
|
|
332
|
+
"env": { "AIFINPAY_WALLET_PASSPHRASE": "<generated>" },
|
|
333
|
+
"passphrase_note": "…",
|
|
334
|
+
"payment_env_example": { "AIFINPAY_PAYMENTS_ENABLED": "1", "…": "…" },
|
|
335
|
+
"next_step": "Put \"env\" into the aifinpay server entry of the MCP client config …"
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
The passphrase appears only inside `env`, because the caller must put it in
|
|
340
|
+
the client config and there is no other channel; a process that captures that
|
|
341
|
+
output captures the passphrase, so treat the output as a secret. A second run
|
|
342
|
+
keeps the wallet and prints a placeholder instead of the passphrase. When
|
|
343
|
+
`AIFINPAY_HOME` is set, `env` also carries it (absolute), so the server reads the
|
|
344
|
+
keystore init wrote; `payment_setup_status` gives the init command with the
|
|
345
|
+
server's `AIFINPAY_HOME` for the same reason. If the keystore exists, is
|
|
346
|
+
encrypted and `AIFINPAY_WALLET_PASSPHRASE` is unset, `init` leaves it untouched,
|
|
347
|
+
prints one JSON line naming the variable and exits with status 2; its
|
|
348
|
+
`next_step` is to run init in a new, empty `AIFINPAY_HOME`
|
|
349
|
+
(`~/.aifinpay/agent-<yyyymmdd>`) and put the `env` it prints into the client
|
|
350
|
+
config.
|
|
271
351
|
|
|
272
352
|
Select the wallet in this order: `SEED_HASH` → `./aifinpay/agents.json` →
|
|
273
353
|
legacy `AIFINPAY_AGENT_SECRET` → `~/.aifinpay/agent.json`.
|
package/bin/aifinpay-mcp.js
CHANGED
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
linkSync,
|
|
42
42
|
unlinkSync,
|
|
43
43
|
} from "node:fs";
|
|
44
|
-
import { join } from "node:path";
|
|
44
|
+
import { join, resolve } from "node:path";
|
|
45
45
|
import { homedir } from "node:os";
|
|
46
46
|
import { createRequire } from "node:module";
|
|
47
47
|
import { scryptSync, randomBytes, createCipheriv, createDecipheriv } from "node:crypto";
|
|
@@ -75,6 +75,11 @@ if (arg === "--help" || arg === "-h" || arg === "help") {
|
|
|
75
75
|
Run init once. It writes ${KEYSTORE} with mode 600 and the server picks
|
|
76
76
|
it up automatically — you do not have to put the secret in a config file.
|
|
77
77
|
|
|
78
|
+
Without a terminal on stdin (an agent's subprocess), or with
|
|
79
|
+
AIFINPAY_NONINTERACTIVE=1, init never prompts: it generates the passphrase
|
|
80
|
+
itself, encrypts the keystore and prints one JSON document with the keystore
|
|
81
|
+
path, the public addresses and the exact "env" block for the MCP client config.
|
|
82
|
+
|
|
78
83
|
Env (all optional):
|
|
79
84
|
SEED_HASH 32-byte hex seed; highest priority
|
|
80
85
|
AIFINPAY_AGENTS_FILE project agents file (default ./aifinpay/agents.json)
|
|
@@ -86,9 +91,10 @@ Env (all optional):
|
|
|
86
91
|
AIFINPAY_TIMEOUT_MS default 30000
|
|
87
92
|
AIFINPAY_HOME default ~/.aifinpay
|
|
88
93
|
|
|
89
|
-
Payments (payable_fetch)
|
|
94
|
+
Payments (payable_fetch) sign nothing until the owner sets all of
|
|
90
95
|
AIFINPAY_PAYMENTS_ENABLED=1, AIFINPAY_GATEWAY_ORIGINS, AIFINPAY_MAX_USD,
|
|
91
|
-
AIFINPAY_DAILY_USD and AIFINPAY_MAX_GAS_POL. init prints an example block
|
|
96
|
+
AIFINPAY_DAILY_USD and AIFINPAY_MAX_GAS_POL. init prints an example block;
|
|
97
|
+
the payment_setup_status tool says which of them is still missing.
|
|
92
98
|
`);
|
|
93
99
|
process.exit(0);
|
|
94
100
|
}
|
|
@@ -100,7 +106,14 @@ if (arg === "--version" || arg === "-v" || arg === "version") {
|
|
|
100
106
|
|
|
101
107
|
// ── init ──────────────────────────────────────────────────────────────────
|
|
102
108
|
|
|
103
|
-
const
|
|
109
|
+
const PASSPHRASE_ENV = "AIFINPAY_WALLET_PASSPHRASE";
|
|
110
|
+
let PASSPHRASE = process.env[PASSPHRASE_ENV] || null;
|
|
111
|
+
// An agent's subprocess has no terminal on stdin. Nothing here may wait for a
|
|
112
|
+
// human then: a 2026-10-19 agent run hung 167 s on a passphrase it could not
|
|
113
|
+
// type and invented its own key handling instead. In this mode init generates
|
|
114
|
+
// the passphrase itself and prints JSON the agent can act on.
|
|
115
|
+
const NONINTERACTIVE = process.env.AIFINPAY_NONINTERACTIVE === "1" || !process.stdin.isTTY;
|
|
116
|
+
let GENERATED_PASSPHRASE = false;
|
|
104
117
|
|
|
105
118
|
// Optional at-rest encryption. Mode 600 keeps the keystore from OTHER users; it
|
|
106
119
|
// does nothing against malware running as YOU — the threat the OSINT write-up of
|
|
@@ -130,7 +143,7 @@ function encryptSecret(secretB58) {
|
|
|
130
143
|
};
|
|
131
144
|
}
|
|
132
145
|
function decryptSecret(store) {
|
|
133
|
-
if (!PASSPHRASE) throw new Error(`${KEYSTORE} is encrypted but
|
|
146
|
+
if (!PASSPHRASE) throw new Error(`${KEYSTORE} is encrypted but ${PASSPHRASE_ENV} is not set.`);
|
|
134
147
|
const key = scryptSync(PASSPHRASE, Buffer.from(store.salt, "base64"), 32, {
|
|
135
148
|
N: 1 << 15,
|
|
136
149
|
r: 8,
|
|
@@ -160,31 +173,75 @@ function readKeystore() {
|
|
|
160
173
|
return typeof parsed?.secretB58 === "string" ? parsed : null;
|
|
161
174
|
}
|
|
162
175
|
|
|
163
|
-
// The owner settings that register payable_fetch, as init prints them. README
|
|
164
|
-
// "Enable native paid GET requests" shows the same block; a test keeps the two
|
|
165
|
-
// equal and starts a server with it. The gas cap is a worst case at the current
|
|
166
|
-
// Polygon gas price, not the fee: 0.05 POL refused every payment at ~280 gwei.
|
|
167
|
-
const PAYMENT_ENV = {
|
|
168
|
-
AIFINPAY_PAYMENTS_ENABLED: "1",
|
|
169
|
-
AIFINPAY_GATEWAY_ORIGINS: "https://merchant.example",
|
|
170
|
-
AIFINPAY_GATEWAY_PATH_MODE: "direct",
|
|
171
|
-
AIFINPAY_MAX_USD: "0.15",
|
|
172
|
-
AIFINPAY_DAILY_USD: "1.00",
|
|
173
|
-
AIFINPAY_MAX_GAS_POL: "0.3",
|
|
174
|
-
};
|
|
175
|
-
|
|
176
176
|
if (arg === "init") {
|
|
177
177
|
const { Agent, AiFinPayAgent } = await import("@aifinpay/agent");
|
|
178
178
|
|
|
179
179
|
const { loadConfigFromEnv } = await import("../dist/config.js");
|
|
180
180
|
const { loadWalletIdentity } = await import("../dist/identity.js");
|
|
181
|
+
const { PAYMENT_ENV, lockedKeystoreStep } = await import("../dist/tools/payment-setup-status.js");
|
|
181
182
|
const config = loadConfigFromEnv();
|
|
182
|
-
|
|
183
|
+
// A keystore that cannot be opened is reported in one line that names the
|
|
184
|
+
// variable, never as a stack trace — and never replaced. An agent cannot ask
|
|
185
|
+
// anyone for the passphrase, so its JSON also names the way past it that
|
|
186
|
+
// touches nothing: a new wallet in a new, empty AIFINPAY_HOME.
|
|
187
|
+
const failKeystore = (error) => {
|
|
188
|
+
const line =
|
|
189
|
+
!PASSPHRASE && existsSync(KEYSTORE)
|
|
190
|
+
? `${KEYSTORE} exists and is encrypted; set ${PASSPHRASE_ENV} to the passphrase used at init (it is not set in this environment).`
|
|
191
|
+
: error.message;
|
|
192
|
+
let encrypted = false;
|
|
193
|
+
try {
|
|
194
|
+
encrypted = Boolean(JSON.parse(readFileSync(KEYSTORE, "utf8"))?.enc);
|
|
195
|
+
} catch {
|
|
196
|
+
/* No readable keystore: the error is about something else. */
|
|
197
|
+
}
|
|
198
|
+
if (NONINTERACTIVE)
|
|
199
|
+
process.stdout.write(
|
|
200
|
+
JSON.stringify({
|
|
201
|
+
error: line,
|
|
202
|
+
keystore: KEYSTORE,
|
|
203
|
+
...(PASSPHRASE ? {} : { missing_env: PASSPHRASE_ENV }),
|
|
204
|
+
...(encrypted ? { next_step: lockedKeystoreStep(KEYSTORE) } : {}),
|
|
205
|
+
}) + "\n"
|
|
206
|
+
);
|
|
207
|
+
else process.stderr.write(line + "\n");
|
|
208
|
+
process.exit(2);
|
|
209
|
+
};
|
|
210
|
+
let selected;
|
|
211
|
+
try {
|
|
212
|
+
selected = loadWalletIdentity(config);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
failKeystore(error);
|
|
215
|
+
}
|
|
216
|
+
const plaintext = process.argv.includes("--plaintext");
|
|
217
|
+
const addressesOf = (agent) => ({ evm: agent.evmAddress, solana: agent.solanaAddress, casper: agent.casperAddress });
|
|
218
|
+
const indexEnv =
|
|
219
|
+
selected?.derivationIndex === undefined ? {} : { AIFINPAY_WALLET_INDEX: String(selected.derivationIndex) };
|
|
220
|
+
// The server reads the keystore (and keeps its payment journal) under the same
|
|
221
|
+
// AIFINPAY_HOME init used, so a non-default one goes into the client env too,
|
|
222
|
+
// absolute: the client does not start the server in this directory.
|
|
223
|
+
const homeEnv = process.env.AIFINPAY_HOME ? { AIFINPAY_HOME: resolve(process.env.AIFINPAY_HOME) } : {};
|
|
224
|
+
// Non-interactive stdout is one JSON document and nothing else, so the
|
|
225
|
+
// caller can parse it. The same facts, as prose, go to a terminal.
|
|
226
|
+
const emit = (json, text) => process.stdout.write(NONINTERACTIVE ? JSON.stringify(json, null, 2) + "\n" : text);
|
|
227
|
+
const nextStep =
|
|
228
|
+
'Put "env" into the aifinpay server entry of the MCP client config and reconnect the server (or call agent_reload in an already connected one), then call payment_setup_status: it names the next step up to the first payment.';
|
|
229
|
+
|
|
183
230
|
if (selected && selected.source !== "legacy-keystore") {
|
|
184
231
|
const agent = selected.seedHash
|
|
185
232
|
? await AiFinPayAgent.fromSeed(selected.seedHash, { derivationIndex: selected.derivationIndex })
|
|
186
233
|
: await AiFinPayAgent.fromSolanaSecret(selected.secretB58);
|
|
187
|
-
|
|
234
|
+
emit(
|
|
235
|
+
{
|
|
236
|
+
keystore: null,
|
|
237
|
+
created: false,
|
|
238
|
+
encrypted: null,
|
|
239
|
+
source: selected.source,
|
|
240
|
+
addresses: addressesOf(agent),
|
|
241
|
+
env: { ...homeEnv, ...indexEnv },
|
|
242
|
+
payment_env_example: PAYMENT_ENV,
|
|
243
|
+
next_step: nextStep,
|
|
244
|
+
},
|
|
188
245
|
`Using ${selected.source}${selected.derivationIndex === undefined ? "" : ` (index ${selected.derivationIndex})`}; no replacement wallet created.\n` +
|
|
189
246
|
`EVM ${agent.evmAddress}\nSolana ${agent.solanaAddress}\nCasper ${agent.casperAddress}\n` +
|
|
190
247
|
`Keep your configured seed backed up privately. Call agent_reload in an already connected MCP server.\n`
|
|
@@ -192,21 +249,37 @@ if (arg === "init") {
|
|
|
192
249
|
process.exit(0);
|
|
193
250
|
}
|
|
194
251
|
|
|
195
|
-
|
|
252
|
+
const openExistingKeystore = () => {
|
|
253
|
+
try {
|
|
254
|
+
return readKeystore();
|
|
255
|
+
} catch (error) {
|
|
256
|
+
failKeystore(error);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
let store = openExistingKeystore();
|
|
196
260
|
let freshlyCreated = false;
|
|
197
261
|
// A new wallet is encrypted at rest unless the owner asks otherwise, by name.
|
|
198
262
|
// It used to be written in plaintext whenever AIFINPAY_WALLET_PASSPHRASE was
|
|
199
263
|
// unset — which is the default — so the documented one-liner produced an
|
|
200
264
|
// unencrypted key for a wallet people then funded. Existing keystores are
|
|
201
265
|
// untouched; only creating a new plaintext one needs the flag.
|
|
202
|
-
if (!store && !PASSPHRASE && !
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
266
|
+
if (!store && !PASSPHRASE && !plaintext) {
|
|
267
|
+
if (NONINTERACTIVE) {
|
|
268
|
+
// 192 random bits. The passphrase is printed once, inside the env block
|
|
269
|
+
// below, because the caller has to put it in the client config and there
|
|
270
|
+
// is no other channel; this is the trade-off of a wallet created by a
|
|
271
|
+
// process that cannot be asked anything.
|
|
272
|
+
PASSPHRASE = randomBytes(24).toString("base64url");
|
|
273
|
+
GENERATED_PASSPHRASE = true;
|
|
274
|
+
} else {
|
|
275
|
+
process.stderr.write(
|
|
276
|
+
`No wallet at ${KEYSTORE}, and none will be created unencrypted by default.\n\n` +
|
|
277
|
+
` Encrypted (recommended): AIFINPAY_WALLET_PASSPHRASE='<a long passphrase>' npx @aifinpay/mcp init\n` +
|
|
278
|
+
` Disposable test wallet: npx @aifinpay/mcp init --plaintext\n\n` +
|
|
279
|
+
`Keep the passphrase: an encrypted wallet cannot be recovered without it.\n`
|
|
280
|
+
);
|
|
281
|
+
process.exit(2);
|
|
282
|
+
}
|
|
210
283
|
}
|
|
211
284
|
if (!store) {
|
|
212
285
|
mkdirSync(HOME, { recursive: true, mode: 0o700 });
|
|
@@ -233,7 +306,9 @@ if (arg === "init") {
|
|
|
233
306
|
freshlyCreated = true;
|
|
234
307
|
} catch (error) {
|
|
235
308
|
if (error.code !== "EEXIST") throw error;
|
|
236
|
-
|
|
309
|
+
// The other process won; a passphrase generated here opens nothing.
|
|
310
|
+
if (GENERATED_PASSPHRASE) PASSPHRASE = null;
|
|
311
|
+
store = openExistingKeystore();
|
|
237
312
|
if (!store) throw new Error(`Existing ${KEYSTORE} is unreadable; refusing to replace it.`);
|
|
238
313
|
}
|
|
239
314
|
} finally {
|
|
@@ -241,6 +316,45 @@ if (arg === "init") {
|
|
|
241
316
|
if (ownsTemporary) unlinkSync(temporary);
|
|
242
317
|
}
|
|
243
318
|
}
|
|
319
|
+
const agent = selected?.seedHash
|
|
320
|
+
? await AiFinPayAgent.fromSeed(selected.seedHash, { derivationIndex: selected.derivationIndex })
|
|
321
|
+
: await AiFinPayAgent.fromSolanaSecret(store.secretB58);
|
|
322
|
+
// The server cannot open an encrypted keystore without the passphrase, so a
|
|
323
|
+
// config block without it does not start.
|
|
324
|
+
const encrypted = freshlyCreated ? Boolean(PASSPHRASE) : Boolean(store.encrypted);
|
|
325
|
+
|
|
326
|
+
if (NONINTERACTIVE) {
|
|
327
|
+
emit(
|
|
328
|
+
{
|
|
329
|
+
keystore: KEYSTORE,
|
|
330
|
+
created: freshlyCreated,
|
|
331
|
+
encrypted,
|
|
332
|
+
source: "legacy-keystore",
|
|
333
|
+
addresses: addressesOf(agent),
|
|
334
|
+
env: {
|
|
335
|
+
...homeEnv,
|
|
336
|
+
...(encrypted
|
|
337
|
+
? {
|
|
338
|
+
[PASSPHRASE_ENV]: GENERATED_PASSPHRASE
|
|
339
|
+
? PASSPHRASE
|
|
340
|
+
: `<the ${PASSPHRASE_ENV} already set in this environment>`,
|
|
341
|
+
}
|
|
342
|
+
: {}),
|
|
343
|
+
...indexEnv,
|
|
344
|
+
},
|
|
345
|
+
...(GENERATED_PASSPHRASE
|
|
346
|
+
? {
|
|
347
|
+
passphrase_note: `${PASSPHRASE_ENV} was generated for this wallet and appears only here, inside env. The wallet cannot be opened or recovered without it.`,
|
|
348
|
+
}
|
|
349
|
+
: {}),
|
|
350
|
+
payment_env_example: PAYMENT_ENV,
|
|
351
|
+
next_step: nextStep,
|
|
352
|
+
},
|
|
353
|
+
""
|
|
354
|
+
);
|
|
355
|
+
process.exit(0);
|
|
356
|
+
}
|
|
357
|
+
|
|
244
358
|
if (freshlyCreated) {
|
|
245
359
|
process.stdout.write(
|
|
246
360
|
PASSPHRASE
|
|
@@ -270,21 +384,15 @@ if (arg === "init") {
|
|
|
270
384
|
);
|
|
271
385
|
}
|
|
272
386
|
|
|
273
|
-
const agent = selected?.seedHash
|
|
274
|
-
? await AiFinPayAgent.fromSeed(selected.seedHash, { derivationIndex: selected.derivationIndex })
|
|
275
|
-
: await AiFinPayAgent.fromSolanaSecret(store.secretB58);
|
|
276
|
-
// The server cannot open an encrypted keystore without the passphrase, so a
|
|
277
|
-
// config block without it does not start.
|
|
278
|
-
const encrypted = freshlyCreated ? Boolean(PASSPHRASE) : Boolean(store.encrypted);
|
|
279
|
-
|
|
280
387
|
process.stdout.write(
|
|
281
388
|
`Your agent's addresses${selected?.derivationIndex === undefined ? "" : ` (index ${selected.derivationIndex})`} — the EVM one is the same on every EVM chain:\n\n` +
|
|
282
389
|
` EVM ${agent.evmAddress}\n` +
|
|
283
390
|
` Solana ${agent.solanaAddress}\n` +
|
|
284
391
|
` Casper ${agent.casperAddress}\n\n` +
|
|
285
392
|
`Add this to your MCP client config and connect/reconnect this MCP server.\n` +
|
|
286
|
-
`As printed it cannot pay
|
|
287
|
-
`settings further down
|
|
393
|
+
`As printed it cannot pay: payable_fetch is listed but signs nothing until\n` +
|
|
394
|
+
`you add the payment settings further down (payment_setup_status says what\n` +
|
|
395
|
+
`is still missing):\n\n` +
|
|
288
396
|
JSON.stringify(
|
|
289
397
|
{
|
|
290
398
|
mcpServers: {
|
|
@@ -292,10 +400,9 @@ if (arg === "init") {
|
|
|
292
400
|
command: "npx",
|
|
293
401
|
args: ["-y", `@aifinpay/mcp@${VERSION}`],
|
|
294
402
|
env: {
|
|
403
|
+
...homeEnv,
|
|
295
404
|
...(encrypted ? { AIFINPAY_WALLET_PASSPHRASE: "<the passphrase you used for init>" } : {}),
|
|
296
|
-
...
|
|
297
|
-
? {}
|
|
298
|
-
: { AIFINPAY_WALLET_INDEX: String(selected.derivationIndex) }),
|
|
405
|
+
...indexEnv,
|
|
299
406
|
},
|
|
300
407
|
},
|
|
301
408
|
},
|
package/dist/server.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export interface ToolContext {
|
|
|
47
47
|
paymentState?: PaymentStateStore;
|
|
48
48
|
/** AIFP-Agent-Framework for this connection's payments; unset sends none. */
|
|
49
49
|
framework?: AgentFramework;
|
|
50
|
+
/** Which identity the server loaded: "ephemeral", "legacy-keystore", "SEED_HASH", "agents.json" or "AIFINPAY_AGENT_SECRET". */
|
|
51
|
+
walletSource?: string;
|
|
50
52
|
log: (level: "info" | "warn" | "error", msg: string) => void;
|
|
51
53
|
}
|
|
52
54
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAgCvD;iFACiF;AACjF,wBAAsB,YAAY,CAAC,MAAM,GAAE,SAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2MxD;AA2BD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,+HAA+H;IAC/H,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D"}
|
package/dist/server.js
CHANGED
|
@@ -12,6 +12,7 @@ import { makeSafeFetch } from "./safe-fetch.js";
|
|
|
12
12
|
import { loadConfigFromEnv, validatePaymentConfig } from "./config.js";
|
|
13
13
|
import { PaymentStateStore } from "./payment-state.js";
|
|
14
14
|
import { payableFetchTool, runPayableFetch } from "./tools/payable-fetch.js";
|
|
15
|
+
import { initCommand, paymentSetupStatusTool, runPaymentSetupStatus } from "./tools/payment-setup-status.js";
|
|
15
16
|
import { agentPassportResolveTool, runAgentPassportResolve, settlementRoutesTool, runSettlementRoutes, settlementInvoiceTool, runSettlementInvoice, settlementSolanaTool, runSettlementSolana, settlementCasperTool, runSettlementCasper, } from "./tools/production-control.js";
|
|
16
17
|
import { deploymentInfoTool, runDeploymentInfo } from "./tools/supported-chains.js";
|
|
17
18
|
import { payChain } from "./pay-chains.js";
|
|
@@ -25,6 +26,7 @@ const safeFetch = makeSafeFetch({
|
|
|
25
26
|
// for those names — see safe-fetch.ts for why this is not a proxy switch.
|
|
26
27
|
trustedHosts: loadConfigFromEnv().trustedHosts,
|
|
27
28
|
});
|
|
29
|
+
const RELOAD_ENV_NOTE = "Owner limits and AIFINPAY_PAYMENTS_ENABLED are read only when this server starts; agent_reload re-reads the keystore and nothing else. If the owner has saved them since, have the client restart the aifinpay MCP server (restart the client, or disable and re-enable the server), then call payment_setup_status.";
|
|
28
30
|
/** Read-only by default. Explicit owner configuration enables the reviewed
|
|
29
31
|
* family-specific v1.4 payable_fetch path; legacy signing tools stay retired. */
|
|
30
32
|
export async function createServer(config = {}) {
|
|
@@ -61,7 +63,7 @@ export async function createServer(config = {}) {
|
|
|
61
63
|
}));
|
|
62
64
|
identitySource = configured?.source ?? "ephemeral";
|
|
63
65
|
if (!configured)
|
|
64
|
-
log("warn",
|
|
66
|
+
log("warn", `[aifinpay-mcp] EPHEMERAL wallet — DO NOT FUND. Run \`${initCommand(config.walletHome)}\`, then agent_reload in this connection.`);
|
|
65
67
|
let paymentState;
|
|
66
68
|
if (config.paymentsEnabled) {
|
|
67
69
|
validatePaymentConfig(config);
|
|
@@ -112,11 +114,15 @@ export async function createServer(config = {}) {
|
|
|
112
114
|
agentClaimSelfTool(),
|
|
113
115
|
{
|
|
114
116
|
name: "agent_reload",
|
|
115
|
-
description: "Reload the configured local wallet files after init or a file update, without starting a new conversation. Returns public addresses only.
|
|
117
|
+
description: "Reload the configured local wallet files after init or a file update, without starting a new conversation. Returns public addresses only. Owner limits and other env changes take effect only after the client restarts the aifinpay MCP server; agent_reload does not read them.",
|
|
116
118
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
117
119
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
118
120
|
},
|
|
119
|
-
|
|
121
|
+
// Always listed. Without the owner's setup it returns the same checklist
|
|
122
|
+
// as payment_setup_status and signs nothing; a fresh install used to show
|
|
123
|
+
// no payment tool at all, and agents stopped there.
|
|
124
|
+
paymentSetupStatusTool(),
|
|
125
|
+
payableFetchTool(),
|
|
120
126
|
agentQuotaTool(),
|
|
121
127
|
agentHistoryTool(),
|
|
122
128
|
...(config.devMode ? [devPaymentQuoteTool()] : []),
|
|
@@ -132,7 +138,7 @@ export async function createServer(config = {}) {
|
|
|
132
138
|
const { name, arguments: args } = request.params;
|
|
133
139
|
// The client named itself at initialize; unknown clients send no framework.
|
|
134
140
|
const framework = frameworkForClient(server.getClientVersion()?.name);
|
|
135
|
-
const ctx = { agent, config, log, paymentState, framework };
|
|
141
|
+
const ctx = { agent, config, log, paymentState, framework, walletSource: identitySource };
|
|
136
142
|
switch (name) {
|
|
137
143
|
case "agent_reload":
|
|
138
144
|
try {
|
|
@@ -157,6 +163,11 @@ export async function createServer(config = {}) {
|
|
|
157
163
|
evm: agent.evmAddress,
|
|
158
164
|
casper: agent.casperAddress,
|
|
159
165
|
reloaded: true,
|
|
166
|
+
// A reload that succeeds while payments stay off read as "the
|
|
167
|
+
// env was not picked up", and an agent stopped there
|
|
168
|
+
// (2026-10-19): config is fixed at start, so say so.
|
|
169
|
+
payments_enabled: Boolean(config.paymentsEnabled),
|
|
170
|
+
...(config.paymentsEnabled ? {} : { env_note: RELOAD_ENV_NOTE }),
|
|
160
171
|
}),
|
|
161
172
|
},
|
|
162
173
|
],
|
|
@@ -170,6 +181,8 @@ export async function createServer(config = {}) {
|
|
|
170
181
|
}
|
|
171
182
|
case "payable_fetch":
|
|
172
183
|
return runPayableFetch(ctx, args ?? {});
|
|
184
|
+
case "payment_setup_status":
|
|
185
|
+
return runPaymentSetupStatus(ctx, args ?? {});
|
|
173
186
|
case "agent_address":
|
|
174
187
|
return runAgentAddress(ctx, args ?? {});
|
|
175
188
|
case "agent_claim_self":
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAuB,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAC7G,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,2EAA2E;AAC3E,8EAA8E;AAC9E,qDAAqD;AACrD,MAAM,SAAS,GAAG,aAAa,CAAC;IAC9B,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,GAAG;IAC9D,8EAA8E;IAC9E,0EAA0E;IAC1E,YAAY,EAAE,iBAAiB,EAAE,CAAC,YAAY;CAC/C,CAAC,CAAC;AAEH,MAAM,eAAe,GACnB,sTAAsT,CAAC;AAEzT;iFACiF;AACjF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAM,GAAc,EAAE;IACvD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,UAAU,CAAC;IACvC,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAElC,IAAI,cAAc,GAAG,WAAW,CAAC;IACjC,KAAK,UAAU,eAAe;QAC5B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,wEAAwE;QACxE,sEAAsE;QACtE,MAAM,GAAG,GACP,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,IAAI,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAChH,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,SAAS;YACpB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,GAAG,CAAC,QAAQ,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,QAAQ,CAAC,eAAe,EAAE,CAAC;YAChG,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9E,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzF,CAAC;QACF,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ;YAC9B,CAAC,CAAC,MAAM,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC1D,CAAC,CAAC,MAAM,aAAa,CAAC,gBAAgB,CAAC,QAAQ,CAAC,SAAU,EAAE,OAAO,CAAC,CAAC;QACvE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC7C,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,eAAe,EAAE,CAAC;IAC3C,IAAI,KAAK,GACP,UAAU,EAAE,MAAM;QAClB,CAAC,MAAM,aAAa,CAAC,GAAG,CAAC;YACvB,SAAS,EAAE,SAAS;YACpB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B,CAAC,CAAC,CAAC;IACN,cAAc,GAAG,UAAU,EAAE,MAAM,IAAI,WAAW,CAAC;IACnD,IAAI,CAAC,UAAU;QACb,GAAG,CACD,MAAM,EACN,wDAAwD,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,2CAA2C,CAClI,CAAC;IACJ,IAAI,YAA2C,CAAC;IAChD,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QAC3B,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACpG,YAAY,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5E,CAAC;IACD,yEAAyE;IACzE,6EAA6E;IAC7E,sDAAsD;IACtD,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9E,KAAK,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QACvD,GAAG,CAAC,MAAM,EAAE,iCAAiC,MAAM,CAAC,YAAY,qBAAqB,CAAC,CAAC;IACzF,CAAC;IAED,GAAG,CAAC,MAAM,EAAE,uDAAuD,KAAK,CAAC,aAAa,WAAW,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAErH,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;QACE,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO;KAC/F,EACD,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAC/C,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAChE,SAAS,EAAE;YACT;gBACE,GAAG,EAAE,kBAAkB;gBACvB,IAAI,EAAE,gBAAgB;gBACtB,QAAQ,EAAE,eAAe;gBACzB,WAAW,EAAE,2FAA2F;aACzG;SACF;KACF,CAAC,CAAC,CAAC;IACJ,MAAM,CAAC,iBAAiB,CAAC,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpE,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK,kBAAkB;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACnF,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,kBAAkB;oBACvB,QAAQ,EAAE,eAAe;oBACzB,IAAI,EAAE,YAAY,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;iBAC3E;aACF;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE;YACL,gBAAgB,EAAE;YAClB,yEAAyE;YACzE,wEAAwE;YACxE,kBAAkB,EAAE;YACpB;gBACE,IAAI,EAAE,cAAc;gBACpB,WAAW,EACT,mRAAmR;gBACrR,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;gBAC5E,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE;aACnF;YACD,yEAAyE;YACzE,0EAA0E;YAC1E,oDAAoD;YACpD,sBAAsB,EAAE;YACxB,gBAAgB,EAAE;YAClB,cAAc,EAAE;YAChB,gBAAgB,EAAE;YAClB,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,wBAAwB,EAAE;YAC1B,oBAAoB,EAAE;YACtB,qBAAqB,EAAE;YACvB,oBAAoB,EAAE;YACtB,oBAAoB,EAAE;YACtB,kBAAkB,EAAE;SACrB;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,4EAA4E;QAC5E,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,IAAI,CAAC,CAAC;QACtE,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;QAC1F,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,cAAc;gBACjB,IAAI,CAAC;oBACH,MAAM,WAAW,GAAG,MAAM,eAAe,EAAE,CAAC;oBAC5C,IAAI,CAAC,WAAW;wBACd,MAAM,IAAI,KAAK,CAAC,iFAAiF,CAAC,CAAC;oBACrG,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;wBAC9E,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;oBACtE,CAAC;oBACD,IAAI,YAAY,IAAI,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;wBACnG,MAAM,IAAI,KAAK,CACb,oGAAoG,CACrG,CAAC;oBACJ,CAAC;oBACD,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;oBAC3B,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC;oBACpC,OAAO;wBACL,OAAO,EAAE;4BACP;gCACE,IAAI,EAAE,MAAM;gCACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oCACnB,MAAM,EAAE,cAAc;oCACtB,MAAM,EAAE,KAAK,CAAC,aAAa;oCAC3B,GAAG,EAAE,KAAK,CAAC,UAAU;oCACrB,MAAM,EAAE,KAAK,CAAC,aAAa;oCAC3B,QAAQ,EAAE,IAAI;oCACd,8DAA8D;oCAC9D,qDAAqD;oCACrD,qDAAqD;oCACrD,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC;oCACjD,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;iCACjE,CAAC;6BACH;yBACF;qBACF,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO;wBACL,OAAO,EAAE,IAAI;wBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yBAA0B,KAAe,CAAC,OAAO,EAAE,EAAE,CAAC;qBACvF,CAAC;gBACJ,CAAC;YACH,KAAK,eAAe;gBAClB,OAAO,eAAe,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC1C,KAAK,sBAAsB;gBACzB,OAAO,qBAAqB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAChD,KAAK,eAAe;gBAClB,OAAO,eAAe,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC1C,KAAK,kBAAkB;gBACrB,OAAO,iBAAiB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC5C,KAAK,aAAa;gBAChB,OAAO,aAAa,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YACxC,KAAK,eAAe;gBAClB,OAAO,eAAe,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC1C,KAAK,mBAAmB;gBACtB,OAAO,kBAAkB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC7C,KAAK,wBAAwB;gBAC3B,OAAO,uBAAuB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAClD,KAAK,mBAAmB;gBACtB,OAAO,mBAAmB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC9C,KAAK,oBAAoB;gBACvB,OAAO,oBAAoB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC/C,KAAK,mBAAmB;gBACtB,OAAO,mBAAmB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC9C,KAAK,mBAAmB;gBACtB,OAAO,mBAAmB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC9C,KAAK,iBAAiB;gBACpB,OAAO,iBAAiB,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YAC5C;gBACE,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,IAAI,EAAE,EAAE,CAAC;iBACtE,CAAC;QACN,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM;QACN,IAAI,KAAK;YACP,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB,CAAC,MAAiB;IAClD,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,eAAe;QAAE,OAAO;IAC/D,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;QAC/G,MAAM,IAAI,KAAK,CACb,0IAA0I,CAC3I,CAAC;IACJ,CAAC;IACD,IACE,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;QACvC,OAAO,MAAM,CAAC,aAAa,KAAK,UAAU;QAC1C,OAAO,MAAM,CAAC,eAAe,KAAK,UAAU,EAC5C,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IACD,MAAM,eAAe,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IAC9D,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,eAAe,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,yDAAyD,QAAQ,CAAC,IAAI,KAAK,eAAe,GAAG,CAAC,CAAC;IACjH,CAAC;AACH,CAAC;AAaD,SAAS,UAAU,CAAC,KAAgC,EAAE,GAAW;IAC/D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,GAAG,IAAI,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payable-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/payable-fetch.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"payable-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/payable-fetch.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAehD,wBAAgB,gBAAgB;IAE5B,IAAI;IACJ,WAAW;IAEX,WAAW;QACT,IAAI;QACJ,UAAU;YACR,GAAG;gBAAI,IAAI;gBAAY,WAAW;;YAClC,cAAc;gBACZ,IAAI;gBACJ,gBAAgB;gBAChB,WAAW;;YAEb,KAAK;gBACH,IAAI;gBACJ,IAAI;gBACJ,WAAW;;YAGb,oBAAoB;gBAClB,IAAI;gBACJ,OAAO;gBACP,WAAW;;;QAIf,QAAQ;QACR,oBAAoB;;IAEtB,WAAW;QAAI,YAAY;QAAS,aAAa;QAAQ,eAAe;;EAE3E;AAED,2FAA2F;AAC3F,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;GAyYpF"}
|
|
@@ -3,6 +3,7 @@ import { validatePaymentConfig } from "../config.js";
|
|
|
3
3
|
import { PaymentStateError } from "../payment-state.js";
|
|
4
4
|
import { independentNativeUsd } from "../native-price.js";
|
|
5
5
|
import { payChain } from "../pay-chains.js";
|
|
6
|
+
import { paymentSetupStatus } from "./payment-setup-status.js";
|
|
6
7
|
// "prefix" is left out on purpose: it needs a resource to anchor to, and the
|
|
7
8
|
// owner's two real requests are "this endpoint" and "this site".
|
|
8
9
|
const SCOPES = ["exact", "merchant"];
|
|
@@ -12,7 +13,7 @@ const MERCHANT_ID = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
|
12
13
|
export function payableFetchTool() {
|
|
13
14
|
return {
|
|
14
15
|
name: "payable_fetch",
|
|
15
|
-
description: 'Fetch a GET resource from an owner-approved AiFinPay merchant. Buys a prepaid batch through verified v1.4 on the chain the owner set in AIFINPAY_PAY_CHAIN (Polygon by default; other supported networks require explicit owner selection) — in its native currency (POL, SOL, ETH, AVAX, BNB or XRP), or in the stablecoin the owner set in AIFINPAY_PAY_ASSET (e.g. USDC; gas is still native) — within owner limits, then reuses its receipt. With scope "merchant" one batch covers every path on the site. Pending payments are recovered without sending another transaction. Other payment protocols are unsupported.',
|
|
16
|
+
description: 'Fetch a GET resource from an owner-approved AiFinPay merchant, paying its AIFP-1 402 when needed. Always listed: until the owner has set up a persistent wallet (npx @aifinpay/mcp init), AIFINPAY_PAYMENTS_ENABLED=1 and every limit, it signs nothing and returns the payment_setup_status checklist with the one next step. Buys a prepaid batch through verified v1.4 on the chain the owner set in AIFINPAY_PAY_CHAIN (Polygon by default; other supported networks require explicit owner selection) — in its native currency (POL, SOL, ETH, AVAX, BNB or XRP), or in the stablecoin the owner set in AIFINPAY_PAY_ASSET (e.g. USDC; gas is still native) — within owner limits, then reuses its receipt. With scope "merchant" one batch covers every path on the site. Pending payments are recovered without sending another transaction. Other payment protocols are unsupported.',
|
|
16
17
|
inputSchema: {
|
|
17
18
|
type: "object",
|
|
18
19
|
properties: {
|
|
@@ -44,6 +45,14 @@ export async function runPayableFetch(ctx, args) {
|
|
|
44
45
|
let state;
|
|
45
46
|
let chain;
|
|
46
47
|
try {
|
|
48
|
+
const store = ctx.paymentState;
|
|
49
|
+
// Not set up: say exactly what is missing instead of refusing in one line.
|
|
50
|
+
// Nothing below runs, so nothing is quoted, signed or sent. The journal
|
|
51
|
+
// exists only for the persistent wallet the server started with.
|
|
52
|
+
if (!ctx.config.paymentsEnabled || !store || store.address !== ctx.agent.evmAddress.toLowerCase()) {
|
|
53
|
+
const status = await paymentSetupStatus(ctx, { readBalance: false });
|
|
54
|
+
return errorResult(JSON.stringify({ error: "payable_fetch is not set up yet; nothing was signed or paid.", ...status }, null, 2));
|
|
55
|
+
}
|
|
47
56
|
let feeCap;
|
|
48
57
|
try {
|
|
49
58
|
feeCap = validatePaymentConfig(ctx.config);
|
|
@@ -52,9 +61,6 @@ export async function runPayableFetch(ctx, args) {
|
|
|
52
61
|
catch (error) {
|
|
53
62
|
return errorResult(error.message);
|
|
54
63
|
}
|
|
55
|
-
const store = ctx.paymentState;
|
|
56
|
-
if (!store || store.address !== ctx.agent.evmAddress.toLowerCase())
|
|
57
|
-
return errorResult("A persistent matching wallet is required for payments.");
|
|
58
64
|
if (Object.keys(args).some((k) => !["url", "max_amount_usd", "scope", "expected_merchant_id"].includes(k)))
|
|
59
65
|
return errorResult("Only url, max_amount_usd, scope and expected_merchant_id are supported; no facilitator fallback.");
|
|
60
66
|
if (typeof args.url !== "string")
|