@quackai/q402-mcp 0.8.38 → 0.8.40

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.
Files changed (2) hide show
  1. package/dist/index.js +19 -3
  2. 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
  // package.json
212
212
  var package_default = {
213
213
  name: "@quackai/q402-mcp",
214
- version: "0.8.38",
214
+ version: "0.8.40",
215
215
  description: "MCP server for Q402 \u2014 gasless USDC/USDT/RLUSD payments on 11 EVM chains + Chainlink CCIP USDC bridge on the eth/avax/arbitrum triangle, callable from Claude (Desktop / Code), OpenAI Codex CLI, and any other Model Context Protocol client.",
216
216
  mcpName: "io.github.bitgett/q402-mcp",
217
217
  keywords: [
@@ -974,6 +974,9 @@ function checkConsent(intent, provided) {
974
974
  // src/tools/pay.ts
975
975
  var PayInputSchema = z2.object({
976
976
  chain: z2.enum(["avax", "bnb", "eth", "xlayer", "stable", "mantle", "injective", "monad", "scroll", "arbitrum", "base"]),
977
+ rail: z2.enum(["q402", "x402"]).optional().describe(
978
+ 'Settlement rail. Base only \u2014 leave unset everywhere else. "q402" (default) = Q402 gasless EIP-7702 (USDC + USDT). "x402" = the Coinbase x402 standard (EIP-3009 USDC transferWithAuthorization), settled gaslessly by the Q402 facilitator \u2014 Base USDC only, no Hooks. walletMode="agentic-server" only.'
979
+ ),
977
980
  to: z2.string().refine(isAddress2, "to must be a valid 0x-prefixed EVM address").describe("Recipient EVM address (0x + 40 hex)."),
978
981
  amount: z2.string().regex(/^\d+(\.\d+)?$/, "amount must be a positive decimal string").describe('Human-readable decimal amount, e.g. "5.00".'),
979
982
  token: z2.enum(["USDC", "USDT", "RLUSD"]).describe(
@@ -1139,6 +1142,12 @@ async function runPay(input) {
1139
1142
  to: input.to.toLowerCase(),
1140
1143
  amount: input.amount,
1141
1144
  token: input.token,
1145
+ // Bind the settlement RAIL. On Base the same (to, amount, token) settles
1146
+ // very differently under q402 (EIP-7702) vs x402 (EIP-3009) — different
1147
+ // signature scheme, gas path, and wallet-state constraints. Consenting to a
1148
+ // Q402-rail preview must NOT authorise an x402 execution on the same token,
1149
+ // so a rail change invalidates the consent and forces a fresh preview.
1150
+ rail: input.rail ?? "q402",
1142
1151
  // Bind the funding source too — the user is consenting to spend from THIS
1143
1152
  // wallet, so a different walletMode/walletId needs a fresh preview.
1144
1153
  wm: effectiveMode,
@@ -1154,13 +1163,14 @@ async function runPay(input) {
1154
1163
  if (!consent.ok) {
1155
1164
  const splitNote = input.hookParams?.splits ? ` \u2014 split ${input.hookParams.splits.length} ways; funds go to the split recipients, not ${input.to}` : "";
1156
1165
  const fromNote = senderWallet ? ` from ${senderWallet.addressShort}` : "";
1166
+ const railNote = input.rail === "x402" ? " via the x402 (EIP-3009) rail" : "";
1157
1167
  return {
1158
1168
  result: failureResult("consent"),
1159
1169
  guardsApplied: [...guardsApplied, "two_phase_consent"],
1160
1170
  senderWallet,
1161
1171
  needsConsent: {
1162
1172
  status: "needs_confirmation",
1163
- preview: `Send ${input.amount} ${input.token} to ${input.to} on ${chain.key}${fromNote}${splitNote}. Confirm with the user, then re-call q402_pay with the same args plus consentToken="${consent.expected}".`,
1173
+ preview: `Send ${input.amount} ${input.token} to ${input.to} on ${chain.key}${railNote}${fromNote}${splitNote}. Confirm with the user, then re-call q402_pay with the same args plus consentToken="${consent.expected}".`,
1164
1174
  consentToken: consent.expected
1165
1175
  }
1166
1176
  };
@@ -1227,7 +1237,8 @@ async function runPay(input) {
1227
1237
  // the per-wallet hook dispatch, so forwarding here is the only
1228
1238
  // place hookParams take effect. The landing route ignores them
1229
1239
  // for owner-sig calls (trust boundary), so this is safe.
1230
- ...input.hookParams ? { hookParams: input.hookParams } : {}
1240
+ ...input.hookParams ? { hookParams: input.hookParams } : {},
1241
+ ...input.rail ? { rail: input.rail } : {}
1231
1242
  }),
1232
1243
  signal: AbortSignal.timeout(6e4)
1233
1244
  });
@@ -1413,6 +1424,11 @@ var PAY_TOOL = {
1413
1424
  enum: CHAIN_KEYS,
1414
1425
  description: "Target chain."
1415
1426
  },
1427
+ rail: {
1428
+ type: "string",
1429
+ enum: ["q402", "x402"],
1430
+ description: 'Settlement rail (Base only). "q402" (default) = gasless EIP-7702 (USDC+USDT). "x402" = Coinbase x402 standard (EIP-3009), Base USDC only, agentic-server only. Leave unset elsewhere.'
1431
+ },
1416
1432
  to: {
1417
1433
  type: "string",
1418
1434
  description: "Recipient EVM address (0x + 40 hex)."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quackai/q402-mcp",
3
- "version": "0.8.38",
3
+ "version": "0.8.40",
4
4
  "description": "MCP server for Q402 — gasless USDC/USDT/RLUSD payments on 11 EVM chains + Chainlink CCIP USDC bridge on the eth/avax/arbitrum triangle, 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": [