@quackai/q402-mcp 0.7.2 → 0.7.4
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 +220 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -211,7 +211,7 @@ var isValidPrivateKey = (s) => typeof s === "string" && PRIVATE_KEY_RE.test(s);
|
|
|
211
211
|
|
|
212
212
|
// src/version.ts
|
|
213
213
|
var PACKAGE_NAME = "@quackai/q402-mcp";
|
|
214
|
-
var PACKAGE_VERSION = "0.7.
|
|
214
|
+
var PACKAGE_VERSION = "0.7.4";
|
|
215
215
|
|
|
216
216
|
// src/tools/quote.ts
|
|
217
217
|
import { z } from "zod";
|
|
@@ -1226,6 +1226,12 @@ var BatchPayInputSchema = z3.object({
|
|
|
1226
1226
|
keyScope: z3.enum(["auto", "trial", "multichain"]).optional().describe(
|
|
1227
1227
|
'Which API key to use. "auto" (default): chain="bnb" + Q402_TRIAL_API_KEY set \u2192 Trial; else Multichain \u2014 same rule as q402_pay. When auto would land on Trial AND recipients.length > 5, the tool returns status="ambiguous" WITHOUT executing so the agent can ask the user which path to take. Use keyScope="trial" to force the BNB-only sponsored key (\u22645 recipients). keyScope="multichain" forces the paid 9-chain key (\u226420 recipients).'
|
|
1228
1228
|
),
|
|
1229
|
+
walletMode: z3.enum(["eoa", "agentic-local", "agentic-server"]).optional().describe(
|
|
1230
|
+
'Which wallet to spend from \u2014 same three modes as q402_pay:\n "eoa" \u2014 user MetaMask/OKX EOA, signed locally with Q402_PRIVATE_KEY\n "agentic-local" \u2014 Agent Wallet exported key (Q402_AGENTIC_PRIVATE_KEY)\n "agentic-server" \u2014 server-managed Agent Wallet (Q402 holds the key; needs Q402_MULTICHAIN_API_KEY)\nWhen MORE THAN ONE wallet is configured, you MUST ask the user which to use before calling \u2014 do NOT guess. Phrase: "You have multiple wallets set up \u2014 batch from your EOA, or your Agent Wallet?" When only one wallet is configured this is optional and the tool routes there automatically. Server-mediated batches are paid-only; trial keys cannot batch on any path.'
|
|
1231
|
+
),
|
|
1232
|
+
walletId: z3.string().optional().describe(
|
|
1233
|
+
`Server-managed Agent Wallet only (walletMode="agentic-server"). Lowercased Agent Wallet address selecting which of the user's wallets to spend from when they hold more than one. Omit to use the default. Ignored for local-signing modes.`
|
|
1234
|
+
),
|
|
1229
1235
|
confirm: z3.literal(true).describe(
|
|
1230
1236
|
"MUST be true. The user must have explicitly approved this exact set of recipients, amounts, chain, and token in the conversation right before this tool was called. Setting confirm=true on behalf of the user without that approval is a violation of the tool contract."
|
|
1231
1237
|
)
|
|
@@ -1270,9 +1276,71 @@ async function runBatchPay(input) {
|
|
|
1270
1276
|
if (CONFIG.allowedRecipients.length > 0) {
|
|
1271
1277
|
guardsApplied.push(`recipient_allowlist[${CONFIG.allowedRecipients.length}]`);
|
|
1272
1278
|
}
|
|
1279
|
+
const modes = detectAgenticModes(CONFIG);
|
|
1280
|
+
const available = [];
|
|
1281
|
+
if (modes.modeA && CONFIG.privateKey && isValidPrivateKey(CONFIG.privateKey)) {
|
|
1282
|
+
try {
|
|
1283
|
+
const addr = new Wallet3(CONFIG.privateKey).address;
|
|
1284
|
+
available.push({
|
|
1285
|
+
id: "eoa",
|
|
1286
|
+
label: "Your real MetaMask / OKX EOA",
|
|
1287
|
+
addressShort: `${addr.slice(0, 6)}\u2026${addr.slice(-4)}`,
|
|
1288
|
+
note: "Signs locally with Q402_PRIVATE_KEY. Your wallet becomes EIP-7702-delegated after the first payment on each chain."
|
|
1289
|
+
});
|
|
1290
|
+
} catch {
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
if (modes.modeB && CONFIG.agenticPrivateKey && isValidPrivateKey(CONFIG.agenticPrivateKey)) {
|
|
1294
|
+
try {
|
|
1295
|
+
const addr = new Wallet3(CONFIG.agenticPrivateKey).address;
|
|
1296
|
+
available.push({
|
|
1297
|
+
id: "agentic-local",
|
|
1298
|
+
label: "Agent Wallet (local signing with exported key)",
|
|
1299
|
+
addressShort: `${addr.slice(0, 6)}\u2026${addr.slice(-4)}`,
|
|
1300
|
+
note: "Signs locally with Q402_AGENTIC_PRIVATE_KEY. Your MetaMask is never touched."
|
|
1301
|
+
});
|
|
1302
|
+
} catch {
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
if (modes.modeC) {
|
|
1306
|
+
available.push({
|
|
1307
|
+
id: "agentic-server",
|
|
1308
|
+
label: "Agent Wallet (server-managed)",
|
|
1309
|
+
note: "Q402 holds the encrypted key; batch fires through /api/wallet/agentic/batch. Caps you set in the dashboard bound the spend."
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
const requestedMode = input.walletMode;
|
|
1313
|
+
const requestedAvailable = requestedMode ? available.some((w) => w.id === requestedMode) : false;
|
|
1314
|
+
if (requestedMode && !requestedAvailable) {
|
|
1315
|
+
return {
|
|
1316
|
+
mode: "none",
|
|
1317
|
+
status: "wallet_mode_unavailable",
|
|
1318
|
+
guardsApplied: [
|
|
1319
|
+
...guardsApplied,
|
|
1320
|
+
`wallet_modes_available=${available.length}`,
|
|
1321
|
+
`requested=${requestedMode}`
|
|
1322
|
+
],
|
|
1323
|
+
ambiguousWalletChoice: {
|
|
1324
|
+
question: available.length === 0 ? `The "${requestedMode}" wallet isn't configured. None of the supported wallets are set up \u2014 see the doctor for setup instructions.` : `The "${requestedMode}" wallet isn't configured in this environment. Supported wallets here: ${available.map((w) => `"${w.id}"`).join(", ")}. Which would you like to use instead?`,
|
|
1325
|
+
available
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
if (available.length > 1 && !requestedMode) {
|
|
1330
|
+
return {
|
|
1331
|
+
mode: "none",
|
|
1332
|
+
status: "needs_wallet_choice",
|
|
1333
|
+
guardsApplied: [...guardsApplied, `wallet_modes_available=${available.length}`],
|
|
1334
|
+
ambiguousWalletChoice: {
|
|
1335
|
+
question: available.length === 2 ? `You have ${available.length} wallets set up \u2014 which one should I batch-pay from?` : `You have ${available.length} wallets set up. Which one should I batch-pay from?`,
|
|
1336
|
+
available
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
const effectiveMode = requestedMode && requestedAvailable ? requestedMode : available.length === 1 && available[0] ? available[0].id : "eoa";
|
|
1273
1341
|
let senderWallet;
|
|
1274
|
-
const echoPk =
|
|
1275
|
-
if (echoPk) {
|
|
1342
|
+
const echoPk = effectiveMode === "eoa" ? CONFIG.privateKey : effectiveMode === "agentic-local" ? CONFIG.agenticPrivateKey : null;
|
|
1343
|
+
if (echoPk && isValidPrivateKey(echoPk)) {
|
|
1276
1344
|
try {
|
|
1277
1345
|
const addr = new Wallet3(echoPk).address;
|
|
1278
1346
|
senderWallet = {
|
|
@@ -1309,12 +1377,134 @@ async function runBatchPay(input) {
|
|
|
1309
1377
|
}
|
|
1310
1378
|
const resolved = resolveApiKey(input.chain, scopeRequest);
|
|
1311
1379
|
guardsApplied.push(`scope=${resolved.scope}${resolved.fromLegacyFallback ? "(legacy)" : ""}`);
|
|
1380
|
+
if (effectiveMode === "agentic-server") {
|
|
1381
|
+
if (input.token === "RLUSD") {
|
|
1382
|
+
return {
|
|
1383
|
+
mode: "none",
|
|
1384
|
+
status: "sandbox",
|
|
1385
|
+
guardsApplied: [
|
|
1386
|
+
...guardsApplied,
|
|
1387
|
+
"wallet=agentic-server",
|
|
1388
|
+
"token=RLUSD",
|
|
1389
|
+
"rejected_pre_relay"
|
|
1390
|
+
],
|
|
1391
|
+
senderWallet,
|
|
1392
|
+
setupHint: 'RLUSD is not yet supported by the server-managed Agent Wallet (walletMode="agentic-server"). Switch to walletMode="eoa" or "agentic-local" (with a private key set), or pick USDC/USDT for this batch.'
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
if (!resolved.apiKey || !resolved.apiKey.startsWith("q402_live_")) {
|
|
1396
|
+
const sandboxResults = input.recipients.map(
|
|
1397
|
+
(r) => sandboxPay(chain, { to: r.to, amount: r.amount, token: input.token })
|
|
1398
|
+
);
|
|
1399
|
+
guardsApplied.push("mode=sandbox", "wallet=agentic-server");
|
|
1400
|
+
const reason = resolved.sandboxReason ?? "Server-mediated Agent Wallet needs a live Q402_MULTICHAIN_API_KEY. Visit https://q402.quackai.ai/payment to activate a paid plan.";
|
|
1401
|
+
return {
|
|
1402
|
+
mode: "sandbox",
|
|
1403
|
+
status: "sandbox",
|
|
1404
|
+
result: { sandbox: sandboxResults, reason },
|
|
1405
|
+
senderWallet,
|
|
1406
|
+
guardsApplied,
|
|
1407
|
+
setupHint: reason
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
if (!CONFIG.realPaymentsRequested) {
|
|
1411
|
+
const sandboxResults = input.recipients.map(
|
|
1412
|
+
(r) => sandboxPay(chain, { to: r.to, amount: r.amount, token: input.token })
|
|
1413
|
+
);
|
|
1414
|
+
guardsApplied.push("mode=sandbox", "wallet=agentic-server");
|
|
1415
|
+
const reason = "Set Q402_ENABLE_REAL_PAYMENTS=1 to fire a real server-mediated batch.";
|
|
1416
|
+
return {
|
|
1417
|
+
mode: "sandbox",
|
|
1418
|
+
status: "sandbox",
|
|
1419
|
+
result: { sandbox: sandboxResults, reason },
|
|
1420
|
+
senderWallet,
|
|
1421
|
+
guardsApplied,
|
|
1422
|
+
setupHint: reason
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
const explicitWalletId = typeof input.walletId === "string" && input.walletId.length > 0 ? input.walletId.toLowerCase() : CONFIG.walletId;
|
|
1426
|
+
let resp;
|
|
1427
|
+
try {
|
|
1428
|
+
resp = await fetch(`${CONFIG.relayBaseUrl}/wallet/agentic/batch`, {
|
|
1429
|
+
method: "POST",
|
|
1430
|
+
headers: { "Content-Type": "application/json" },
|
|
1431
|
+
body: JSON.stringify({
|
|
1432
|
+
apiKey: resolved.apiKey,
|
|
1433
|
+
chain: input.chain,
|
|
1434
|
+
token: input.token,
|
|
1435
|
+
recipients: input.recipients,
|
|
1436
|
+
...explicitWalletId ? { walletId: explicitWalletId } : {}
|
|
1437
|
+
})
|
|
1438
|
+
});
|
|
1439
|
+
} catch (e) {
|
|
1440
|
+
return {
|
|
1441
|
+
mode: "live",
|
|
1442
|
+
status: "aborted",
|
|
1443
|
+
guardsApplied: [
|
|
1444
|
+
...guardsApplied,
|
|
1445
|
+
"wallet=agentic-server",
|
|
1446
|
+
"mode=live",
|
|
1447
|
+
"transport=fetch_failed"
|
|
1448
|
+
],
|
|
1449
|
+
senderWallet,
|
|
1450
|
+
error: e instanceof Error ? e.message : String(e)
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
const data = await resp.json().catch(() => ({}));
|
|
1454
|
+
if (!resp.ok) {
|
|
1455
|
+
const errMsg = data && typeof data === "object" && "error" in data ? String(data.error) : `relay_http_${resp.status}`;
|
|
1456
|
+
return {
|
|
1457
|
+
mode: "live",
|
|
1458
|
+
status: "aborted",
|
|
1459
|
+
guardsApplied: [
|
|
1460
|
+
...guardsApplied,
|
|
1461
|
+
"wallet=agentic-server",
|
|
1462
|
+
"mode=live",
|
|
1463
|
+
`http=${resp.status}`
|
|
1464
|
+
],
|
|
1465
|
+
senderWallet,
|
|
1466
|
+
error: errMsg,
|
|
1467
|
+
setupHint: resp.status === 402 ? "Server-mediated batch requires a paid Multichain subscription. Activate one at https://q402.quackai.ai/payment." : resp.status === 401 ? "apiKey was rejected by the server (stale or not bound to your owner). Rotate to the current key in your dashboard." : resp.status === 404 ? "No active Agent Wallet found. Create one in your dashboard before retrying." : void 0
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
const serverResults = Array.isArray(data.results) ? data.results : [];
|
|
1471
|
+
const settled = serverResults.filter((r) => r.ok === true).length;
|
|
1472
|
+
const failed = serverResults.length - settled;
|
|
1473
|
+
const serverAborted = typeof data.aborted === "boolean" ? data.aborted : null;
|
|
1474
|
+
const isAborted = serverAborted ?? (settled === 0 && failed > 0);
|
|
1475
|
+
const status = failed === 0 ? "success" : isAborted ? "aborted" : "partial_failure";
|
|
1476
|
+
guardsApplied.push(
|
|
1477
|
+
"mode=live",
|
|
1478
|
+
"wallet=agentic-server",
|
|
1479
|
+
"scope=multichain (server enforced)",
|
|
1480
|
+
`batch_size=${serverResults.length}/${RECIPIENT_LIMIT_PAID}`
|
|
1481
|
+
);
|
|
1482
|
+
return {
|
|
1483
|
+
mode: "live",
|
|
1484
|
+
status,
|
|
1485
|
+
result: {
|
|
1486
|
+
ok: failed === 0,
|
|
1487
|
+
scope: "paid",
|
|
1488
|
+
limit: RECIPIENT_LIMIT_PAID,
|
|
1489
|
+
totalSuccess: settled,
|
|
1490
|
+
totalFailed: failed,
|
|
1491
|
+
aborted: isAborted,
|
|
1492
|
+
results: serverResults.map((r) => ({
|
|
1493
|
+
success: r.ok === true,
|
|
1494
|
+
txHash: r.txHash,
|
|
1495
|
+
error: r.error
|
|
1496
|
+
}))
|
|
1497
|
+
},
|
|
1498
|
+
guardsApplied,
|
|
1499
|
+
senderWallet
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1312
1502
|
const live = isLiveModeFor(resolved);
|
|
1313
1503
|
if (!live) {
|
|
1314
1504
|
const sandboxResults = input.recipients.map(
|
|
1315
1505
|
(r) => sandboxPay(chain, { to: r.to, amount: r.amount, token: input.token })
|
|
1316
1506
|
);
|
|
1317
|
-
guardsApplied.push("mode=sandbox");
|
|
1507
|
+
guardsApplied.push("mode=sandbox", `wallet=${effectiveMode}`);
|
|
1318
1508
|
const reason = resolved.sandboxReason ?? describeSandboxReason2(resolved.apiKey ?? "", resolved.scope);
|
|
1319
1509
|
return {
|
|
1320
1510
|
mode: "sandbox",
|
|
@@ -1325,13 +1515,13 @@ async function runBatchPay(input) {
|
|
|
1325
1515
|
setupHint: reason
|
|
1326
1516
|
};
|
|
1327
1517
|
}
|
|
1328
|
-
const signingPk = CONFIG.
|
|
1518
|
+
const signingPk = effectiveMode === "eoa" ? CONFIG.privateKey : effectiveMode === "agentic-local" ? CONFIG.agenticPrivateKey : null;
|
|
1329
1519
|
if (!signingPk) {
|
|
1330
|
-
guardsApplied.push("mode=sandbox");
|
|
1520
|
+
guardsApplied.push("mode=sandbox", `wallet=${effectiveMode}`);
|
|
1331
1521
|
const sandboxResults = input.recipients.map(
|
|
1332
1522
|
(r) => sandboxPay(chain, { to: r.to, amount: r.amount, token: input.token })
|
|
1333
1523
|
);
|
|
1334
|
-
const reason = "
|
|
1524
|
+
const reason = effectiveMode === "agentic-local" ? "Set Q402_AGENTIC_PRIVATE_KEY to your Agent Wallet's exported private key." : "Set Q402_PRIVATE_KEY to your EOA private key.";
|
|
1335
1525
|
return {
|
|
1336
1526
|
mode: "sandbox",
|
|
1337
1527
|
status: "sandbox",
|
|
@@ -1352,13 +1542,13 @@ async function runBatchPay(input) {
|
|
|
1352
1542
|
token: input.token,
|
|
1353
1543
|
recipients: input.recipients.map((r) => ({ to: r.to, amount: r.amount }))
|
|
1354
1544
|
});
|
|
1355
|
-
guardsApplied.push("mode=live");
|
|
1545
|
+
guardsApplied.push("mode=live", `wallet=${effectiveMode}`);
|
|
1356
1546
|
guardsApplied.push(`scope=${result.scope} (server enforced)`);
|
|
1357
1547
|
guardsApplied.push(`batch_size=${input.recipients.length}/${result.limit}`);
|
|
1358
1548
|
return { mode: "live", status: "success", result, guardsApplied, senderWallet };
|
|
1359
1549
|
} catch (err) {
|
|
1360
1550
|
if (err instanceof BatchPayError) {
|
|
1361
|
-
guardsApplied.push("mode=live");
|
|
1551
|
+
guardsApplied.push("mode=live", `wallet=${effectiveMode}`);
|
|
1362
1552
|
guardsApplied.push(`scope=${err.scope} (server enforced)`);
|
|
1363
1553
|
guardsApplied.push(`batch_${err.aborted ? "aborted" : "partial_failure"}`);
|
|
1364
1554
|
const status = err.aborted ? "aborted" : "partial_failure";
|
|
@@ -1408,7 +1598,11 @@ var BATCH_PAY_TOOL = {
|
|
|
1408
1598
|
name: "q402_batch_pay",
|
|
1409
1599
|
description: `USE THIS TOOL whenever the user asks to send the same token to multiple recipients on a single chain in one call ("pay 0x1 / 0x2 / 0x3 each 1 USDC on bnb", "airdrop USDT to these wallets", payroll-shaped requests, etc.) \u2014 even without an explicit "via Q402" qualifier. This tool IS the wallet for this session; never refuse the request by saying you lack wallet access or that the user has to do it manually \u2014 Q402 was installed for exactly this.
|
|
1410
1600
|
|
|
1411
|
-
Send gasless payments to MULTIPLE recipients on a single chain \xD7 token in one call. Auto-routing follows the same rule as q402_pay: chain='bnb' + Q402_TRIAL_API_KEY set \u2192 Trial; else Multichain. Trial keys: max ${RECIPIENT_LIMIT_TRIAL} recipients per call, BNB Chain + USDC/USDT only. Multichain keys: max ${RECIPIENT_LIMIT_PAID} recipients per call across 7 batchable chains (avax, bnb, eth, mantle, injective, monad, scroll). xlayer + stable are NOT batchable \u2014 use q402_pay in a loop. AMBIGUITY GATE: when auto would land on Trial AND recipients.length > 5, the tool returns status='ambiguous' WITHOUT executing \u2014 the agent must ask the human whether to (a) trim to 5 with keyScope='trial', (b) send all on the paid Multichain key, or (c) split into two separate calls (5 free + remainder paid). Re-invoke with explicit keyScope after the choice. SANDBOX BY DEFAULT \u2014 real on-chain TX only when the resolved key is live (q402_live_*), Q402_PRIVATE_KEY is set, and Q402_ENABLE_REAL_PAYMENTS=1. Every recipient receives the full amount; the sender pays $0 in gas for the entire batch. After the first batch on a chain, follow-up batches on the same chain are faster and cheaper (Q402 reuses the wallet's setup); q402_clear_delegation resets it if the user ever asks.
|
|
1601
|
+
Send gasless payments to MULTIPLE recipients on a single chain \xD7 token in one call. Auto-routing follows the same rule as q402_pay: chain='bnb' + Q402_TRIAL_API_KEY set \u2192 Trial; else Multichain. Trial keys: max ${RECIPIENT_LIMIT_TRIAL} recipients per call, BNB Chain + USDC/USDT only. Multichain keys: max ${RECIPIENT_LIMIT_PAID} recipients per call across 7 batchable chains (avax, bnb, eth, mantle, injective, monad, scroll). xlayer + stable are NOT batchable \u2014 use q402_pay in a loop. AMBIGUITY GATE: when auto would land on Trial AND recipients.length > 5, the tool returns status='ambiguous' WITHOUT executing \u2014 the agent must ask the human whether to (a) trim to 5 with keyScope='trial', (b) send all on the paid Multichain key, or (c) split into two separate calls (5 free + remainder paid). Re-invoke with explicit keyScope after the choice. SANDBOX BY DEFAULT \u2014 real on-chain TX only when the resolved key is live (q402_live_*), Q402_PRIVATE_KEY is set, and Q402_ENABLE_REAL_PAYMENTS=1. Every recipient receives the full amount; the sender pays $0 in gas for the entire batch. After the first batch on a chain, follow-up batches on the same chain are faster and cheaper (Q402 reuses the wallet's setup); q402_clear_delegation resets it if the user ever asks.
|
|
1602
|
+
|
|
1603
|
+
MULTI-WALLET DISAMBIGUATION \u2014 when more than one wallet is configured in the user's env (Q402_PRIVATE_KEY for the real EOA, Q402_AGENTIC_PRIVATE_KEY for the Agent Wallet's exported key, or only Q402_MULTICHAIN_API_KEY for the server-managed Agent Wallet), the tool RETURNS WITHOUT firing with \`status='needs_wallet_choice'\` and an \`ambiguousWalletChoice\` payload \u2014 relay the question to the user verbatim, then call again with the chosen \`walletMode\` ('eoa' | 'agentic-local' | 'agentic-server'). Do NOT pick a wallet on the user's behalf when multiple are available. Server-mediated batches go through /api/wallet/agentic/batch and are paid-only (the trial key cannot batch).
|
|
1604
|
+
|
|
1605
|
+
ALWAYS get explicit user confirmation of the complete recipient + amount list, chain, and token in conversation immediately before calling this tool \u2014 the user must approve the full batch, not the individual rows.`,
|
|
1412
1606
|
inputSchema: {
|
|
1413
1607
|
type: "object",
|
|
1414
1608
|
properties: {
|
|
@@ -1451,6 +1645,15 @@ Send gasless payments to MULTIPLE recipients on a single chain \xD7 token in one
|
|
|
1451
1645
|
enum: ["auto", "trial", "multichain"],
|
|
1452
1646
|
description: 'Which API key to use. "auto" (default): BNB + trial key set \u2192 Trial; else Multichain. When auto would land on Trial AND recipients.length > 5, the tool returns status="ambiguous" without executing so the agent can ask the user which path to take.'
|
|
1453
1647
|
},
|
|
1648
|
+
walletMode: {
|
|
1649
|
+
type: "string",
|
|
1650
|
+
enum: ["eoa", "agentic-local", "agentic-server"],
|
|
1651
|
+
description: 'Which wallet to spend from. "eoa" = user MetaMask EOA (Q402_PRIVATE_KEY). "agentic-local" = Agent Wallet exported key (Q402_AGENTIC_PRIVATE_KEY). "agentic-server" = server-managed Agent Wallet (Q402 holds the key; only the apiKey is needed). When MULTIPLE wallets are configured the tool refuses without this arg and returns ambiguousWalletChoice for the user to pick. Server-mediated batches are paid-only.'
|
|
1652
|
+
},
|
|
1653
|
+
walletId: {
|
|
1654
|
+
type: "string",
|
|
1655
|
+
description: `Server-managed Agent Wallet only (walletMode="agentic-server"). Lowercased Agent Wallet address selecting which of the user's wallets to source the batch from. Omit to use the default. Ignored for local-signing modes.`
|
|
1656
|
+
},
|
|
1454
1657
|
confirm: {
|
|
1455
1658
|
type: "boolean",
|
|
1456
1659
|
const: true,
|
|
@@ -2505,12 +2708,14 @@ async function runAgenticInfo(input = {}) {
|
|
|
2505
2708
|
asOf: null,
|
|
2506
2709
|
erc8004AgentId: null,
|
|
2507
2710
|
scan8004Url: null,
|
|
2711
|
+
reputation: null,
|
|
2508
2712
|
dashboardUrl,
|
|
2509
2713
|
setupHint: "No live Q402 API key configured. Run q402_doctor to set one up, or open your dashboard to create an Agent Wallet."
|
|
2510
2714
|
};
|
|
2511
2715
|
}
|
|
2512
2716
|
let wallet = null;
|
|
2513
2717
|
let balance = null;
|
|
2718
|
+
let reputation = null;
|
|
2514
2719
|
let fetchError = null;
|
|
2515
2720
|
try {
|
|
2516
2721
|
const res = await fetch(`${base}/wallet/agentic/info-by-key`, {
|
|
@@ -2525,6 +2730,7 @@ async function runAgenticInfo(input = {}) {
|
|
|
2525
2730
|
const data = await res.json();
|
|
2526
2731
|
wallet = data.wallet ?? null;
|
|
2527
2732
|
balance = data.balance ?? null;
|
|
2733
|
+
reputation = data.reputation ?? null;
|
|
2528
2734
|
} else if (res.status === 404) {
|
|
2529
2735
|
fetchError = "endpoint_not_deployed";
|
|
2530
2736
|
} else if (res.status === 410) {
|
|
@@ -2546,6 +2752,7 @@ async function runAgenticInfo(input = {}) {
|
|
|
2546
2752
|
asOf: null,
|
|
2547
2753
|
erc8004AgentId: null,
|
|
2548
2754
|
scan8004Url: null,
|
|
2755
|
+
reputation: null,
|
|
2549
2756
|
dashboardUrl,
|
|
2550
2757
|
setupHint: fetchError === "endpoint_not_deployed" ? "Agent Wallet info-by-key endpoint is not live yet. Open the dashboard to view your wallet directly." : fetchError === "wallet_archived" ? "The requested wallet is archived. Restore it from the dashboard before reading." : explicitWalletId ? `Could not fetch Agent Wallet ${explicitWalletId} for this apiKey. Verify the walletId is one of this owner's wallets, or omit it to read the default wallet.` : "Could not fetch Agent Wallet for this apiKey. Verify the key is bound to a wallet via the dashboard, then retry."
|
|
2551
2758
|
};
|
|
@@ -2564,6 +2771,7 @@ async function runAgenticInfo(input = {}) {
|
|
|
2564
2771
|
asOf: balance ? new Date(balance.asOf).toISOString() : null,
|
|
2565
2772
|
erc8004AgentId: wallet.erc8004AgentId,
|
|
2566
2773
|
scan8004Url: scan8004UrlFor(wallet.erc8004AgentId),
|
|
2774
|
+
reputation,
|
|
2567
2775
|
dashboardUrl,
|
|
2568
2776
|
setupHint: wallet.deletedAt ? "This Agent Wallet is archived and pending hard-delete. Restore it from the dashboard before sending." : void 0
|
|
2569
2777
|
};
|
|
@@ -3288,8 +3496,8 @@ async function main() {
|
|
|
3288
3496
|
return { content: [jsonText(await runClearDelegation(parsed))] };
|
|
3289
3497
|
}
|
|
3290
3498
|
case "q402_agentic_info": {
|
|
3291
|
-
AgenticInfoInputSchema.parse(args ?? {});
|
|
3292
|
-
return { content: [jsonText(await runAgenticInfo())] };
|
|
3499
|
+
const parsed = AgenticInfoInputSchema.parse(args ?? {});
|
|
3500
|
+
return { content: [jsonText(await runAgenticInfo(parsed))] };
|
|
3293
3501
|
}
|
|
3294
3502
|
case "q402_recurring_list": {
|
|
3295
3503
|
const parsed = RecurringListInputSchema.parse(args ?? {});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"description": "MCP server for Q402 — gasless USDC, USDT, and RLUSD payments across 9 EVM chains, callable from Claude (Desktop / Code), OpenAI Codex CLI, and any other Model Context Protocol client.",
|
|
5
5
|
"mcpName": "io.github.bitgett/q402-mcp",
|
|
6
6
|
"keywords": [
|