@arispay/payagent-mcp 2.8.0 → 3.0.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.
package/dist/index.js CHANGED
@@ -37,22 +37,8 @@ function platformToolsEnabled(raw = process.env.PAYAGENT_MCP_PROFILE) {
37
37
  var arispayUrl = getArispayUrl(process.env.ARISPAY_URL);
38
38
  var legacyAgentKey = process.env.ARISPAY_AGENT_KEY;
39
39
  var legacyWalletAddress = process.env.PAYAGENT_WALLET;
40
- function resolveAgent(name) {
41
- if (name) return getAgent(name);
42
- const agents = listAgents();
43
- return agents[0];
44
- }
45
- function resolveAgentKey(name) {
46
- if (name) {
47
- const stored = getAgent(name);
48
- if (stored) return { key: stored.apiKey, source: `agent \`${name}\`` };
49
- return void 0;
50
- }
51
- if (legacyAgentKey) return { key: legacyAgentKey, source: "ARISPAY_AGENT_KEY" };
52
- const first = listAgents()[0];
53
- if (first) return { key: first.apiKey, source: `agent \`${first.name}\`` };
54
- return void 0;
55
- }
40
+ var SELF_ENDUSER_EXTERNAL_ID = "self";
41
+ var buyformeUrl = process.env.BUYFORME_URL?.replace(/\/$/, "") ?? "https://buyforme.arispay.app";
56
42
  function requireDevKey() {
57
43
  const key = getApiKey();
58
44
  if (!key) {
@@ -68,34 +54,328 @@ function textResult(text, isError = false) {
68
54
  ...isError ? { isError } : {}
69
55
  };
70
56
  }
57
+ async function resolveWallet(client, name) {
58
+ const list = await client.listWallets();
59
+ return list.wallets.find((w) => w.name === name);
60
+ }
61
+ async function resolveSelfEndUserId(client) {
62
+ try {
63
+ const user = await client.getEndUserByExternalId(SELF_ENDUSER_EXTERNAL_ID);
64
+ return user.id;
65
+ } catch {
66
+ return void 0;
67
+ }
68
+ }
71
69
  var server = new McpServer({
72
70
  name: "payagent",
73
- version: "2.1.0"
71
+ version: "3.0.0"
74
72
  });
73
+ server.tool(
74
+ "create_user",
75
+ "Cold-start in one call: create an ArisPay user account plus the master funding account. Safe to re-run \u2014 it recovers the existing account instead of creating duplicates.",
76
+ {
77
+ email: z.string().describe("Email for the new ArisPay account."),
78
+ name: z.string().optional().describe("Human name. Falls back to the email local-part.")
79
+ },
80
+ async ({ email, name }) => {
81
+ try {
82
+ const result = await bootstrapAgent({
83
+ email,
84
+ name,
85
+ arispayUrl: process.env.ARISPAY_URL,
86
+ clientId: "payagent-mcp-bootstrap"
87
+ });
88
+ const devKey = getApiKey();
89
+ if (devKey) {
90
+ const client = new DelegationClient(arispayUrl, devKey);
91
+ try {
92
+ await client.createEndUser({
93
+ externalId: SELF_ENDUSER_EXTERNAL_ID,
94
+ email,
95
+ findOrCreate: true
96
+ });
97
+ } catch {
98
+ }
99
+ }
100
+ const lines = [
101
+ `\u2713 Account: ${result.email} (org \`${result.orgName}\`)`,
102
+ `\u2713 Master funding account ready.`,
103
+ "",
104
+ "Next steps:",
105
+ " 1. create_wallet({ name: 'Daily', perTx, daily, monthly })",
106
+ " 2. fund_wallet({ wallet: 'Daily', rail: 'europ' }) for SEPA / EUR\xD8P",
107
+ " or fund_wallet({ wallet: 'Daily', rail: 'card' }) for card top-up."
108
+ ];
109
+ return textResult(lines.join("\n"));
110
+ } catch (err) {
111
+ if (err instanceof BootstrapError) {
112
+ return textResult(`create_user failed (${err.code}): ${err.message}`, true);
113
+ }
114
+ return textResult(
115
+ `create_user failed: ${err instanceof Error ? err.message : String(err)}`,
116
+ true
117
+ );
118
+ }
119
+ }
120
+ );
121
+ server.tool(
122
+ "create_wallet",
123
+ "Create a sub-wallet / spending profile. Sub-wallets draw from the master funding account and enforce per-transaction, daily, and monthly spend limits.",
124
+ {
125
+ name: z.string().describe("Human name for this sub-wallet, e.g. 'Daily' or 'Travel'."),
126
+ perTx: z.number().int().positive().describe("Per-transaction spend cap in cents."),
127
+ daily: z.number().int().positive().describe("Daily spend cap in cents."),
128
+ monthly: z.number().int().positive().describe("Monthly spend cap in cents."),
129
+ allowedDomains: z.array(z.string()).optional().describe("If provided, restrict this sub-wallet to paying only these domains.")
130
+ },
131
+ async ({ name, perTx, daily, monthly, allowedDomains }) => {
132
+ try {
133
+ const devKey = requireDevKey();
134
+ const client = new DelegationClient(arispayUrl, devKey);
135
+ const wallet = await client.createWallet({
136
+ name,
137
+ perTx,
138
+ daily,
139
+ monthly,
140
+ allowedDomains
141
+ });
142
+ const lines = [
143
+ `\u2713 Sub-wallet \`${wallet.name}\` created.`,
144
+ ` id: ${wallet.id}`,
145
+ ` limits: ${wallet.limits.perTx ?? "\u2014"}\xA2 / tx, ${wallet.limits.daily ?? "\u2014"}\xA2 / day, ${wallet.limits.monthly ?? "\u2014"}\xA2 / month`,
146
+ "",
147
+ `Fund it with fund_wallet({ wallet: "${wallet.name}", rail: "europ" | "card" }).`
148
+ ];
149
+ return textResult(lines.join("\n"));
150
+ } catch (err) {
151
+ return textResult(
152
+ `create_wallet failed: ${err instanceof Error ? err.message : String(err)}`,
153
+ true
154
+ );
155
+ }
156
+ }
157
+ );
158
+ server.tool(
159
+ "list_wallets",
160
+ "List all sub-wallets under this account.",
161
+ {},
162
+ async () => {
163
+ try {
164
+ const devKey = requireDevKey();
165
+ const client = new DelegationClient(arispayUrl, devKey);
166
+ const list = await client.listWallets();
167
+ if (!list.wallets.length) {
168
+ return textResult(
169
+ "No sub-wallets yet. Create one with create_wallet({ name, perTx, daily, monthly })."
170
+ );
171
+ }
172
+ const lines = list.wallets.map(
173
+ (w) => [
174
+ `\`${w.name}\` (${w.id})`,
175
+ ` status: ${w.status}`,
176
+ ` limits: ${w.limits.perTx ?? "\u2014"}\xA2 / tx, ${w.limits.daily ?? "\u2014"}\xA2 / day, ${w.limits.monthly ?? "\u2014"}\xA2 / month`,
177
+ ` balance: ${w.balance} ${w.balanceCurrency}`
178
+ ].join("\n")
179
+ );
180
+ return textResult(lines.join("\n\n"));
181
+ } catch (err) {
182
+ return textResult(
183
+ `list_wallets failed: ${err instanceof Error ? err.message : String(err)}`,
184
+ true
185
+ );
186
+ }
187
+ }
188
+ );
189
+ server.tool(
190
+ "fund_wallet",
191
+ "Add money to the master funding account so a sub-wallet can spend. rail='europ' opens the Schuman KYC / vIBAN flow in a browser; rail='card' mints a hosted card-setup URL.",
192
+ {
193
+ wallet: z.string().describe("Name of a sub-wallet (used only for handoff context)."),
194
+ rail: z.enum(["europ", "card"]).describe("Funding rail: 'europ' for SEPA/EUR\xD8P, 'card' for debit/credit card."),
195
+ amount: z.number().positive().optional().describe("Optional preset amount in dollars.")
196
+ },
197
+ async ({ wallet, rail, amount }) => {
198
+ try {
199
+ const devKey = requireDevKey();
200
+ const client = new DelegationClient(arispayUrl, devKey);
201
+ const resolved = await resolveWallet(client, wallet);
202
+ if (!resolved) {
203
+ return textResult(`No sub-wallet named \`${wallet}\`. Run list_wallets().`, true);
204
+ }
205
+ if (rail === "europ") {
206
+ const handoffUrl = `${buyformeUrl}/onboarding/fund-europ?agentId=${encodeURIComponent(
207
+ resolved.id
208
+ )}`;
209
+ const lines2 = [
210
+ `Fund the master wallet for \`${wallet}\` with EUR\xD8P via Schuman:`,
211
+ "",
212
+ ` ${handoffUrl}`,
213
+ "",
214
+ "Open that link in a browser to:",
215
+ " 1. Verify your identity with Schuman Financial (one-time KYC).",
216
+ " 2. Receive a dedicated SEPA vIBAN.",
217
+ " 3. Send EUR by bank transfer; Schuman mints EUR\xD8P once it clears.",
218
+ "",
219
+ "After the deposit clears, the master funding account is credited and this sub-wallet can spend."
220
+ ];
221
+ return textResult(lines2.join("\n"));
222
+ }
223
+ const endUserId = await resolveSelfEndUserId(client);
224
+ if (!endUserId) {
225
+ return textResult(
226
+ "No payer record found. Run create_user first, then retry fund_wallet with rail='card'.",
227
+ true
228
+ );
229
+ }
230
+ const session = await client.createCardSetupSession({ endUserId });
231
+ const lines = [
232
+ `Add a card to fund the master wallet for \`${wallet}\`:`,
233
+ "",
234
+ ` ${session.setupUrl}`,
235
+ "",
236
+ ` Expires at: ${session.expiresAt}`,
237
+ "",
238
+ "After the card is verified, you can top up. Card top-ups are not yet exposed via MCP; use the BuyForMe web app or the ArisPay dashboard for now."
239
+ ];
240
+ return textResult(lines.join("\n"));
241
+ } catch (err) {
242
+ return textResult(
243
+ `fund_wallet failed: ${err instanceof Error ? err.message : String(err)}`,
244
+ true
245
+ );
246
+ }
247
+ }
248
+ );
249
+ server.tool(
250
+ "get_balance",
251
+ "Show the master funding-account balance(s) and a sub-wallet's spend limits. If no wallet is named, lists all sub-wallets.",
252
+ {
253
+ wallet: z.string().optional().describe("Optional sub-wallet name. Omit to list all sub-wallets.")
254
+ },
255
+ async ({ wallet }) => {
256
+ try {
257
+ const devKey = requireDevKey();
258
+ const client = new DelegationClient(arispayUrl, devKey);
259
+ if (!wallet) {
260
+ const list = await client.listWallets();
261
+ if (!list.wallets.length) {
262
+ return textResult("No sub-wallets yet. Create one with create_wallet().");
263
+ }
264
+ const lines2 = list.wallets.map((w) => {
265
+ const lim = `limits: ${w.limits.perTx ?? "\u2014"}\xA2 / tx, ${w.limits.daily ?? "\u2014"}\xA2 / day, ${w.limits.monthly ?? "\u2014"}\xA2 / month`;
266
+ return `\`${w.name}\` \u2014 ${w.balance} ${w.balanceCurrency} \u2014 ${lim}`;
267
+ });
268
+ return textResult(lines2.join("\n"));
269
+ }
270
+ const resolved = await resolveWallet(client, wallet);
271
+ if (!resolved) {
272
+ return textResult(`No sub-wallet named \`${wallet}\`.`, true);
273
+ }
274
+ const bal = await client.getWalletBalance(resolved.id);
275
+ const lines = [
276
+ `Sub-wallet: \`${bal.wallet.name}\``,
277
+ ` status: ${bal.wallet.status}`,
278
+ ` limits: ${bal.wallet.limits.perTx ?? "\u2014"}\xA2 / tx, ${bal.wallet.limits.daily ?? "\u2014"}\xA2 / day, ${bal.wallet.limits.monthly ?? "\u2014"}\xA2 / month`,
279
+ "",
280
+ "Master funding accounts:"
281
+ ];
282
+ if (!bal.fundingAccounts.length) {
283
+ lines.push(" No funded accounts yet. Use fund_wallet() to add money.");
284
+ } else {
285
+ for (const acct of bal.fundingAccounts) {
286
+ lines.push(` ${acct.currency}: ${acct.balance}\xA2 (${acct.provider ?? "internal"})`);
287
+ }
288
+ }
289
+ return textResult(lines.join("\n"));
290
+ } catch (err) {
291
+ return textResult(
292
+ `get_balance failed: ${err instanceof Error ? err.message : String(err)}`,
293
+ true
294
+ );
295
+ }
296
+ }
297
+ );
298
+ server.tool(
299
+ "pay_merchant",
300
+ "Pay a merchant from the master wallet through a sub-wallet. For balance-rail payments (from FundingAccount), merchantId is required. For card-rail payments, the user must have a verified card on file.",
301
+ {
302
+ wallet: z.string().describe("Name of the sub-wallet to spend through."),
303
+ merchantUrl: z.string().describe("Canonical merchant URL for this payment."),
304
+ amount: z.number().int().positive().describe("Amount in cents."),
305
+ memo: z.string().describe("Human-readable memo, e.g. 'T-shirt from getwatta.com'."),
306
+ merchantId: z.string().optional().describe("Required for balance-rail payments to a registered merchant."),
307
+ currency: z.string().optional().describe("Currency code. Default: USD."),
308
+ rail: z.enum(["balance", "card"]).optional().describe("Force balance or card rail. Default: server picks based on available funding.")
309
+ },
310
+ async ({ wallet, merchantUrl, amount, memo, merchantId, currency, rail }) => {
311
+ try {
312
+ const devKey = requireDevKey();
313
+ const client = new DelegationClient(arispayUrl, devKey);
314
+ const resolved = await resolveWallet(client, wallet);
315
+ if (!resolved) {
316
+ return textResult(`No sub-wallet named \`${wallet}\`.`, true);
317
+ }
318
+ const endUserId = await resolveSelfEndUserId(client);
319
+ if (!endUserId) {
320
+ return textResult(
321
+ "No payer record found. Run create_user first, then retry the payment.",
322
+ true
323
+ );
324
+ }
325
+ const payment = await client.createPayment(resolved.id, {
326
+ userId: endUserId,
327
+ amount,
328
+ currency: currency ?? "USD",
329
+ memo,
330
+ merchantUrl,
331
+ merchantId,
332
+ rail
333
+ });
334
+ const lines = [
335
+ `Payment ${payment.id}: ${payment.status}`,
336
+ ` rail: ${payment.rail}`,
337
+ ` amount: ${payment.amount}\xA2 ${payment.currency}`
338
+ ];
339
+ if (payment.merchantName) lines.push(` merchant: ${payment.merchantName}`);
340
+ if (payment.txHash) lines.push(` tx hash: ${payment.txHash}`);
341
+ if (payment.spend) {
342
+ const fmtCap = (v) => v == null ? "no cap" : `${v}\xA2`;
343
+ lines.push(
344
+ ` budget: ${fmtCap(payment.spend.remainingDaily)} left today, ${fmtCap(payment.spend.remainingMonthly)} this month`
345
+ );
346
+ }
347
+ if (payment.nextAction?.challengeUrl) {
348
+ lines.push(` 3DS challenge URL: ${payment.nextAction.challengeUrl}`);
349
+ }
350
+ if (payment.error) {
351
+ lines.push(` error: ${payment.error.code} \u2014 ${payment.error.message}`);
352
+ }
353
+ return textResult(lines.join("\n"), payment.status === "failed");
354
+ } catch (err) {
355
+ return textResult(
356
+ `pay_merchant failed: ${err instanceof Error ? err.message : String(err)}`,
357
+ true
358
+ );
359
+ }
360
+ }
361
+ );
75
362
  server.tool(
76
363
  "pay_api",
77
- "Make an HTTP request to a paid API, transparently paying any x402 (HTTP 402) challenge with USDC under the agent's spend limits. THE tool for fetching paid resources \u2014 never bypass a 402 or hand-roll payment.",
364
+ "Advanced: make an HTTP request to an x402-protected API, paying with USDC on Base via delegated signing. This is a separate rail from the wallet-centric balance/card flows.",
78
365
  {
79
- url: z.string().describe("The full URL of the API endpoint to call"),
80
- method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).default("GET").describe("HTTP method"),
81
- headers: z.record(z.string(), z.string()).optional().describe("Additional HTTP headers"),
82
- body: z.string().optional().describe("Request body (for POST/PUT/PATCH)"),
83
- agent: z.string().optional().describe(
84
- "Optional: name of a locally-stored agent to pay with. Defaults to ARISPAY_AGENT_KEY or the first stored agent."
85
- )
366
+ url: z.string().describe("The full URL of the API endpoint to call."),
367
+ method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).default("GET"),
368
+ headers: z.record(z.string(), z.string()).optional(),
369
+ body: z.string().optional(),
370
+ agent: z.string().optional().describe("Optional name of a stored x402 payer agent.")
86
371
  },
87
372
  async ({ url, method, headers, body, agent }) => {
88
- const resolved = resolveAgentKey(agent);
89
- if (!resolved) {
373
+ const stored = agent ? getAgent(agent) : listAgents()[0];
374
+ if (!stored?.apiKey) {
90
375
  return textResult(
91
376
  [
92
- "No agent available. Cold-start in one call:",
93
- ' bootstrap_agent({ email: "you@example.com", name: "<your-name>" })',
94
- "",
95
- "Or, if a developer key is already paired (`npx payagent init`):",
96
- " create_agent({ name, perTx, daily, monthly })",
97
- "",
98
- "Or set ARISPAY_AGENT_KEY for legacy single-agent mode."
377
+ "No x402 payer agent available. For wallet-centric payments use pay_merchant.",
378
+ "To create an x402 agent, use create_agent({ name, perTx, daily, monthly })."
99
379
  ].join("\n"),
100
380
  true
101
381
  );
@@ -104,14 +384,14 @@ server.tool(
104
384
  let paymentInfo;
105
385
  const fetch402 = payFetchDelegated({
106
386
  arispayUrl,
107
- apiKey: resolved.key,
387
+ apiKey: stored.apiKey,
108
388
  onPayment: (info) => {
109
389
  paymentInfo = info;
110
390
  }
111
391
  });
112
392
  const response = await fetch402(url, { method, headers, body });
113
393
  const responseBody = await response.text();
114
- const statusLine = paymentInfo ? `HTTP ${response.status} (paid ${paymentInfo.amountCents}\xA2 via ${resolved.source} \u2014 budget left: ${paymentInfo.remainingDaily}\xA2 today, ${paymentInfo.remainingMonthly}\xA2 this month)` : `HTTP ${response.status} (paid via ${resolved.source})`;
394
+ const statusLine = paymentInfo ? `HTTP ${response.status} (paid ${paymentInfo.amountCents}\xA2 via \`${stored.name}\` \u2014 budget left: ${paymentInfo.remainingDaily}\xA2 today, ${paymentInfo.remainingMonthly}\xA2 this month)` : `HTTP ${response.status} (paid via \`${stored.name}\`)`;
115
395
  return textResult([statusLine, "", responseBody].join("\n"));
116
396
  } catch (err) {
117
397
  const message = err instanceof Error ? err.message : String(err);
@@ -120,9 +400,7 @@ server.tool(
120
400
  [
121
401
  `Error: ${message}`,
122
402
  "",
123
- "This looks like the agent wallet is out of USDC. Fund it and retry:",
124
- " Use the `fund_agent` tool (rail='usdc' for the wallet address,",
125
- " or rail='europ' to fund via SEPA/EUR\xD8P in the browser)."
403
+ "The x402 agent wallet is out of USDC. Fund it with fund_agent({ name }) or switch to wallet-centric pay_merchant."
126
404
  ].join("\n"),
127
405
  true
128
406
  );
@@ -131,49 +409,17 @@ server.tool(
131
409
  }
132
410
  }
133
411
  );
134
- server.tool(
135
- "check_wallet",
136
- `Show the current agent's credentials, wallet address, and on-chain USDC balance \u2014 the quick "what state am I in" probe.`,
137
- {
138
- agent: z.string().optional().describe(
139
- "Optional: name of a locally-stored agent. Defaults to legacy ARISPAY_WALLET mode."
140
- )
141
- },
142
- async ({ agent }) => {
143
- const resolved = resolveAgent(agent);
144
- const walletAddress = resolved?.walletAddress ?? legacyWalletAddress;
145
- const keyTail = resolved?.apiKey.slice(-4) ?? (legacyAgentKey ? legacyAgentKey.slice(-4) : void 0);
146
- const lines = [`ArisPay URL: ${arispayUrl}`];
147
- if (resolved) lines.push(`Agent: ${resolved.name} (${resolved.agentId})`);
148
- if (keyTail) lines.push(`Agent key: ap_\u2026${keyTail}`);
149
- if (walletAddress) {
150
- lines.push(`Wallet: ${walletAddress}`);
151
- try {
152
- const raw = await getUSDCBalance(walletAddress, resolved?.network ?? "base");
153
- lines.push(`Balance: ${formatUSDC(raw)} USDC on ${resolved?.network ?? "base"}`);
154
- } catch (err) {
155
- lines.push(
156
- `Balance: unavailable (${err instanceof Error ? err.message : String(err)})`
157
- );
158
- }
159
- } else {
160
- lines.push("", "No wallet known. Use `create_agent` or set PAYAGENT_WALLET for legacy mode.");
161
- }
162
- lines.push("", "Manage limits + full history: https://arispay.app/dashboard");
163
- return textResult(lines.join("\n"));
164
- }
165
- );
166
412
  server.tool(
167
413
  "create_agent",
168
- "Provision an additional x402 payment agent (wallet + spend limits) under the already-paired developer account.",
414
+ "Advanced: provision an x402 payer agent with its own Base USDC wallet. Use create_wallet instead unless you specifically need to pay x402-protected HTTP resources.",
169
415
  {
170
- name: z.string().describe("Local identifier for this agent. Used by later tools."),
416
+ name: z.string().describe("Local identifier for this x402 agent."),
171
417
  perTx: z.number().int().positive().describe("Per-transaction spend cap in cents."),
172
418
  daily: z.number().int().positive().describe("Daily spend cap in cents."),
173
419
  monthly: z.number().int().positive().describe("Monthly spend cap in cents."),
174
- allowedDomains: z.array(z.string()).optional().describe("If provided, restrict this agent to paying only these domains."),
175
- network: z.enum(["base", "base-sepolia", "ethereum", "polygon"]).default("base").describe("EVM network the agent pays on."),
176
- agentType: z.string().optional().describe('Optional metadata label (e.g. "hermes").')
420
+ allowedDomains: z.array(z.string()).optional(),
421
+ network: z.enum(["base", "base-sepolia", "ethereum", "polygon"]).default("base"),
422
+ agentType: z.string().optional()
177
423
  },
178
424
  async ({ name, perTx, daily, monthly, allowedDomains, network, agentType }) => {
179
425
  try {
@@ -186,13 +432,13 @@ server.tool(
186
432
  agentType
187
433
  });
188
434
  const lines = [
189
- `\u2713 Agent \`${name}\` created.`,
435
+ `\u2713 x402 agent \`${name}\` created.`,
190
436
  ` Agent ID: ${agent.agentId}`,
191
437
  ` Wallet: ${agent.walletAddress}`,
192
438
  ` Network: ${agent.network}`,
193
439
  ` Limits: ${perTx}\xA2 / tx, ${daily}\xA2 / day, ${monthly}\xA2 / month`,
194
440
  "",
195
- ` Fund the wallet with USDC on ${agent.network}, then call \`get_balance\` with name="${name}".`
441
+ ` Fund the wallet with USDC on ${agent.network}, then call get_balance_agent with name="${name}".`
196
442
  ];
197
443
  return textResult(lines.join("\n"));
198
444
  } catch (err) {
@@ -203,57 +449,35 @@ server.tool(
203
449
  }
204
450
  }
205
451
  );
206
- var buyformeUrl = process.env.BUYFORME_URL?.replace(/\/$/, "") ?? "https://buyforme.arispay.app";
207
452
  server.tool(
208
453
  "fund_agent",
209
- "Get funding instructions for an agent's wallet. Use rail='usdc' for the direct USDC deposit address on Base, or rail='europ' for a browser handoff to complete Schuman identity verification and receive a SEPA vIBAN that credits EUR\xD8P.",
454
+ "Advanced: get the USDC deposit address for an x402 payer agent.",
210
455
  {
211
- name: z.string().describe("Name of a locally-stored agent."),
212
- rail: z.enum(["usdc", "europ"]).default("usdc").describe(
213
- "Funding rail: 'usdc' sends stablecoin directly to the agent wallet; 'europ' opens the BuyForMe EUR\xD8P onboarding flow in a browser to verify identity and get a vIBAN."
214
- )
456
+ name: z.string().describe("Name of a locally-stored x402 agent.")
215
457
  },
216
- async ({ name, rail }) => {
458
+ async ({ name }) => {
217
459
  const stored = getAgent(name);
218
- if (!stored) return textResult(`No locally-stored agent named \`${name}\`.`, true);
219
- if (rail === "europ") {
220
- const handoffUrl = `${buyformeUrl}/onboarding/fund-europ?agentId=${encodeURIComponent(
221
- stored.agentId
222
- )}`;
223
- const lines2 = [
224
- `Fund \`${name}\` with EUR\xD8P via Schuman:`,
225
- "",
226
- ` ${handoffUrl}`,
227
- "",
228
- "Open that link in a browser to:",
229
- " 1. Verify your identity with Schuman Financial (one-time KYC).",
230
- " 2. Receive a dedicated SEPA vIBAN.",
231
- " 3. Send EUR by bank transfer; Schuman mints EUR\xD8P to your wallet once it clears.",
232
- "",
233
- "After the deposit clears, call `get_balance` to confirm the agent's USDC balance."
234
- ];
235
- return textResult(lines2.join("\n"));
236
- }
460
+ if (!stored) return textResult(`No x402 agent named \`${name}\`.`, true);
237
461
  const lines = [
238
- `Fund \`${name}\` by sending USDC on ${stored.network ?? "base"} to:`,
462
+ `Fund x402 agent \`${name}\` by sending USDC on ${stored.network ?? "base"} to:`,
239
463
  "",
240
464
  ` ${stored.walletAddress}`,
241
465
  "",
242
466
  "Only send USDC on the network shown above. Other tokens or networks may be lost.",
243
- "Call `get_balance` when the deposit lands."
467
+ "Call get_balance_agent when the deposit lands."
244
468
  ];
245
469
  return textResult(lines.join("\n"));
246
470
  }
247
471
  );
248
472
  server.tool(
249
- "get_balance",
250
- "Server-side USDC balance + funding status for one named agent.",
473
+ "get_balance_agent",
474
+ "Advanced: on-chain USDC balance for an x402 payer agent.",
251
475
  {
252
- name: z.string().describe("Name of a locally-stored agent.")
476
+ name: z.string().describe("Name of a locally-stored x402 agent.")
253
477
  },
254
478
  async ({ name }) => {
255
479
  const stored = getAgent(name);
256
- if (!stored) return textResult(`No locally-stored agent named \`${name}\`.`, true);
480
+ if (!stored) return textResult(`No x402 agent named \`${name}\`.`, true);
257
481
  try {
258
482
  const devKey = requireDevKey();
259
483
  const client = new DelegationClient(arispayUrl, devKey);
@@ -267,7 +491,72 @@ server.tool(
267
491
  return textResult(lines.join("\n"));
268
492
  } catch (err) {
269
493
  return textResult(
270
- `get_balance failed: ${err instanceof Error ? err.message : String(err)}`,
494
+ `get_balance_agent failed: ${err instanceof Error ? err.message : String(err)}`,
495
+ true
496
+ );
497
+ }
498
+ }
499
+ );
500
+ server.tool(
501
+ "list_agents",
502
+ "Advanced: list x402 payer agents with on-chain wallets.",
503
+ {
504
+ withBalance: z.boolean().optional().describe("Fetch on-chain USDC balance per agent.")
505
+ },
506
+ async ({ withBalance }) => {
507
+ const devKey = getApiKey();
508
+ if (!devKey) {
509
+ return textResult("No developer key found. Run create_user or npx payagent init.");
510
+ }
511
+ try {
512
+ const result = await syncAgents({ includeBalance: withBalance === true });
513
+ if (!result.agents.length) {
514
+ return textResult("No x402 agents found. Use create_agent to provision one.");
515
+ }
516
+ const lines = result.agents.map((a) => {
517
+ const balanceLine = a.usdcBalance !== void 0 ? ` balance: ${formatUSDC(BigInt(a.usdcBalance || "0"))} USDC` : null;
518
+ return [
519
+ a.name,
520
+ ` agent id: ${a.agentId}`,
521
+ ` wallet: ${a.walletAddress}`,
522
+ ` network: ${a.network}`,
523
+ ` limits: ${a.limits.maxPerTx}\xA2 / tx, ${a.limits.maxDaily}\xA2 / day, ${a.limits.maxMonthly}\xA2 / month`,
524
+ ...balanceLine ? [balanceLine] : []
525
+ ].join("\n");
526
+ });
527
+ return textResult(lines.join("\n\n"));
528
+ } catch (err) {
529
+ return textResult(
530
+ `list_agents failed: ${err instanceof Error ? err.message : String(err)}`,
531
+ true
532
+ );
533
+ }
534
+ }
535
+ );
536
+ server.tool(
537
+ "rename_agent",
538
+ "Advanced: rename an x402 payer agent.",
539
+ {
540
+ name: z.string().describe("Current local name of the x402 agent."),
541
+ newName: z.string().describe("New name.")
542
+ },
543
+ async ({ name, newName }) => {
544
+ if (name === newName) {
545
+ return textResult(`Agent \`${name}\` already has that name.`);
546
+ }
547
+ const stored = getAgent(name);
548
+ if (!stored) {
549
+ return textResult(`No x402 agent named \`${name}\`.`, true);
550
+ }
551
+ try {
552
+ const devKey = requireDevKey();
553
+ const client = new DelegationClient(arispayUrl, devKey);
554
+ const result = await client.renameAgent(stored.agentId, newName);
555
+ renameStoredAgent(name, result.name);
556
+ return textResult(`\u2713 Renamed \`${name}\` \u2192 \`${result.name}\`.`);
557
+ } catch (err) {
558
+ return textResult(
559
+ `rename_agent failed: ${err instanceof Error ? err.message : String(err)}`,
271
560
  true
272
561
  );
273
562
  }
@@ -276,24 +565,22 @@ server.tool(
276
565
  if (platformToolsEnabled()) {
277
566
  server.tool(
278
567
  "create_enduser",
279
- "Platform mode: register an end-customer (EndUser) under your account, keyed by your own externalId.",
568
+ "Platform mode: register an end-customer under your account.",
280
569
  {
281
- externalId: z.string().describe("Your own stable id for this customer (e.g. `tg:12345`)."),
282
- email: z.string().optional().describe("Optional email for compliance / receipts."),
283
- findOrCreate: z.boolean().optional().describe("If true, return the existing user instead of erroring on externalId collision.")
570
+ externalId: z.string().describe("Your own stable id for this customer."),
571
+ email: z.string().optional(),
572
+ findOrCreate: z.boolean().optional()
284
573
  },
285
574
  async ({ externalId, email, findOrCreate }) => {
286
575
  try {
287
576
  const devKey = requireDevKey();
288
577
  const client = new DelegationClient(arispayUrl, devKey);
289
578
  const user = await client.createEndUser({ externalId, email, findOrCreate });
290
- const lines = [
291
- `\u2713 End-user \`${externalId}\` ready.`,
292
- ` ArisPay id: ${user.id}`,
293
- ` Has card: ${user.hasPaymentMethod ? "yes" : "no"}`,
294
- ` Has wallet: ${user.hasWallet ? "yes" : "no"}`
295
- ];
296
- return textResult(lines.join("\n"));
579
+ return textResult(
580
+ `\u2713 End-user \`${externalId}\` ready.
581
+ ArisPay id: ${user.id}
582
+ Has card: ${user.hasPaymentMethod ? "yes" : "no"}`
583
+ );
297
584
  } catch (err) {
298
585
  return textResult(
299
586
  `create_enduser failed: ${err instanceof Error ? err.message : String(err)}`,
@@ -304,10 +591,10 @@ if (platformToolsEnabled()) {
304
591
  );
305
592
  server.tool(
306
593
  "attach_card_for_user",
307
- "Platform mode: mint a hosted card-entry URL for an end-user (ArisPay handles tokenization + 3DS).",
594
+ "Platform mode: mint a hosted card-entry URL for an end-user.",
308
595
  {
309
- userId: z.string().describe("The ArisPay-internal end-user id (not externalId)."),
310
- agentName: z.string().optional().describe("Optional locally-stored agent name to scope the card-setup session to.")
596
+ userId: z.string().describe("ArisPay-internal end-user id."),
597
+ agentName: z.string().optional().describe("Optional x402 agent name to scope the session to.")
311
598
  },
312
599
  async ({ userId, agentName }) => {
313
600
  try {
@@ -315,17 +602,11 @@ if (platformToolsEnabled()) {
315
602
  const client = new DelegationClient(arispayUrl, devKey);
316
603
  const agentId = agentName ? getAgent(agentName)?.agentId : void 0;
317
604
  const session = await client.createCardSetupSession({ endUserId: userId, agentId });
318
- const lines = [
319
- `Card-entry URL for user \`${userId}\`:`,
320
- "",
321
- ` ${session.setupUrl}`,
322
- "",
323
- ` Expires at: ${session.expiresAt}`,
324
- "",
325
- "Share this URL with the end-user. They enter the card on ArisPay's hosted page; we handle tokenization + 3DS.",
326
- "Call `get_user_status` afterwards to confirm the card is attached."
327
- ];
328
- return textResult(lines.join("\n"));
605
+ return textResult(
606
+ [`Card-entry URL:`, ` ${session.setupUrl}`, ` Expires at: ${session.expiresAt}`].join(
607
+ "\n"
608
+ )
609
+ );
329
610
  } catch (err) {
330
611
  return textResult(
331
612
  `attach_card_for_user failed: ${err instanceof Error ? err.message : String(err)}`,
@@ -336,22 +617,20 @@ if (platformToolsEnabled()) {
336
617
  );
337
618
  server.tool(
338
619
  "set_user_limits",
339
- "Platform mode: set per-(user, agent) spend caps in integer cents plus MCC allow/block rules.",
620
+ "Platform mode: set per-(user, agent) spend caps.",
340
621
  {
341
- userId: z.string().describe("ArisPay-internal end-user id."),
342
- agentName: z.string().describe("Locally-stored agent name."),
343
- perTx: z.number().int().optional().describe("Per-transaction cap in cents. Omit to inherit agent defaults."),
344
- daily: z.number().int().optional().describe("Daily cap in cents."),
345
- monthly: z.number().int().optional().describe("Monthly cap in cents."),
346
- allowedMcc: z.array(z.string()).optional().describe("Allowed Merchant Category Codes."),
347
- blockedMcc: z.array(z.string()).optional().describe("Blocked MCCs.")
622
+ userId: z.string(),
623
+ agentName: z.string(),
624
+ perTx: z.number().int().optional(),
625
+ daily: z.number().int().optional(),
626
+ monthly: z.number().int().optional(),
627
+ allowedMcc: z.array(z.string()).optional(),
628
+ blockedMcc: z.array(z.string()).optional()
348
629
  },
349
630
  async ({ userId, agentName, perTx, daily, monthly, allowedMcc, blockedMcc }) => {
350
631
  try {
351
632
  const stored = getAgent(agentName);
352
- if (!stored) {
353
- return textResult(`No locally-stored agent named \`${agentName}\`.`, true);
354
- }
633
+ if (!stored) return textResult(`No x402 agent named \`${agentName}\`.`, true);
355
634
  const devKey = requireDevKey();
356
635
  const client = new DelegationClient(arispayUrl, devKey);
357
636
  const limit = await client.setUserLimits(userId, {
@@ -363,10 +642,7 @@ if (platformToolsEnabled()) {
363
642
  blockedMerchantCategories: blockedMcc
364
643
  });
365
644
  return textResult(
366
- [
367
- `\u2713 Limits set for \`${userId}\` on agent \`${agentName}\`.`,
368
- ` per-tx ${limit.maxPerTransaction ?? "inherit"}\xA2, daily ${limit.maxDaily ?? "inherit"}\xA2, monthly ${limit.maxMonthly ?? "inherit"}\xA2`
369
- ].join("\n")
645
+ `\u2713 Limits set. per-tx ${limit.maxPerTransaction ?? "inherit"}\xA2, daily ${limit.maxDaily ?? "inherit"}\xA2, monthly ${limit.maxMonthly ?? "inherit"}\xA2`
370
646
  );
371
647
  } catch (err) {
372
648
  return textResult(
@@ -378,9 +654,9 @@ if (platformToolsEnabled()) {
378
654
  );
379
655
  server.tool(
380
656
  "get_user_status",
381
- "Platform mode: report an end-user's card, wallet, and payment readiness.",
657
+ "Platform mode: report an end-user's card and wallet readiness.",
382
658
  {
383
- userId: z.string().describe("ArisPay-internal end-user id.")
659
+ userId: z.string()
384
660
  },
385
661
  async ({ userId }) => {
386
662
  try {
@@ -389,21 +665,9 @@ if (platformToolsEnabled()) {
389
665
  const user = await client.getEndUser(userId);
390
666
  const lines = [
391
667
  `${user.externalId} (${user.id})`,
392
- ` email: ${user.email ?? "\u2014"}`,
393
- ` card: ${user.hasPaymentMethod ? `${user.cardBrand ?? "card"} \u2026${user.cardLast4 ?? "????"}` : "\u2014"}`,
394
- ` wallet: ${user.walletAddress ?? "\u2014"}${user.walletChain ? ` on ${user.walletChain}` : ""}`
668
+ ` card: ${user.hasPaymentMethod ? `${user.cardBrand ?? "card"} \u2026${user.cardLast4 ?? "????"}` : "\u2014"}`,
669
+ ` wallet: ${user.walletAddress ?? "\u2014"}${user.walletChain ? ` on ${user.walletChain}` : ""}`
395
670
  ];
396
- if (user.hasWallet) {
397
- try {
398
- const w = await client.getWalletStatus(userId);
399
- lines.push(` balance: ${w.usdcBalance} USDC base units`);
400
- lines.push(
401
- ` allowance: ${w.usdcAllowance} (${w.allowanceSufficient ? "ok" : "insufficient"})`
402
- );
403
- lines.push(` ready: ${w.ready}`);
404
- } catch {
405
- }
406
- }
407
671
  return textResult(lines.join("\n"));
408
672
  } catch (err) {
409
673
  return textResult(
@@ -413,231 +677,32 @@ if (platformToolsEnabled()) {
413
677
  }
414
678
  }
415
679
  );
416
- server.tool(
417
- "pay_merchant",
418
- "Direct payment to a known merchant via ArisPay rails (card / crypto / balance / MPP) when you already know the amount. For x402-protected HTTP resources use `pay_api` instead.",
419
- {
420
- agentName: z.string().describe("Name of the locally-stored agent making the payment."),
421
- merchantUrl: z.string().describe("Canonical merchant URL (stored on the payment record)."),
422
- amount: z.number().int().positive().describe("Amount in cents."),
423
- memo: z.string().describe("Human-readable memo attached to the payment."),
424
- userId: z.string().optional().describe("Optional ArisPay end-user id. Required when the agent is in platform mode."),
425
- rail: z.enum(["card", "crypto", "balance", "mpp"]).optional().describe("Force a specific rail. Default: server-picked based on agent mode + userId."),
426
- merchantName: z.string().optional().describe("Optional human-readable merchant name."),
427
- merchantCategoryCode: z.string().optional().describe("MCC for spend-limit enforcement.")
428
- },
429
- async ({
430
- agentName,
431
- merchantUrl,
432
- amount,
433
- memo,
434
- userId,
435
- rail,
436
- merchantName,
437
- merchantCategoryCode
438
- }) => {
439
- try {
440
- const stored = getAgent(agentName);
441
- if (!stored) {
442
- return textResult(`No locally-stored agent named \`${agentName}\`.`, true);
443
- }
444
- const devKey = requireDevKey();
445
- const client = new DelegationClient(arispayUrl, devKey);
446
- const payment = await client.createPayment(stored.agentId, {
447
- amount,
448
- memo,
449
- merchantUrl,
450
- merchantName,
451
- merchantCategoryCode,
452
- userId,
453
- rail
454
- });
455
- const lines = [
456
- `Payment ${payment.id}: ${payment.status}`,
457
- ` rail: ${payment.rail}`,
458
- ` amount: ${payment.amount}\xA2 ${payment.currency}`
459
- ];
460
- if (payment.merchantName) lines.push(` merchant: ${payment.merchantName}`);
461
- if (payment.txHash) lines.push(` tx hash: ${payment.txHash}`);
462
- if (payment.spend) {
463
- const fmtCap = (v) => v == null ? "no cap" : `${v}\xA2`;
464
- lines.push(
465
- ` budget: ${fmtCap(payment.spend.remainingDaily)} left today, ${fmtCap(payment.spend.remainingMonthly)} this month`
466
- );
467
- }
468
- if (payment.nextAction) {
469
- lines.push(` next action: ${payment.nextAction.type}`);
470
- if (payment.nextAction.challengeUrl) {
471
- lines.push(` 3DS challenge URL: ${payment.nextAction.challengeUrl}`);
472
- }
473
- }
474
- if (payment.error) {
475
- lines.push(` error: ${payment.error.code} \u2014 ${payment.error.message}`);
476
- }
477
- return textResult(lines.join("\n"), payment.status === "failed");
478
- } catch (err) {
479
- return textResult(
480
- `pay_merchant failed: ${err instanceof Error ? err.message : String(err)}`,
481
- true
482
- );
483
- }
484
- }
485
- );
486
680
  }
487
681
  server.tool(
488
- "bootstrap_agent",
489
- "Cold-start in one call: create (or recover) an ArisPay account plus a payment agent from just an email. Run this first on a fresh machine; safe to re-run \u2014 it recovers the existing agent and wallet set instead of creating duplicates.",
490
- {
491
- email: z.string().describe("Email for the new ArisPay developer account."),
492
- name: z.string().optional().describe("Human name. Falls back to the email local-part."),
493
- orgName: z.string().optional().describe(`Workspace / org name. Falls back to "<name>'s Team".`),
494
- agentName: z.string().optional().describe('Local name for the provisioned agent. Default: "default".'),
495
- perTx: z.number().int().positive().optional().describe("Per-tx cap in cents. Default: 50."),
496
- daily: z.number().int().positive().optional().describe("Daily cap in cents. Default: 1000."),
497
- monthly: z.number().int().positive().optional().describe("Monthly cap in cents. Default: 10000."),
498
- allowedDomains: z.array(z.string()).optional().describe("Domains the agent may pay. Empty = unrestricted.")
499
- },
500
- async ({ email, name, orgName, agentName, perTx, daily, monthly, allowedDomains }) => {
501
- try {
502
- const result = await bootstrapAgent({
503
- email,
504
- name,
505
- orgName,
506
- agentName,
507
- limits: { perTx, daily, monthly },
508
- allowedDomains,
509
- arispayUrl: process.env.ARISPAY_URL,
510
- clientId: "payagent-mcp-bootstrap"
511
- });
512
- const lines = [
513
- `\u2713 Account: ${result.email} (org \`${result.orgName}\`)`,
514
- `\u2713 Agent: ${result.agentName} (${result.agentId})`,
515
- ` Wallet: ${result.walletAddress} (${result.network})`,
516
- ` Limits: ${result.limits.perTx}\xA2 / tx, ${result.limits.daily}\xA2 / day, ${result.limits.monthly}\xA2 / month`,
517
- "",
518
- `Fund the wallet by sending USDC on ${result.network} to ${result.walletAddress}.`,
519
- `Or call \`fund_agent\` with name="${result.agentName}" and rail="usdc" or rail="europ".`
520
- ];
521
- if (result.pairing) {
522
- lines.push("");
523
- lines.push("\u{1F4F1} Open BuyForMe on your phone (signs you into the same account):");
524
- lines.push(` ${result.pairing.url}`);
525
- lines.push(` Link expires: ${result.pairing.expiresAt}`);
526
- }
527
- return textResult(lines.join("\n"));
528
- } catch (err) {
529
- if (err instanceof BootstrapError) {
530
- return textResult(`bootstrap_agent failed (${err.code}): ${err.message}`, true);
531
- }
532
- return textResult(
533
- `bootstrap_agent failed: ${err instanceof Error ? err.message : String(err)}`,
534
- true
535
- );
536
- }
537
- }
538
- );
539
- server.tool(
540
- "list_agents",
541
- "List all wallets under this account (server-authoritative; rehydrates the local cache).",
682
+ "check_wallet",
683
+ "Legacy diagnostic for x402 payer agents. Use get_balance for wallet-centric balances.",
542
684
  {
543
- withBalance: z.boolean().optional().describe(
544
- "When true, fetch on-chain USDC balance per agent (adds one round-trip per wallet)."
545
- )
685
+ agent: z.string().optional().describe("Optional name of a locally-stored x402 agent.")
546
686
  },
547
- async ({ withBalance }) => {
548
- const devKey = getApiKey();
549
- if (!devKey) {
550
- const local = listAgents();
551
- if (!local.length) {
552
- return textResult(
553
- "No developer key set and no agents cached locally. Run `bootstrap_agent` or set ARISPAY_API_KEY."
554
- );
555
- }
556
- const lines = local.map(
557
- (a) => [
558
- a.name,
559
- ` agent id: ${a.agentId}`,
560
- ` wallet: ${a.walletAddress}`,
561
- ` network: ${a.network ?? "base"}`,
562
- ` limits: ${a.limits.perTx}\xA2 / tx, ${a.limits.daily}\xA2 / day, ${a.limits.monthly}\xA2 / month`,
563
- ` created: ${a.createdAt}`,
564
- " (local cache only \u2014 set ARISPAY_API_KEY to sync from the server)"
565
- ].join("\n")
566
- );
567
- return textResult(lines.join("\n\n"));
568
- }
569
- try {
570
- const result = await syncAgents({ includeBalance: withBalance === true });
571
- if (!result.agents.length) {
572
- return textResult(
573
- "No wallets found under this developer key. Create one with `create_agent` or `bootstrap_agent`."
574
- );
687
+ async ({ agent }) => {
688
+ const stored = agent ? getAgent(agent) : listAgents()[0];
689
+ const walletAddress = stored?.walletAddress ?? legacyWalletAddress;
690
+ const keyTail = stored?.apiKey.slice(-4) ?? (legacyAgentKey ? legacyAgentKey.slice(-4) : void 0);
691
+ const lines = [`ArisPay URL: ${arispayUrl}`];
692
+ if (stored) lines.push(`Agent: ${stored.name} (${stored.agentId})`);
693
+ if (keyTail) lines.push(`Agent key: ap_\u2026${keyTail}`);
694
+ if (walletAddress) {
695
+ lines.push(`Wallet: ${walletAddress}`);
696
+ try {
697
+ const raw = await getUSDCBalance(walletAddress, stored?.network ?? "base");
698
+ lines.push(`Balance: ${formatUSDC(raw)} USDC on ${stored?.network ?? "base"}`);
699
+ } catch (err) {
700
+ lines.push(`Balance: unavailable (${err instanceof Error ? err.message : String(err)})`);
575
701
  }
576
- const lines = result.agents.map((a) => {
577
- const balanceLine = a.usdcBalance !== void 0 ? ` balance: ${formatUSDC(BigInt(a.usdcBalance || "0"))} USDC` : null;
578
- const fundedLine = a.fundedAt ? ` funded: ${a.fundedAt}` : " funded: not yet";
579
- const domainsLine = a.allowedDomains.length ? ` domains: ${a.allowedDomains.join(", ")}` : " domains: (unrestricted)";
580
- const suspendedLine = a.suspended ? " status: SUSPENDED" : null;
581
- return [
582
- a.name,
583
- ` agent id: ${a.agentId}`,
584
- ` wallet: ${a.walletAddress}`,
585
- ` network: ${a.network}`,
586
- ` limits: ${a.limits.maxPerTx}\xA2 / tx, ${a.limits.maxDaily}\xA2 / day, ${a.limits.maxMonthly}\xA2 / month`,
587
- domainsLine,
588
- fundedLine,
589
- ...balanceLine ? [balanceLine] : [],
590
- ...suspendedLine ? [suspendedLine] : [],
591
- ` created: ${a.createdAt}`
592
- ].join("\n");
593
- });
594
- return textResult(
595
- `${result.agents.length} wallet${result.agents.length === 1 ? "" : "s"} under this account (synced from server):
596
-
597
- ${lines.join("\n\n")}`
598
- );
599
- } catch (err) {
600
- return textResult(
601
- `list_agents failed: ${err instanceof Error ? err.message : String(err)}`,
602
- true
603
- );
604
- }
605
- }
606
- );
607
- server.tool(
608
- "rename_agent",
609
- "Rename an agent on the server and in the local cache (names are unique per account).",
610
- {
611
- name: z.string().describe("Current local name of the agent to rename."),
612
- newName: z.string().describe(
613
- "New name. Letters, numbers, spaces, hyphens, underscores, dots. 1-64 chars. Must be unique per account."
614
- )
615
- },
616
- async ({ name, newName }) => {
617
- if (name === newName) {
618
- return textResult(`Agent \`${name}\` already has that name \u2014 nothing to do.`);
619
- }
620
- const stored = getAgent(name);
621
- if (!stored) {
622
- return textResult(
623
- `No locally-cached agent named \`${name}\`. Run \`list_agents\` first to sync, or check the spelling.`,
624
- true
625
- );
626
- }
627
- try {
628
- const devKey = requireDevKey();
629
- const client = new DelegationClient(arispayUrl, devKey);
630
- const result = await client.renameAgent(stored.agentId, newName);
631
- renameStoredAgent(name, result.name);
632
- return textResult(
633
- `\u2713 Renamed \`${name}\` \u2192 \`${result.name}\`. Wallet ${result.walletAddress ?? stored.walletAddress} is unchanged.`
634
- );
635
- } catch (err) {
636
- return textResult(
637
- `rename_agent failed: ${err instanceof Error ? err.message : String(err)}`,
638
- true
639
- );
702
+ } else {
703
+ lines.push("", "No wallet known.");
640
704
  }
705
+ return textResult(lines.join("\n"));
641
706
  }
642
707
  );
643
708
  async function main() {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/pay-api-helpers.ts","../src/profile.ts"],"sourcesContent":["/**\n * payagent-mcp — MCP server for agent-side x402 payments + headless launch.\n *\n * Thirteen tools over stdio. Core (the 80% path):\n * - bootstrap_agent(...) — cold-start: sign up + provision an agent in one call\n * - pay_api(url, ...) — paid HTTP request via delegated signing\n * - check_wallet() — report current agent credentials + on-chain balance\n *\n * Wallet management:\n * - create_agent(...) — provision a new x402 agent (calls /v1/agents/x402)\n * - fund_agent({ name, rail }) — USDC deposit address, or EURØP browser handoff\n * - get_balance({ name }) — on-server USDC balance + fundedAt latch\n * - list_agents() — server-authoritative wallet enumeration\n * - rename_agent(...) — server-side rename + local cache mirror\n *\n * Platform (end-user) tools:\n * - create_enduser(...) — find-or-create an EndUser by externalId\n * - attach_card_for_user(...)— mint a hosted card-setup session URL\n * - set_user_limits(...) — per-(user, agent) spend caps + MCC rules\n * - get_user_status(...) — card / wallet / readiness report\n * - pay_merchant(...) — direct payment via POST /v1/payments\n *\n * Config store lives at ~/.payagent/config.json (shared with the `payagent`\n * CLI). Credentials created via `npx payagent init` + `payagent agent create`\n * are immediately available here; equally, agents created via\n * `create_agent` are immediately visible to the CLI.\n *\n * Two auth modes, picked at request time:\n * 1. Legacy single-agent: ARISPAY_AGENT_KEY set → pay_api + check_wallet use it directly.\n * 2. Multi-agent: no env var, credentials come from the shared config store.\n * Management tools (create / fund / get_balance / list) always use the\n * developer key from the config store (or ARISPAY_API_KEY env).\n */\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n BootstrapError,\n type DelegatedPaymentInfo,\n DelegationClient,\n type StoredAgent,\n bootstrapAgent,\n formatUSDC,\n getAgent,\n getApiKey,\n getArispayUrl,\n getUSDCBalance,\n launchAgent,\n listAgents,\n payFetchDelegated,\n renameStoredAgent,\n syncAgents,\n} from \"payagent\";\nimport { z } from \"zod\";\nimport { looksLikeInsufficientFunds } from \"./pay-api-helpers.js\";\nimport { platformToolsEnabled } from \"./profile.js\";\n\n// ── Configuration ─────────────────────────────────────\n\nconst arispayUrl = getArispayUrl(process.env.ARISPAY_URL);\n/** Legacy single-agent key (kept for backwards compatibility). */\nconst legacyAgentKey = process.env.ARISPAY_AGENT_KEY;\nconst legacyWalletAddress = process.env.PAYAGENT_WALLET;\n\nfunction resolveAgent(name?: string): StoredAgent | undefined {\n if (name) return getAgent(name);\n const agents = listAgents();\n return agents[0];\n}\n\n/**\n * Look up the agent-scoped key to use for paid requests.\n * Priority: explicit agent name → legacy env var → first stored agent.\n */\nfunction resolveAgentKey(name?: string): { key: string; source: string } | undefined {\n if (name) {\n const stored = getAgent(name);\n if (stored) return { key: stored.apiKey, source: `agent \\`${name}\\`` };\n return undefined;\n }\n if (legacyAgentKey) return { key: legacyAgentKey, source: \"ARISPAY_AGENT_KEY\" };\n const first = listAgents()[0];\n if (first) return { key: first.apiKey, source: `agent \\`${first.name}\\`` };\n return undefined;\n}\n\nfunction requireDevKey(): string {\n const key = getApiKey();\n if (!key) {\n throw new Error(\n \"No ArisPay developer key found. Run `npx payagent init` or set ARISPAY_API_KEY.\",\n );\n }\n return key;\n}\n\nfunction textResult(text: string, isError = false) {\n return {\n content: [{ type: \"text\" as const, text }],\n ...(isError ? { isError } : {}),\n };\n}\n\n// ── MCP Server ────────────────────────────────────────\n\nconst server = new McpServer({\n name: \"payagent\",\n version: \"2.1.0\",\n});\n\n// --- pay_api ----------------------------------------------------------------\n\nserver.tool(\n \"pay_api\",\n \"Make an HTTP request to a paid API, transparently paying any x402 (HTTP 402) challenge with USDC under the agent's spend limits. THE tool for fetching paid resources — never bypass a 402 or hand-roll payment.\",\n {\n url: z.string().describe(\"The full URL of the API endpoint to call\"),\n method: z\n .enum([\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"])\n .default(\"GET\")\n .describe(\"HTTP method\"),\n headers: z.record(z.string(), z.string()).optional().describe(\"Additional HTTP headers\"),\n body: z.string().optional().describe(\"Request body (for POST/PUT/PATCH)\"),\n agent: z\n .string()\n .optional()\n .describe(\n \"Optional: name of a locally-stored agent to pay with. Defaults to ARISPAY_AGENT_KEY or the first stored agent.\",\n ),\n },\n async ({ url, method, headers, body, agent }) => {\n const resolved = resolveAgentKey(agent);\n if (!resolved) {\n return textResult(\n [\n \"No agent available. Cold-start in one call:\",\n ' bootstrap_agent({ email: \"you@example.com\", name: \"<your-name>\" })',\n \"\",\n \"Or, if a developer key is already paired (`npx payagent init`):\",\n \" create_agent({ name, perTx, daily, monthly })\",\n \"\",\n \"Or set ARISPAY_AGENT_KEY for legacy single-agent mode.\",\n ].join(\"\\n\"),\n true,\n );\n }\n try {\n // Budget headroom rides the delegated-sign response — capture it so the\n // host learns its remaining budget without a second tool call.\n let paymentInfo: DelegatedPaymentInfo | undefined;\n const fetch402 = payFetchDelegated({\n arispayUrl,\n apiKey: resolved.key,\n onPayment: (info) => {\n paymentInfo = info;\n },\n });\n const response = await fetch402(url, { method, headers, body });\n const responseBody = await response.text();\n const statusLine = paymentInfo\n ? `HTTP ${response.status} (paid ${paymentInfo.amountCents}¢ via ${resolved.source} — budget left: ${paymentInfo.remainingDaily}¢ today, ${paymentInfo.remainingMonthly}¢ this month)`\n : `HTTP ${response.status} (paid via ${resolved.source})`;\n return textResult([statusLine, \"\", responseBody].join(\"\\n\"));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // Detect \"agent wallet has no USDC\" — point the host at fund_agent\n // so it can choose the USDC deposit address or the EURØP handoff.\n if (looksLikeInsufficientFunds(message)) {\n return textResult(\n [\n `Error: ${message}`,\n \"\",\n \"This looks like the agent wallet is out of USDC. Fund it and retry:\",\n \" Use the `fund_agent` tool (rail='usdc' for the wallet address,\",\n \" or rail='europ' to fund via SEPA/EURØP in the browser).\",\n ].join(\"\\n\"),\n true,\n );\n }\n return textResult(`Error: ${message}`, true);\n }\n },\n);\n\n// --- check_wallet ----------------------------------------------------------\n\nserver.tool(\n \"check_wallet\",\n 'Show the current agent\\'s credentials, wallet address, and on-chain USDC balance — the quick \"what state am I in\" probe.',\n {\n agent: z\n .string()\n .optional()\n .describe(\n \"Optional: name of a locally-stored agent. Defaults to legacy ARISPAY_WALLET mode.\",\n ),\n },\n async ({ agent }) => {\n const resolved = resolveAgent(agent);\n const walletAddress = resolved?.walletAddress ?? legacyWalletAddress;\n const keyTail =\n resolved?.apiKey.slice(-4) ?? (legacyAgentKey ? legacyAgentKey.slice(-4) : undefined);\n\n const lines = [`ArisPay URL: ${arispayUrl}`];\n if (resolved) lines.push(`Agent: ${resolved.name} (${resolved.agentId})`);\n if (keyTail) lines.push(`Agent key: ap_…${keyTail}`);\n\n if (walletAddress) {\n lines.push(`Wallet: ${walletAddress}`);\n try {\n const raw = await getUSDCBalance(walletAddress, (resolved?.network as \"base\") ?? \"base\");\n lines.push(`Balance: ${formatUSDC(raw)} USDC on ${resolved?.network ?? \"base\"}`);\n } catch (err) {\n lines.push(\n `Balance: unavailable (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n } else {\n lines.push(\"\", \"No wallet known. Use `create_agent` or set PAYAGENT_WALLET for legacy mode.\");\n }\n\n lines.push(\"\", \"Manage limits + full history: https://arispay.app/dashboard\");\n return textResult(lines.join(\"\\n\"));\n },\n);\n\n// --- create_agent ----------------------------------------------------------\n\nserver.tool(\n \"create_agent\",\n \"Provision an additional x402 payment agent (wallet + spend limits) under the already-paired developer account.\",\n {\n name: z.string().describe(\"Local identifier for this agent. Used by later tools.\"),\n perTx: z.number().int().positive().describe(\"Per-transaction spend cap in cents.\"),\n daily: z.number().int().positive().describe(\"Daily spend cap in cents.\"),\n monthly: z.number().int().positive().describe(\"Monthly spend cap in cents.\"),\n allowedDomains: z\n .array(z.string())\n .optional()\n .describe(\"If provided, restrict this agent to paying only these domains.\"),\n network: z\n .enum([\"base\", \"base-sepolia\", \"ethereum\", \"polygon\"])\n .default(\"base\")\n .describe(\"EVM network the agent pays on.\"),\n agentType: z.string().optional().describe('Optional metadata label (e.g. \"hermes\").'),\n },\n async ({ name, perTx, daily, monthly, allowedDomains, network, agentType }) => {\n try {\n requireDevKey(); // fail fast with a helpful message if not signed in\n const agent = await launchAgent({\n name,\n limits: { perTx, daily, monthly },\n allowedDomains,\n network,\n agentType,\n });\n const lines = [\n `✓ Agent \\`${name}\\` created.`,\n ` Agent ID: ${agent.agentId}`,\n ` Wallet: ${agent.walletAddress}`,\n ` Network: ${agent.network}`,\n ` Limits: ${perTx}¢ / tx, ${daily}¢ / day, ${monthly}¢ / month`,\n \"\",\n ` Fund the wallet with USDC on ${agent.network}, then call \\`get_balance\\` with name=\"${name}\".`,\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `create_agent failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- fund_agent ------------------------------------------------------------\n\n/** Browser handoff host for EURØP / Schuman KYC. */\nconst buyformeUrl =\n process.env.BUYFORME_URL?.replace(/\\/$/, \"\") ?? \"https://buyforme.arispay.app\";\n\nserver.tool(\n \"fund_agent\",\n \"Get funding instructions for an agent's wallet. Use rail='usdc' for the direct USDC deposit address on Base, or rail='europ' for a browser handoff to complete Schuman identity verification and receive a SEPA vIBAN that credits EURØP.\",\n {\n name: z.string().describe(\"Name of a locally-stored agent.\"),\n rail: z\n .enum([\"usdc\", \"europ\"])\n .default(\"usdc\")\n .describe(\n \"Funding rail: 'usdc' sends stablecoin directly to the agent wallet; 'europ' opens the BuyForMe EURØP onboarding flow in a browser to verify identity and get a vIBAN.\",\n ),\n },\n async ({ name, rail }) => {\n const stored = getAgent(name);\n if (!stored) return textResult(`No locally-stored agent named \\`${name}\\`.`, true);\n\n if (rail === \"europ\") {\n const handoffUrl = `${buyformeUrl}/onboarding/fund-europ?agentId=${encodeURIComponent(\n stored.agentId,\n )}`;\n const lines = [\n `Fund \\`${name}\\` with EURØP via Schuman:`,\n \"\",\n ` ${handoffUrl}`,\n \"\",\n \"Open that link in a browser to:\",\n \" 1. Verify your identity with Schuman Financial (one-time KYC).\",\n \" 2. Receive a dedicated SEPA vIBAN.\",\n \" 3. Send EUR by bank transfer; Schuman mints EURØP to your wallet once it clears.\",\n \"\",\n \"After the deposit clears, call `get_balance` to confirm the agent's USDC balance.\",\n ];\n return textResult(lines.join(\"\\n\"));\n }\n\n const lines = [\n `Fund \\`${name}\\` by sending USDC on ${stored.network ?? \"base\"} to:`,\n \"\",\n ` ${stored.walletAddress}`,\n \"\",\n \"Only send USDC on the network shown above. Other tokens or networks may be lost.\",\n \"Call `get_balance` when the deposit lands.\",\n ];\n return textResult(lines.join(\"\\n\"));\n },\n);\n\n// --- get_balance -----------------------------------------------------------\n\nserver.tool(\n \"get_balance\",\n \"Server-side USDC balance + funding status for one named agent.\",\n {\n name: z.string().describe(\"Name of a locally-stored agent.\"),\n },\n async ({ name }) => {\n const stored = getAgent(name);\n if (!stored) return textResult(`No locally-stored agent named \\`${name}\\`.`, true);\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const balance = await client.getBalance(stored.agentId);\n const human = formatUSDC(BigInt(balance.usdcBalance || \"0\"));\n const lines = [\n `${name}: ${human} USDC on ${balance.network}`,\n balance.fundedAt ? ` First funded at: ${balance.fundedAt}` : \" Not yet funded.\",\n ` Wallet: ${balance.walletAddress}`,\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `get_balance failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- Platform (end-user) tools ----------------------------------------------\n//\n// Skipped under PAYAGENT_MCP_PROFILE=core so pay-URL-only hosts load 8 tool\n// schemas instead of 13 (see src/profile.ts).\nif (platformToolsEnabled()) {\n // --- create_enduser --------------------------------------------------------\n\n server.tool(\n \"create_enduser\",\n \"Platform mode: register an end-customer (EndUser) under your account, keyed by your own externalId.\",\n {\n externalId: z.string().describe(\"Your own stable id for this customer (e.g. `tg:12345`).\"),\n email: z.string().optional().describe(\"Optional email for compliance / receipts.\"),\n findOrCreate: z\n .boolean()\n .optional()\n .describe(\"If true, return the existing user instead of erroring on externalId collision.\"),\n },\n async ({ externalId, email, findOrCreate }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const user = await client.createEndUser({ externalId, email, findOrCreate });\n const lines = [\n `✓ End-user \\`${externalId}\\` ready.`,\n ` ArisPay id: ${user.id}`,\n ` Has card: ${user.hasPaymentMethod ? \"yes\" : \"no\"}`,\n ` Has wallet: ${user.hasWallet ? \"yes\" : \"no\"}`,\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `create_enduser failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n\n // --- attach_card_for_user -------------------------------------------------\n\n server.tool(\n \"attach_card_for_user\",\n \"Platform mode: mint a hosted card-entry URL for an end-user (ArisPay handles tokenization + 3DS).\",\n {\n userId: z.string().describe(\"The ArisPay-internal end-user id (not externalId).\"),\n agentName: z\n .string()\n .optional()\n .describe(\"Optional locally-stored agent name to scope the card-setup session to.\"),\n },\n async ({ userId, agentName }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const agentId = agentName ? getAgent(agentName)?.agentId : undefined;\n const session = await client.createCardSetupSession({ endUserId: userId, agentId });\n const lines = [\n `Card-entry URL for user \\`${userId}\\`:`,\n \"\",\n ` ${session.setupUrl}`,\n \"\",\n ` Expires at: ${session.expiresAt}`,\n \"\",\n \"Share this URL with the end-user. They enter the card on ArisPay's hosted page; we handle tokenization + 3DS.\",\n \"Call `get_user_status` afterwards to confirm the card is attached.\",\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `attach_card_for_user failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n\n // --- set_user_limits -------------------------------------------------------\n\n server.tool(\n \"set_user_limits\",\n \"Platform mode: set per-(user, agent) spend caps in integer cents plus MCC allow/block rules.\",\n {\n userId: z.string().describe(\"ArisPay-internal end-user id.\"),\n agentName: z.string().describe(\"Locally-stored agent name.\"),\n perTx: z\n .number()\n .int()\n .optional()\n .describe(\"Per-transaction cap in cents. Omit to inherit agent defaults.\"),\n daily: z.number().int().optional().describe(\"Daily cap in cents.\"),\n monthly: z.number().int().optional().describe(\"Monthly cap in cents.\"),\n allowedMcc: z.array(z.string()).optional().describe(\"Allowed Merchant Category Codes.\"),\n blockedMcc: z.array(z.string()).optional().describe(\"Blocked MCCs.\"),\n },\n async ({ userId, agentName, perTx, daily, monthly, allowedMcc, blockedMcc }) => {\n try {\n const stored = getAgent(agentName);\n if (!stored) {\n return textResult(`No locally-stored agent named \\`${agentName}\\`.`, true);\n }\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const limit = await client.setUserLimits(userId, {\n agentId: stored.agentId,\n maxPerTransaction: perTx ?? null,\n maxDaily: daily ?? null,\n maxMonthly: monthly ?? null,\n allowedMerchantCategories: allowedMcc,\n blockedMerchantCategories: blockedMcc,\n });\n return textResult(\n [\n `✓ Limits set for \\`${userId}\\` on agent \\`${agentName}\\`.`,\n ` per-tx ${limit.maxPerTransaction ?? \"inherit\"}¢, daily ${limit.maxDaily ?? \"inherit\"}¢, monthly ${limit.maxMonthly ?? \"inherit\"}¢`,\n ].join(\"\\n\"),\n );\n } catch (err) {\n return textResult(\n `set_user_limits failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n\n // --- get_user_status -------------------------------------------------------\n\n server.tool(\n \"get_user_status\",\n \"Platform mode: report an end-user's card, wallet, and payment readiness.\",\n {\n userId: z.string().describe(\"ArisPay-internal end-user id.\"),\n },\n async ({ userId }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const user = await client.getEndUser(userId);\n const lines = [\n `${user.externalId} (${user.id})`,\n ` email: ${user.email ?? \"—\"}`,\n ` card: ${user.hasPaymentMethod ? `${user.cardBrand ?? \"card\"} …${user.cardLast4 ?? \"????\"}` : \"—\"}`,\n ` wallet: ${user.walletAddress ?? \"—\"}${user.walletChain ? ` on ${user.walletChain}` : \"\"}`,\n ];\n if (user.hasWallet) {\n try {\n const w = await client.getWalletStatus(userId);\n lines.push(` balance: ${w.usdcBalance} USDC base units`);\n lines.push(\n ` allowance: ${w.usdcAllowance} (${w.allowanceSufficient ? \"ok\" : \"insufficient\"})`,\n );\n lines.push(` ready: ${w.ready}`);\n } catch {\n // getWalletStatus fails if wallet not configured — ignore.\n }\n }\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `get_user_status failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n\n // --- pay_merchant ----------------------------------------------------------\n\n server.tool(\n \"pay_merchant\",\n \"Direct payment to a known merchant via ArisPay rails (card / crypto / balance / MPP) when you already know the amount. For x402-protected HTTP resources use `pay_api` instead.\",\n {\n agentName: z.string().describe(\"Name of the locally-stored agent making the payment.\"),\n merchantUrl: z.string().describe(\"Canonical merchant URL (stored on the payment record).\"),\n amount: z.number().int().positive().describe(\"Amount in cents.\"),\n memo: z.string().describe(\"Human-readable memo attached to the payment.\"),\n userId: z\n .string()\n .optional()\n .describe(\"Optional ArisPay end-user id. Required when the agent is in platform mode.\"),\n rail: z\n .enum([\"card\", \"crypto\", \"balance\", \"mpp\"])\n .optional()\n .describe(\"Force a specific rail. Default: server-picked based on agent mode + userId.\"),\n merchantName: z.string().optional().describe(\"Optional human-readable merchant name.\"),\n merchantCategoryCode: z.string().optional().describe(\"MCC for spend-limit enforcement.\"),\n },\n async ({\n agentName,\n merchantUrl,\n amount,\n memo,\n userId,\n rail,\n merchantName,\n merchantCategoryCode,\n }) => {\n try {\n const stored = getAgent(agentName);\n if (!stored) {\n return textResult(`No locally-stored agent named \\`${agentName}\\`.`, true);\n }\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const payment = await client.createPayment(stored.agentId, {\n amount,\n memo,\n merchantUrl,\n merchantName,\n merchantCategoryCode,\n userId,\n rail,\n });\n const lines = [\n `Payment ${payment.id}: ${payment.status}`,\n ` rail: ${payment.rail}`,\n ` amount: ${payment.amount}¢ ${payment.currency}`,\n ];\n if (payment.merchantName) lines.push(` merchant: ${payment.merchantName}`);\n if (payment.txHash) lines.push(` tx hash: ${payment.txHash}`);\n if (payment.spend) {\n const fmtCap = (v: number | null) => (v == null ? \"no cap\" : `${v}¢`);\n lines.push(\n ` budget: ${fmtCap(payment.spend.remainingDaily)} left today, ${fmtCap(payment.spend.remainingMonthly)} this month`,\n );\n }\n if (payment.nextAction) {\n lines.push(` next action: ${payment.nextAction.type}`);\n if (payment.nextAction.challengeUrl) {\n lines.push(` 3DS challenge URL: ${payment.nextAction.challengeUrl}`);\n }\n }\n if (payment.error) {\n lines.push(` error: ${payment.error.code} — ${payment.error.message}`);\n }\n return textResult(lines.join(\"\\n\"), payment.status === \"failed\");\n } catch (err) {\n return textResult(\n `pay_merchant failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n}\n\n// --- bootstrap_agent -------------------------------------------------------\n//\n// Cold-start primitive: signs up a developer + provisions an agent in one\n// MCP tool call, no `payagent init` required first. Backed by\n// `POST /v1/bootstrap` on the API. Persists results to the same\n// ~/.payagent/config.json the CLI uses, so afterwards every other tool\n// (`pay_api`, `check_wallet`, `get_balance`, `fund_agent`) just works.\n\nserver.tool(\n \"bootstrap_agent\",\n \"Cold-start in one call: create (or recover) an ArisPay account plus a payment agent from just an email. Run this first on a fresh machine; safe to re-run — it recovers the existing agent and wallet set instead of creating duplicates.\",\n {\n email: z.string().describe(\"Email for the new ArisPay developer account.\"),\n name: z.string().optional().describe(\"Human name. Falls back to the email local-part.\"),\n orgName: z\n .string()\n .optional()\n .describe('Workspace / org name. Falls back to \"<name>\\'s Team\".'),\n agentName: z\n .string()\n .optional()\n .describe('Local name for the provisioned agent. Default: \"default\".'),\n perTx: z.number().int().positive().optional().describe(\"Per-tx cap in cents. Default: 50.\"),\n daily: z.number().int().positive().optional().describe(\"Daily cap in cents. Default: 1000.\"),\n monthly: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Monthly cap in cents. Default: 10000.\"),\n allowedDomains: z\n .array(z.string())\n .optional()\n .describe(\"Domains the agent may pay. Empty = unrestricted.\"),\n },\n async ({ email, name, orgName, agentName, perTx, daily, monthly, allowedDomains }) => {\n try {\n const result = await bootstrapAgent({\n email,\n name,\n orgName,\n agentName,\n limits: { perTx, daily, monthly },\n allowedDomains,\n arispayUrl: process.env.ARISPAY_URL,\n clientId: \"payagent-mcp-bootstrap\",\n });\n const lines = [\n `✓ Account: ${result.email} (org \\`${result.orgName}\\`)`,\n `✓ Agent: ${result.agentName} (${result.agentId})`,\n ` Wallet: ${result.walletAddress} (${result.network})`,\n ` Limits: ${result.limits.perTx}¢ / tx, ${result.limits.daily}¢ / day, ${result.limits.monthly}¢ / month`,\n \"\",\n `Fund the wallet by sending USDC on ${result.network} to ${result.walletAddress}.`,\n `Or call \\`fund_agent\\` with name=\"${result.agentName}\" and rail=\"usdc\" or rail=\"europ\".`,\n ];\n // BuyForMe phone-pairing handoff. Surface the URL prominently so\n // the user (or the AI host) can choose to open it directly or\n // pass it along to the human-on-the-phone.\n if (result.pairing) {\n lines.push(\"\");\n lines.push(\"📱 Open BuyForMe on your phone (signs you into the same account):\");\n lines.push(` ${result.pairing.url}`);\n lines.push(` Link expires: ${result.pairing.expiresAt}`);\n }\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n if (err instanceof BootstrapError) {\n return textResult(`bootstrap_agent failed (${err.code}): ${err.message}`, true);\n }\n return textResult(\n `bootstrap_agent failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- list_agents -----------------------------------------------------------\n//\n// Server-authoritative. Hits `GET /v1/agents?withDelegation=1` and (when\n// `withBalance: true`) fans out per-agent balance checks. The local\n// `~/.payagent/config.json` is rehydrated as a side-effect so a subsequent\n// pay_api / fund_agent call sees the same wallet view. Falls back to the\n// local cache when no developer key is available — keeps the legacy\n// single-agent-via-ARISPAY_AGENT_KEY flow working without a dev key.\n\nserver.tool(\n \"list_agents\",\n \"List all wallets under this account (server-authoritative; rehydrates the local cache).\",\n {\n withBalance: z\n .boolean()\n .optional()\n .describe(\n \"When true, fetch on-chain USDC balance per agent (adds one round-trip per wallet).\",\n ),\n },\n async ({ withBalance }) => {\n // If the user has no developer key, we can't hit the server. Fall back\n // to the local cache so the tool stays useful for env-key-only setups.\n const devKey = getApiKey();\n if (!devKey) {\n const local = listAgents();\n if (!local.length) {\n return textResult(\n \"No developer key set and no agents cached locally. Run `bootstrap_agent` or set ARISPAY_API_KEY.\",\n );\n }\n const lines = local.map((a) =>\n [\n a.name,\n ` agent id: ${a.agentId}`,\n ` wallet: ${a.walletAddress}`,\n ` network: ${a.network ?? \"base\"}`,\n ` limits: ${a.limits.perTx}¢ / tx, ${a.limits.daily}¢ / day, ${a.limits.monthly}¢ / month`,\n ` created: ${a.createdAt}`,\n \" (local cache only — set ARISPAY_API_KEY to sync from the server)\",\n ].join(\"\\n\"),\n );\n return textResult(lines.join(\"\\n\\n\"));\n }\n\n try {\n const result = await syncAgents({ includeBalance: withBalance === true });\n if (!result.agents.length) {\n return textResult(\n \"No wallets found under this developer key. Create one with `create_agent` or `bootstrap_agent`.\",\n );\n }\n const lines = result.agents.map((a) => {\n const balanceLine =\n a.usdcBalance !== undefined\n ? ` balance: ${formatUSDC(BigInt(a.usdcBalance || \"0\"))} USDC`\n : null;\n const fundedLine = a.fundedAt ? ` funded: ${a.fundedAt}` : \" funded: not yet\";\n const domainsLine = a.allowedDomains.length\n ? ` domains: ${a.allowedDomains.join(\", \")}`\n : \" domains: (unrestricted)\";\n const suspendedLine = a.suspended ? \" status: SUSPENDED\" : null;\n return [\n a.name,\n ` agent id: ${a.agentId}`,\n ` wallet: ${a.walletAddress}`,\n ` network: ${a.network}`,\n ` limits: ${a.limits.maxPerTx}¢ / tx, ${a.limits.maxDaily}¢ / day, ${a.limits.maxMonthly}¢ / month`,\n domainsLine,\n fundedLine,\n ...(balanceLine ? [balanceLine] : []),\n ...(suspendedLine ? [suspendedLine] : []),\n ` created: ${a.createdAt}`,\n ].join(\"\\n\");\n });\n return textResult(\n `${result.agents.length} wallet${result.agents.length === 1 ? \"\" : \"s\"} under this account (synced from server):\\n\\n${lines.join(\"\\n\\n\")}`,\n );\n } catch (err) {\n return textResult(\n `list_agents failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- rename_agent ----------------------------------------------------------\n//\n// Renames the server-side Agent (PATCH /v1/agents/:id) AND the local\n// cache entry. The server enforces per-org name uniqueness — a 409 here\n// means another wallet under this account already uses that name.\n\nserver.tool(\n \"rename_agent\",\n \"Rename an agent on the server and in the local cache (names are unique per account).\",\n {\n name: z.string().describe(\"Current local name of the agent to rename.\"),\n newName: z\n .string()\n .describe(\n \"New name. Letters, numbers, spaces, hyphens, underscores, dots. 1-64 chars. Must be unique per account.\",\n ),\n },\n async ({ name, newName }) => {\n if (name === newName) {\n return textResult(`Agent \\`${name}\\` already has that name — nothing to do.`);\n }\n const stored = getAgent(name);\n if (!stored) {\n return textResult(\n `No locally-cached agent named \\`${name}\\`. Run \\`list_agents\\` first to sync, or check the spelling.`,\n true,\n );\n }\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const result = await client.renameAgent(stored.agentId, newName);\n // Server accepted — mirror locally. `result.name` is the canonical\n // form (server may have trimmed it), so we use that, not the raw input.\n renameStoredAgent(name, result.name);\n return textResult(\n `✓ Renamed \\`${name}\\` → \\`${result.name}\\`. Wallet ${result.walletAddress ?? stored.walletAddress} is unchanged.`,\n );\n } catch (err) {\n return textResult(\n `rename_agent failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// ── Start ─────────────────────────────────────────────\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain().catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n});\n","/**\n * Helpers for the `pay_api` MCP tool.\n *\n * Extracted into their own module so the heuristic that triggers\n * automatic Onramp-URL surfacing is unit-testable. The trigger has to\n * be conservative — false positives turn legitimate errors (allowed-\n * domain blocks, suspended agents) into misleading \"fund your wallet\"\n * suggestions.\n */\n\n/**\n * Does this error message look like the agent's USDC ran out?\n *\n * The signal we trust is `PaymentRejectedError(402, \"Server returned 402\n * after payment was signed and sent. Seller response: ...\")` from\n * `payFetchDelegated`, where the seller's body contains a funds- or\n * balance-shaped token. We do not pre-flight balance on every call —\n * that would add a round-trip to the warm path. Post-hoc detection\n * only, and only when both the 402 status AND a balance keyword\n * appear in the same message.\n */\nexport function looksLikeInsufficientFunds(message: string): boolean {\n if (!/402/.test(message)) return false;\n return /insufficient|insufficient_funds|insufficient_balance|exceeds_balance|invalid_transfer/i.test(\n message,\n );\n}\n","/**\n * Tool-profile selection (docs/agent-discoverability.md, open question 2).\n *\n * Every registered tool's schema is resident in the MCP host's context on\n * every task. The common persona — \"an agent that pays URLs\" — never needs\n * the five platform (end-user) tools, so `PAYAGENT_MCP_PROFILE=core` skips\n * registering them and the host loads 8 schemas instead of 13:\n *\n * core profile: bootstrap_agent, pay_api, check_wallet, create_agent,\n * fund_agent, get_balance, list_agents, rename_agent\n * all (default): the above + create_enduser, attach_card_for_user,\n * set_user_limits, get_user_status, pay_merchant\n *\n * Default stays \"all\" for backward compatibility with existing host configs.\n */\nexport function platformToolsEnabled(raw = process.env.PAYAGENT_MCP_PROFILE): boolean {\n return (raw ?? \"all\").trim().toLowerCase() !== \"core\";\n}\n"],"mappings":"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","names":["lines"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/pay-api-helpers.ts","../src/profile.ts"],"sourcesContent":["/**\n * payagent-mcp — MCP server for ArisPay's wallet-centric model.\n *\n * Core idea: the user has a master funding account and one or more\n * sub-wallets (spending profiles). Sub-wallets do NOT hold their own\n * on-chain keys; they draw from the user's FundingAccount when making\n * payments. The AI (Claude, Cursor, etc.) is the agent that operates the\n * sub-wallet on the user's behalf.\n *\n * Default tools:\n * - create_user({ email, name? }) — sign up + create master funding account\n * - create_wallet({ name, perTx, daily, monthly, allowedDomains? })\n * — create a sub-wallet / spending profile\n * - list_wallets() — list sub-wallets\n * - fund_wallet({ wallet, rail, amount? }) — fund the master wallet (europ via Schuman vIBAN,\n * card via hosted card-setup)\n * - get_balance({ wallet? }) — sub-wallet + master funding-account balances\n * - pay_merchant({ wallet, merchantUrl, amount, memo, merchantId?, currency? })\n * — pay from the master wallet via balance/card rail\n *\n * Advanced / x402 rail:\n * - pay_api(url, ...) — pay an x402-protected HTTP resource (Base USDC)\n * - create_agent(...) — provision an x402 payer with its own Base wallet\n * - list_agents() — list x402 payer agents\n * - fund_agent({ name }) — fund an x402 agent's Base wallet\n * - get_balance_agent({ name }) — on-chain USDC balance for an x402 agent\n *\n * Auth: developer bearer key from ~/.payagent/config.json or ARISPAY_API_KEY.\n */\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n BootstrapError,\n type DelegatedPaymentInfo,\n DelegationClient,\n HostedTopupNotConfiguredError,\n type StoredAgent,\n bootstrapAgent,\n formatUSDC,\n getAgent,\n getApiKey,\n getArispayUrl,\n getUSDCBalance,\n launchAgent,\n listAgents,\n payFetchDelegated,\n renameStoredAgent,\n syncAgents,\n} from \"payagent\";\nimport { z } from \"zod\";\nimport { looksLikeInsufficientFunds } from \"./pay-api-helpers.js\";\nimport { platformToolsEnabled } from \"./profile.js\";\n\n// ── Configuration ─────────────────────────────────────\n\nconst arispayUrl = getArispayUrl(process.env.ARISPAY_URL);\nconst legacyAgentKey = process.env.ARISPAY_AGENT_KEY;\nconst legacyWalletAddress = process.env.PAYAGENT_WALLET;\n\n/** External id used to represent the developer user as their own EndUser/payer. */\nconst SELF_ENDUSER_EXTERNAL_ID = \"self\";\n\n/** Browser handoff host for EURØP / Schuman KYC. */\nconst buyformeUrl =\n process.env.BUYFORME_URL?.replace(/\\/$/, \"\") ?? \"https://buyforme.arispay.app\";\n\nfunction requireDevKey(): string {\n const key = getApiKey();\n if (!key) {\n throw new Error(\n \"No ArisPay developer key found. Run `npx payagent init` or set ARISPAY_API_KEY.\",\n );\n }\n return key;\n}\n\nfunction textResult(text: string, isError = false) {\n return {\n content: [{ type: \"text\" as const, text }],\n ...(isError ? { isError } : {}),\n };\n}\n\n// ── Wallet resolution ─────────────────────────────────\n\n/**\n * Resolve a locally-known sub-wallet name to its server-side wallet id.\n * Wallets are authoritative on the server; we look them up by name each time\n * so renaming on the server is always reflected immediately.\n */\nasync function resolveWallet(\n client: DelegationClient,\n name: string,\n): Promise<{ id: string; name: string } | undefined> {\n const list = await client.listWallets();\n return list.wallets.find((w) => w.name === name);\n}\n\n/**\n * Resolve the \"self\" EndUser id for the authenticated developer. This is the\n * payer record that owns the master FundingAccount.\n */\nasync function resolveSelfEndUserId(client: DelegationClient): Promise<string | undefined> {\n try {\n const user = await client.getEndUserByExternalId(SELF_ENDUSER_EXTERNAL_ID);\n return user.id;\n } catch {\n return undefined;\n }\n}\n\n// ── MCP Server ────────────────────────────────────────\n\nconst server = new McpServer({\n name: \"payagent\",\n version: \"3.0.0\",\n});\n\n// --- create_user ------------------------------------------------------------\n\nserver.tool(\n \"create_user\",\n \"Cold-start in one call: create an ArisPay user account plus the master funding account. Safe to re-run — it recovers the existing account instead of creating duplicates.\",\n {\n email: z.string().describe(\"Email for the new ArisPay account.\"),\n name: z.string().optional().describe(\"Human name. Falls back to the email local-part.\"),\n },\n async ({ email, name }) => {\n try {\n const result = await bootstrapAgent({\n email,\n name,\n arispayUrl: process.env.ARISPAY_URL,\n clientId: \"payagent-mcp-bootstrap\",\n });\n\n // Ensure the developer user has a self EndUser record so the master\n // FundingAccount can be provisioned.\n const devKey = getApiKey();\n if (devKey) {\n const client = new DelegationClient(arispayUrl, devKey);\n try {\n await client.createEndUser({\n externalId: SELF_ENDUSER_EXTERNAL_ID,\n email,\n findOrCreate: true,\n });\n } catch {\n // Best-effort; the wallets route will create it on demand if needed.\n }\n }\n\n const lines = [\n `✓ Account: ${result.email} (org \\`${result.orgName}\\`)`,\n `✓ Master funding account ready.`,\n \"\",\n \"Next steps:\",\n \" 1. create_wallet({ name: 'Daily', perTx, daily, monthly })\",\n \" 2. fund_wallet({ wallet: 'Daily', rail: 'europ' }) for SEPA / EURØP\", \n \" or fund_wallet({ wallet: 'Daily', rail: 'card' }) for card top-up.\",\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n if (err instanceof BootstrapError) {\n return textResult(`create_user failed (${err.code}): ${err.message}`, true);\n }\n return textResult(\n `create_user failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- create_wallet ----------------------------------------------------------\n\nserver.tool(\n \"create_wallet\",\n \"Create a sub-wallet / spending profile. Sub-wallets draw from the master funding account and enforce per-transaction, daily, and monthly spend limits.\",\n {\n name: z.string().describe(\"Human name for this sub-wallet, e.g. 'Daily' or 'Travel'.\"),\n perTx: z.number().int().positive().describe(\"Per-transaction spend cap in cents.\"),\n daily: z.number().int().positive().describe(\"Daily spend cap in cents.\"),\n monthly: z.number().int().positive().describe(\"Monthly spend cap in cents.\"),\n allowedDomains: z\n .array(z.string())\n .optional()\n .describe(\"If provided, restrict this sub-wallet to paying only these domains.\"),\n },\n async ({ name, perTx, daily, monthly, allowedDomains }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const wallet = await client.createWallet({\n name,\n perTx,\n daily,\n monthly,\n allowedDomains,\n });\n const lines = [\n `✓ Sub-wallet \\`${wallet.name}\\` created.`,\n ` id: ${wallet.id}`,\n ` limits: ${wallet.limits.perTx ?? \"—\"}¢ / tx, ${wallet.limits.daily ?? \"—\"}¢ / day, ${wallet.limits.monthly ?? \"—\"}¢ / month`,\n \"\",\n `Fund it with fund_wallet({ wallet: \"${wallet.name}\", rail: \"europ\" | \"card\" }).`,\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `create_wallet failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- list_wallets -----------------------------------------------------------\n\nserver.tool(\n \"list_wallets\",\n \"List all sub-wallets under this account.\",\n {},\n async () => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const list = await client.listWallets();\n if (!list.wallets.length) {\n return textResult(\n \"No sub-wallets yet. Create one with create_wallet({ name, perTx, daily, monthly }).\",\n );\n }\n const lines = list.wallets.map((w) =>\n [\n `\\`${w.name}\\` (${w.id})`,\n ` status: ${w.status}`,\n ` limits: ${w.limits.perTx ?? \"—\"}¢ / tx, ${w.limits.daily ?? \"—\"}¢ / day, ${w.limits.monthly ?? \"—\"}¢ / month`,\n ` balance: ${w.balance} ${w.balanceCurrency}`,\n ].join(\"\\n\"),\n );\n return textResult(lines.join(\"\\n\\n\"));\n } catch (err) {\n return textResult(\n `list_wallets failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- fund_wallet ------------------------------------------------------------\n\nserver.tool(\n \"fund_wallet\",\n \"Add money to the master funding account so a sub-wallet can spend. rail='europ' opens the Schuman KYC / vIBAN flow in a browser; rail='card' mints a hosted card-setup URL.\",\n {\n wallet: z.string().describe(\"Name of a sub-wallet (used only for handoff context).\"),\n rail: z\n .enum([\"europ\", \"card\"])\n .describe(\"Funding rail: 'europ' for SEPA/EURØP, 'card' for debit/credit card.\"),\n amount: z.number().positive().optional().describe(\"Optional preset amount in dollars.\"),\n },\n async ({ wallet, rail, amount }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const resolved = await resolveWallet(client, wallet);\n if (!resolved) {\n return textResult(`No sub-wallet named \\`${wallet}\\`. Run list_wallets().`, true);\n }\n\n if (rail === \"europ\") {\n const handoffUrl = `${buyformeUrl}/onboarding/fund-europ?agentId=${encodeURIComponent(\n resolved.id,\n )}`;\n const lines = [\n `Fund the master wallet for \\`${wallet}\\` with EURØP via Schuman:`,\n \"\",\n ` ${handoffUrl}`,\n \"\",\n \"Open that link in a browser to:\",\n \" 1. Verify your identity with Schuman Financial (one-time KYC).\",\n \" 2. Receive a dedicated SEPA vIBAN.\",\n \" 3. Send EUR by bank transfer; Schuman mints EURØP once it clears.\",\n \"\",\n \"After the deposit clears, the master funding account is credited and this sub-wallet can spend.\",\n ];\n return textResult(lines.join(\"\\n\"));\n }\n\n // rail === 'card'\n const endUserId = await resolveSelfEndUserId(client);\n if (!endUserId) {\n return textResult(\n \"No payer record found. Run create_user first, then retry fund_wallet with rail='card'.\",\n true,\n );\n }\n const session = await client.createCardSetupSession({ endUserId });\n const lines = [\n `Add a card to fund the master wallet for \\`${wallet}\\`:`,\n \"\",\n ` ${session.setupUrl}`,\n \"\",\n ` Expires at: ${session.expiresAt}`,\n \"\",\n \"After the card is verified, you can top up. Card top-ups are not yet exposed via MCP; use the BuyForMe web app or the ArisPay dashboard for now.\",\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `fund_wallet failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- get_balance ------------------------------------------------------------\n\nserver.tool(\n \"get_balance\",\n \"Show the master funding-account balance(s) and a sub-wallet's spend limits. If no wallet is named, lists all sub-wallets.\",\n {\n wallet: z\n .string()\n .optional()\n .describe(\"Optional sub-wallet name. Omit to list all sub-wallets.\"),\n },\n async ({ wallet }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n\n if (!wallet) {\n const list = await client.listWallets();\n if (!list.wallets.length) {\n return textResult(\"No sub-wallets yet. Create one with create_wallet().\");\n }\n const lines = list.wallets.map((w) => {\n const lim = `limits: ${w.limits.perTx ?? \"—\"}¢ / tx, ${w.limits.daily ?? \"—\"}¢ / day, ${w.limits.monthly ?? \"—\"}¢ / month`;\n return `\\`${w.name}\\` — ${w.balance} ${w.balanceCurrency} — ${lim}`;\n });\n return textResult(lines.join(\"\\n\"));\n }\n\n const resolved = await resolveWallet(client, wallet);\n if (!resolved) {\n return textResult(`No sub-wallet named \\`${wallet}\\`.`, true);\n }\n\n const bal = await client.getWalletBalance(resolved.id);\n const lines = [\n `Sub-wallet: \\`${bal.wallet.name}\\``,\n ` status: ${bal.wallet.status}`,\n ` limits: ${bal.wallet.limits.perTx ?? \"—\"}¢ / tx, ${bal.wallet.limits.daily ?? \"—\"}¢ / day, ${bal.wallet.limits.monthly ?? \"—\"}¢ / month`,\n \"\",\n \"Master funding accounts:\",\n ];\n if (!bal.fundingAccounts.length) {\n lines.push(\" No funded accounts yet. Use fund_wallet() to add money.\");\n } else {\n for (const acct of bal.fundingAccounts) {\n lines.push(` ${acct.currency}: ${acct.balance}¢ (${acct.provider ?? \"internal\"})`);\n }\n }\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `get_balance failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- pay_merchant -----------------------------------------------------------\n\nserver.tool(\n \"pay_merchant\",\n \"Pay a merchant from the master wallet through a sub-wallet. For balance-rail payments (from FundingAccount), merchantId is required. For card-rail payments, the user must have a verified card on file.\",\n {\n wallet: z.string().describe(\"Name of the sub-wallet to spend through.\"),\n merchantUrl: z.string().describe(\"Canonical merchant URL for this payment.\"),\n amount: z.number().int().positive().describe(\"Amount in cents.\"),\n memo: z.string().describe(\"Human-readable memo, e.g. 'T-shirt from getwatta.com'.\"),\n merchantId: z\n .string()\n .optional()\n .describe(\"Required for balance-rail payments to a registered merchant.\"),\n currency: z.string().optional().describe(\"Currency code. Default: USD.\"),\n rail: z\n .enum([\"balance\", \"card\"])\n .optional()\n .describe(\"Force balance or card rail. Default: server picks based on available funding.\"),\n },\n async ({ wallet, merchantUrl, amount, memo, merchantId, currency, rail }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const resolved = await resolveWallet(client, wallet);\n if (!resolved) {\n return textResult(`No sub-wallet named \\`${wallet}\\`.`, true);\n }\n\n const endUserId = await resolveSelfEndUserId(client);\n if (!endUserId) {\n return textResult(\n \"No payer record found. Run create_user first, then retry the payment.\",\n true,\n );\n }\n\n const payment = await client.createPayment(resolved.id, {\n userId: endUserId,\n amount,\n currency: currency ?? \"USD\",\n memo,\n merchantUrl,\n merchantId,\n rail,\n });\n\n const lines = [\n `Payment ${payment.id}: ${payment.status}`,\n ` rail: ${payment.rail}`,\n ` amount: ${payment.amount}¢ ${payment.currency}`,\n ];\n if (payment.merchantName) lines.push(` merchant: ${payment.merchantName}`);\n if (payment.txHash) lines.push(` tx hash: ${payment.txHash}`);\n if (payment.spend) {\n const fmtCap = (v: number | null) => (v == null ? \"no cap\" : `${v}¢`);\n lines.push(\n ` budget: ${fmtCap(payment.spend.remainingDaily)} left today, ${fmtCap(payment.spend.remainingMonthly)} this month`,\n );\n }\n if (payment.nextAction?.challengeUrl) {\n lines.push(` 3DS challenge URL: ${payment.nextAction.challengeUrl}`);\n }\n if (payment.error) {\n lines.push(` error: ${payment.error.code} — ${payment.error.message}`);\n }\n return textResult(lines.join(\"\\n\"), payment.status === \"failed\");\n } catch (err) {\n return textResult(\n `pay_merchant failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- pay_api (advanced x402) ------------------------------------------------\n\nserver.tool(\n \"pay_api\",\n \"Advanced: make an HTTP request to an x402-protected API, paying with USDC on Base via delegated signing. This is a separate rail from the wallet-centric balance/card flows.\",\n {\n url: z.string().describe(\"The full URL of the API endpoint to call.\"),\n method: z.enum([\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"]).default(\"GET\"),\n headers: z.record(z.string(), z.string()).optional(),\n body: z.string().optional(),\n agent: z.string().optional().describe(\"Optional name of a stored x402 payer agent.\"),\n },\n async ({ url, method, headers, body, agent }) => {\n const stored = agent ? getAgent(agent) : listAgents()[0];\n if (!stored?.apiKey) {\n return textResult(\n [\n \"No x402 payer agent available. For wallet-centric payments use pay_merchant.\",\n \"To create an x402 agent, use create_agent({ name, perTx, daily, monthly }).\",\n ].join(\"\\n\"),\n true,\n );\n }\n try {\n let paymentInfo: DelegatedPaymentInfo | undefined;\n const fetch402 = payFetchDelegated({\n arispayUrl,\n apiKey: stored.apiKey,\n onPayment: (info) => {\n paymentInfo = info;\n },\n });\n const response = await fetch402(url, { method, headers, body });\n const responseBody = await response.text();\n const statusLine = paymentInfo\n ? `HTTP ${response.status} (paid ${paymentInfo.amountCents}¢ via \\`${stored.name}\\` — budget left: ${paymentInfo.remainingDaily}¢ today, ${paymentInfo.remainingMonthly}¢ this month)`\n : `HTTP ${response.status} (paid via \\`${stored.name}\\`)`;\n return textResult([statusLine, \"\", responseBody].join(\"\\n\"));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (looksLikeInsufficientFunds(message)) {\n return textResult(\n [\n `Error: ${message}`,\n \"\",\n \"The x402 agent wallet is out of USDC. Fund it with fund_agent({ name }) or switch to wallet-centric pay_merchant.\",\n ].join(\"\\n\"),\n true,\n );\n }\n return textResult(`Error: ${message}`, true);\n }\n },\n);\n\n// --- create_agent (advanced x402) -------------------------------------------\n\nserver.tool(\n \"create_agent\",\n \"Advanced: provision an x402 payer agent with its own Base USDC wallet. Use create_wallet instead unless you specifically need to pay x402-protected HTTP resources.\",\n {\n name: z.string().describe(\"Local identifier for this x402 agent.\"),\n perTx: z.number().int().positive().describe(\"Per-transaction spend cap in cents.\"),\n daily: z.number().int().positive().describe(\"Daily spend cap in cents.\"),\n monthly: z.number().int().positive().describe(\"Monthly spend cap in cents.\"),\n allowedDomains: z.array(z.string()).optional(),\n network: z.enum([\"base\", \"base-sepolia\", \"ethereum\", \"polygon\"]).default(\"base\"),\n agentType: z.string().optional(),\n },\n async ({ name, perTx, daily, monthly, allowedDomains, network, agentType }) => {\n try {\n requireDevKey();\n const agent = await launchAgent({\n name,\n limits: { perTx, daily, monthly },\n allowedDomains,\n network,\n agentType,\n });\n const lines = [\n `✓ x402 agent \\`${name}\\` created.`,\n ` Agent ID: ${agent.agentId}`,\n ` Wallet: ${agent.walletAddress}`,\n ` Network: ${agent.network}`,\n ` Limits: ${perTx}¢ / tx, ${daily}¢ / day, ${monthly}¢ / month`,\n \"\",\n ` Fund the wallet with USDC on ${agent.network}, then call get_balance_agent with name=\"${name}\".`,\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `create_agent failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- fund_agent (advanced x402) ---------------------------------------------\n\nserver.tool(\n \"fund_agent\",\n \"Advanced: get the USDC deposit address for an x402 payer agent.\",\n {\n name: z.string().describe(\"Name of a locally-stored x402 agent.\"),\n },\n async ({ name }) => {\n const stored = getAgent(name);\n if (!stored) return textResult(`No x402 agent named \\`${name}\\`.`, true);\n const lines = [\n `Fund x402 agent \\`${name}\\` by sending USDC on ${stored.network ?? \"base\"} to:`,\n \"\",\n ` ${stored.walletAddress}`,\n \"\",\n \"Only send USDC on the network shown above. Other tokens or networks may be lost.\",\n \"Call get_balance_agent when the deposit lands.\",\n ];\n return textResult(lines.join(\"\\n\"));\n },\n);\n\n// --- get_balance_agent (advanced x402) --------------------------------------\n\nserver.tool(\n \"get_balance_agent\",\n \"Advanced: on-chain USDC balance for an x402 payer agent.\",\n {\n name: z.string().describe(\"Name of a locally-stored x402 agent.\"),\n },\n async ({ name }) => {\n const stored = getAgent(name);\n if (!stored) return textResult(`No x402 agent named \\`${name}\\`.`, true);\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const balance = await client.getBalance(stored.agentId);\n const human = formatUSDC(BigInt(balance.usdcBalance || \"0\"));\n const lines = [\n `${name}: ${human} USDC on ${balance.network}`,\n balance.fundedAt ? ` First funded at: ${balance.fundedAt}` : \" Not yet funded.\",\n ` Wallet: ${balance.walletAddress}`,\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `get_balance_agent failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- list_agents (advanced x402) --------------------------------------------\n\nserver.tool(\n \"list_agents\",\n \"Advanced: list x402 payer agents with on-chain wallets.\",\n {\n withBalance: z.boolean().optional().describe(\"Fetch on-chain USDC balance per agent.\"),\n },\n async ({ withBalance }) => {\n const devKey = getApiKey();\n if (!devKey) {\n return textResult(\"No developer key found. Run create_user or npx payagent init.\");\n }\n try {\n const result = await syncAgents({ includeBalance: withBalance === true });\n if (!result.agents.length) {\n return textResult(\"No x402 agents found. Use create_agent to provision one.\");\n }\n const lines = result.agents.map((a) => {\n const balanceLine =\n a.usdcBalance !== undefined\n ? ` balance: ${formatUSDC(BigInt(a.usdcBalance || \"0\"))} USDC`\n : null;\n return [\n a.name,\n ` agent id: ${a.agentId}`,\n ` wallet: ${a.walletAddress}`,\n ` network: ${a.network}`,\n ` limits: ${a.limits.maxPerTx}¢ / tx, ${a.limits.maxDaily}¢ / day, ${a.limits.maxMonthly}¢ / month`,\n ...(balanceLine ? [balanceLine] : []),\n ].join(\"\\n\");\n });\n return textResult(lines.join(\"\\n\\n\"));\n } catch (err) {\n return textResult(\n `list_agents failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- rename_agent (advanced x402) -------------------------------------------\n\nserver.tool(\n \"rename_agent\",\n \"Advanced: rename an x402 payer agent.\",\n {\n name: z.string().describe(\"Current local name of the x402 agent.\"),\n newName: z.string().describe(\"New name.\"),\n },\n async ({ name, newName }) => {\n if (name === newName) {\n return textResult(`Agent \\`${name}\\` already has that name.`);\n }\n const stored = getAgent(name);\n if (!stored) {\n return textResult(`No x402 agent named \\`${name}\\`.`, true);\n }\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const result = await client.renameAgent(stored.agentId, newName);\n renameStoredAgent(name, result.name);\n return textResult(`✓ Renamed \\`${name}\\` → \\`${result.name}\\`.`);\n } catch (err) {\n return textResult(\n `rename_agent failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n);\n\n// --- Platform (end-user) tools ----------------------------------------------\n//\n// Skipped under PAYAGENT_MCP_PROFILE=core.\nif (platformToolsEnabled()) {\n server.tool(\n \"create_enduser\",\n \"Platform mode: register an end-customer under your account.\",\n {\n externalId: z.string().describe(\"Your own stable id for this customer.\"),\n email: z.string().optional(),\n findOrCreate: z.boolean().optional(),\n },\n async ({ externalId, email, findOrCreate }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const user = await client.createEndUser({ externalId, email, findOrCreate });\n return textResult(\n `✓ End-user \\`${externalId}\\` ready.\\n ArisPay id: ${user.id}\\n Has card: ${user.hasPaymentMethod ? \"yes\" : \"no\"}`,\n );\n } catch (err) {\n return textResult(\n `create_enduser failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n\n server.tool(\n \"attach_card_for_user\",\n \"Platform mode: mint a hosted card-entry URL for an end-user.\",\n {\n userId: z.string().describe(\"ArisPay-internal end-user id.\"),\n agentName: z.string().optional().describe(\"Optional x402 agent name to scope the session to.\"),\n },\n async ({ userId, agentName }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const agentId = agentName ? getAgent(agentName)?.agentId : undefined;\n const session = await client.createCardSetupSession({ endUserId: userId, agentId });\n return textResult(\n [`Card-entry URL:`, ` ${session.setupUrl}`, ` Expires at: ${session.expiresAt}`].join(\n \"\\n\",\n ),\n );\n } catch (err) {\n return textResult(\n `attach_card_for_user failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n\n server.tool(\n \"set_user_limits\",\n \"Platform mode: set per-(user, agent) spend caps.\",\n {\n userId: z.string(),\n agentName: z.string(),\n perTx: z.number().int().optional(),\n daily: z.number().int().optional(),\n monthly: z.number().int().optional(),\n allowedMcc: z.array(z.string()).optional(),\n blockedMcc: z.array(z.string()).optional(),\n },\n async ({ userId, agentName, perTx, daily, monthly, allowedMcc, blockedMcc }) => {\n try {\n const stored = getAgent(agentName);\n if (!stored) return textResult(`No x402 agent named \\`${agentName}\\`.`, true);\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const limit = await client.setUserLimits(userId, {\n agentId: stored.agentId,\n maxPerTransaction: perTx ?? null,\n maxDaily: daily ?? null,\n maxMonthly: monthly ?? null,\n allowedMerchantCategories: allowedMcc,\n blockedMerchantCategories: blockedMcc,\n });\n return textResult(\n `✓ Limits set. per-tx ${limit.maxPerTransaction ?? \"inherit\"}¢, daily ${limit.maxDaily ?? \"inherit\"}¢, monthly ${limit.maxMonthly ?? \"inherit\"}¢`,\n );\n } catch (err) {\n return textResult(\n `set_user_limits failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n\n server.tool(\n \"get_user_status\",\n \"Platform mode: report an end-user's card and wallet readiness.\",\n {\n userId: z.string(),\n },\n async ({ userId }) => {\n try {\n const devKey = requireDevKey();\n const client = new DelegationClient(arispayUrl, devKey);\n const user = await client.getEndUser(userId);\n const lines = [\n `${user.externalId} (${user.id})`,\n ` card: ${user.hasPaymentMethod ? `${user.cardBrand ?? \"card\"} …${user.cardLast4 ?? \"????\"}` : \"—\"}`,\n ` wallet: ${user.walletAddress ?? \"—\"}${user.walletChain ? ` on ${user.walletChain}` : \"\"}`,\n ];\n return textResult(lines.join(\"\\n\"));\n } catch (err) {\n return textResult(\n `get_user_status failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }\n },\n );\n}\n\n// --- check_wallet (legacy diagnostic) ---------------------------------------\n\nserver.tool(\n \"check_wallet\",\n \"Legacy diagnostic for x402 payer agents. Use get_balance for wallet-centric balances.\",\n {\n agent: z.string().optional().describe(\"Optional name of a locally-stored x402 agent.\"),\n },\n async ({ agent }) => {\n const stored = agent ? getAgent(agent) : listAgents()[0];\n const walletAddress = stored?.walletAddress ?? legacyWalletAddress;\n const keyTail =\n stored?.apiKey.slice(-4) ?? (legacyAgentKey ? legacyAgentKey.slice(-4) : undefined);\n\n const lines = [`ArisPay URL: ${arispayUrl}`];\n if (stored) lines.push(`Agent: ${stored.name} (${stored.agentId})`);\n if (keyTail) lines.push(`Agent key: ap_…${keyTail}`);\n\n if (walletAddress) {\n lines.push(`Wallet: ${walletAddress}`);\n try {\n const raw = await getUSDCBalance(walletAddress, (stored?.network as \"base\") ?? \"base\");\n lines.push(`Balance: ${formatUSDC(raw)} USDC on ${stored?.network ?? \"base\"}`);\n } catch (err) {\n lines.push(`Balance: unavailable (${err instanceof Error ? err.message : String(err)})`);\n }\n } else {\n lines.push(\"\", \"No wallet known.\");\n }\n return textResult(lines.join(\"\\n\"));\n },\n);\n\n// ── Start ─────────────────────────────────────────────\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain().catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n});\n","/**\n * Helpers for the `pay_api` MCP tool.\n *\n * Extracted into their own module so the heuristic that triggers\n * automatic Onramp-URL surfacing is unit-testable. The trigger has to\n * be conservative — false positives turn legitimate errors (allowed-\n * domain blocks, suspended agents) into misleading \"fund your wallet\"\n * suggestions.\n */\n\n/**\n * Does this error message look like the agent's USDC ran out?\n *\n * The signal we trust is `PaymentRejectedError(402, \"Server returned 402\n * after payment was signed and sent. Seller response: ...\")` from\n * `payFetchDelegated`, where the seller's body contains a funds- or\n * balance-shaped token. We do not pre-flight balance on every call —\n * that would add a round-trip to the warm path. Post-hoc detection\n * only, and only when both the 402 status AND a balance keyword\n * appear in the same message.\n */\nexport function looksLikeInsufficientFunds(message: string): boolean {\n if (!/402/.test(message)) return false;\n return /insufficient|insufficient_funds|insufficient_balance|exceeds_balance|invalid_transfer/i.test(\n message,\n );\n}\n","/**\n * Tool-profile selection (docs/agent-discoverability.md, open question 2).\n *\n * Every registered tool's schema is resident in the MCP host's context on\n * every task. The common persona — \"an agent that pays URLs\" — never needs\n * the five platform (end-user) tools, so `PAYAGENT_MCP_PROFILE=core` skips\n * registering them and the host loads 8 schemas instead of 13:\n *\n * core profile: bootstrap_agent, pay_api, check_wallet, create_agent,\n * fund_agent, get_balance, list_agents, rename_agent\n * all (default): the above + create_enduser, attach_card_for_user,\n * set_user_limits, get_user_status, pay_merchant\n *\n * Default stays \"all\" for backward compatibility with existing host configs.\n */\nexport function platformToolsEnabled(raw = process.env.PAYAGENT_MCP_PROFILE): boolean {\n return (raw ?? \"all\").trim().toLowerCase() !== \"core\";\n}\n"],"mappings":"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","names":["lines"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arispay/payagent-mcp",
3
- "version": "2.8.0",
3
+ "version": "3.0.0",
4
4
  "description": "MCP server that gives AI agents a wallet: pay x402 APIs (USD + EUR), check balances, self-onboard with one tool call. Use with Claude, Cursor, or any MCP client — delegated custody, no private keys on the agent.",
5
5
  "type": "module",
6
6
  "bin": {