@quackai/q402-mcp 0.5.9 → 0.5.11

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 (3) hide show
  1. package/README.md +25 -8
  2. package/dist/index.js +47 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -65,8 +65,12 @@ Create `~/.q402/mcp.env` yourself. The template below matches what `q402_doctor`
65
65
  # Hardware wallets (Ledger / Trezor) are not supported yet.
66
66
  # Q402_PRIVATE_KEY=0x...
67
67
 
68
- # Start at 0 (sandbox). Flip to 1 only after real values are pasted above.
69
- Q402_ENABLE_REAL_PAYMENTS=0
68
+ # Live mode switch:
69
+ # 0 = sandbox (test mode, no funds move)
70
+ # 1 = real on-chain payments
71
+ # Default 1 — safe because mode only flips to live when BOTH a live
72
+ # API key AND a valid 32-byte private key are uncommented above.
73
+ Q402_ENABLE_REAL_PAYMENTS=1
70
74
 
71
75
  # Default Q402 deployment. Only change for self-hosted.
72
76
  Q402_RELAY_BASE_URL=https://q402.quackai.ai/api
@@ -132,9 +136,11 @@ Then export the values in `~/.zshrc` / `~/.bashrc`. See the [Codex config refere
132
136
 
133
137
  `q402_receipt` is the natural follow-up: after `q402_pay` returns a `receiptUrl`, hand the agent the `rct_…` id and ask *"verify this receipt"* — the tool re-runs the same canonical-JSON + EIP-191 recovery the receipt page does in the browser, so the verification doesn't depend on trusting any UI. Example prompts that work today:
134
138
 
135
- > *"Pay 0.10 USDT on BNB to vitalik.eth, then verify the receipt."*
139
+ > *"Pay 0.10 USDT on BNB to 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045, then verify the receipt."*
136
140
  > *"Is `rct_afa5f50bc49a65ebba3b28ab` a real Q402 receipt? Verify the signature."*
137
141
 
142
+ > ℹ️ `q402_pay` takes a 0x-prefixed EVM address — ENS names are not resolved by the tool. If your prompt mentions a name like `vitalik.eth`, your AI client needs to resolve it client-side before invoking the tool.
143
+
138
144
  > Per-chain gas tank balances and full transaction history live in the [dashboard](https://q402.quackai.ai/dashboard) — those endpoints require a wallet signature, not a bare API key, so the MCP server points the agent there instead of exposing them.
139
145
 
140
146
  ---
@@ -159,10 +165,16 @@ To enable real on-chain transactions, the resolved API key must be live (`q402_l
159
165
 
160
166
  # Q402_PRIVATE_KEY=0x... # signer for the payer EOA (32-byte hex)
161
167
 
162
- # Start at 0 (sandbox). Flip to 1 only after real values are pasted above —
163
- # a malformed Q402_PRIVATE_KEY (e.g. the "0x..." placeholder) is rejected at
164
- # the live-mode gate, so partial setups stay in sandbox with a clear hint.
165
- Q402_ENABLE_REAL_PAYMENTS=0
168
+ # Live mode switch:
169
+ # 0 = sandbox (test mode, no funds move every q402_pay returns a fake hash)
170
+ # 1 = real on-chain payments (live mode)
171
+ # Default is 1: real payments enabled. Safe because mode only flips
172
+ # to live when BOTH a live API key (q402_live_*) AND a valid 32-byte
173
+ # private key are set above. Placeholders ("0x...") are rejected by
174
+ # the live-mode gate, so partial setups stay in sandbox with a hint.
175
+ # Change to 0 to force sandbox even with real keys (e.g. for chained
176
+ # testing on a paid plan).
177
+ Q402_ENABLE_REAL_PAYMENTS=1
166
178
  ```
167
179
 
168
180
  Anything missing for the resolved scope → automatic sandbox fallback with a hint pointing at what to set.
@@ -194,7 +206,12 @@ Combined with the `confirm: true` argument the tool requires, this means the mod
194
206
  | `Q402_ALLOWED_RECIPIENTS` | optional | Comma-separated lowercase addresses. Defaults to no allowlist. |
195
207
  | `Q402_RELAY_BASE_URL` | optional | Defaults to `https://q402.quackai.ai/api`. Override for self-hosted Q402. |
196
208
 
197
- > Older integrations may still set `Q402_API_KEY` as a single-env fallback — that still works silently for back-compat. New setups should use the two-key model above; `q402_doctor` only guides users to those two.
209
+ <details>
210
+ <summary>Migrating from legacy single-key setups</summary>
211
+
212
+ If you set up Q402 before v0.5.0 you may have a single `Q402_API_KEY` env var. The server still resolves that silently — your existing integration won't break. New installs should use the two-key model above (`Q402_TRIAL_API_KEY` and/or `Q402_MULTICHAIN_API_KEY`); `q402_doctor` and the rest of the docs only guide users to those two. To migrate, rename your existing var to `Q402_MULTICHAIN_API_KEY` in `~/.q402/mcp.env` and restart your MCP client.
213
+
214
+ </details>
198
215
 
199
216
  ---
200
217
 
package/dist/index.js CHANGED
@@ -168,7 +168,7 @@ var isValidPrivateKey = (s) => typeof s === "string" && PRIVATE_KEY_RE.test(s);
168
168
 
169
169
  // src/version.ts
170
170
  var PACKAGE_NAME = "@quackai/q402-mcp";
171
- var PACKAGE_VERSION = "0.5.9";
171
+ var PACKAGE_VERSION = "0.5.11";
172
172
 
173
173
  // src/tools/quote.ts
174
174
  import { z } from "zod";
@@ -504,7 +504,7 @@ var Q402NodeClient = class _Q402NodeClient {
504
504
  }
505
505
  async fetchFacilitator() {
506
506
  const url = `${this.opts.relayBaseUrl.replace(/\/$/, "")}/relay/info`;
507
- const resp = await fetch(url);
507
+ const resp = await fetch(url, { signal: AbortSignal.timeout(1e4) });
508
508
  if (!resp.ok) {
509
509
  throw new Error(
510
510
  `failed to fetch relay facilitator info from ${url} (${resp.status})`
@@ -578,7 +578,8 @@ var Q402NodeClient = class _Q402NodeClient {
578
578
  const resp = await fetch(`${relayBaseUrl.replace(/\/$/, "")}/relay`, {
579
579
  method: "POST",
580
580
  headers: { "Content-Type": "application/json" },
581
- body: JSON.stringify(body)
581
+ body: JSON.stringify(body),
582
+ signal: AbortSignal.timeout(3e4)
582
583
  });
583
584
  const data = await resp.json();
584
585
  if (!resp.ok) {
@@ -699,7 +700,8 @@ var Q402NodeClient = class _Q402NodeClient {
699
700
  token,
700
701
  facilitator,
701
702
  recipients: signedRows
702
- })
703
+ }),
704
+ signal: AbortSignal.timeout(6e4)
703
705
  });
704
706
  const data = await resp.json();
705
707
  if (!resp.ok || data.ok === false) {
@@ -1129,7 +1131,7 @@ async function runBalance() {
1129
1131
  if (CONFIG.trialApiKey) targets.push({ scope: "trial", key: CONFIG.trialApiKey });
1130
1132
  if (CONFIG.multichainApiKey) targets.push({ scope: "multichain", key: CONFIG.multichainApiKey });
1131
1133
  if (targets.length === 0 && CONFIG.legacyApiKey) {
1132
- targets.push({ scope: "legacy", key: CONFIG.legacyApiKey });
1134
+ targets.push({ scope: "multichain", key: CONFIG.legacyApiKey });
1133
1135
  }
1134
1136
  if (targets.length === 0) {
1135
1137
  return {
@@ -1559,11 +1561,15 @@ var ENV_FILE_TEMPLATE = `# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
1559
1561
  # your machine \u2014 never leaves your device, never sent to any server.
1560
1562
  # Q402_PRIVATE_KEY=0x...
1561
1563
 
1562
- # \u2500\u2500\u2500 Live mode flag \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1563
- # Default 0 = sandbox (test responses, no funds move). Flip to 1 only
1564
- # AFTER you've pasted real values into the lines above \u2014 otherwise the
1565
- # server will refuse the placeholders.
1566
- Q402_ENABLE_REAL_PAYMENTS=0
1564
+ # \u2500\u2500\u2500 Live mode switch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1565
+ # 0 = sandbox (test mode, no funds move \u2014 every q402_pay returns a fake hash)
1566
+ # 1 = real on-chain payments (live mode)
1567
+ # Default is 1: real payments enabled. This is safe because mode only
1568
+ # flips to live when BOTH a live API key (q402_live_*) AND a valid
1569
+ # 32-byte private key are set above. Until you uncomment + paste both,
1570
+ # you stay in sandbox. Change to 0 to force sandbox even with real
1571
+ # keys (e.g. for chained testing on a paid plan).
1572
+ Q402_ENABLE_REAL_PAYMENTS=1
1567
1573
 
1568
1574
  # \u2500\u2500\u2500 Q402 relay endpoint \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1569
1575
  # Default canonical Q402 deployment. Only change for self-hosted.
@@ -1774,7 +1780,21 @@ async function runDoctor() {
1774
1780
  warnings,
1775
1781
  recommendedActions,
1776
1782
  greeting: phase === "first-install" ? `Q402 MCP is installed (v${PACKAGE_VERSION}).` : `Q402 MCP is installed (v${PACKAGE_VERSION}) \u2014 partially configured.`,
1777
- nextStep: phase === "first-install" ? "Offer to create ~/.q402/mcp.env. After yes, execute recommendedActions in order: first the `ensure-q402-dir` shell action (use bash on macOS/Linux, PowerShell on Windows via the shellWindows variant), then the `create-env-file` write_file action. Then open the file in the user's editor \u2014 `code` works for VS Code / Cursor / Cline (e.g. `code ~/.q402/mcp.env`); `open` on macOS, `start` on Windows, `xdg-open` on Linux as fallback. Walk through filling in the API key (from /event for free Trial or /payment for paid Multichain) and private key one at a time. Do NOT accept key values via chat \u2014 direct the user to edit the file in their editor. BEFORE they paste a private key, surface the `advisories` array: use a fresh wallet (not their main one), heads-up that the wallet will show 'Smart account' in MetaMask after the first payment (that's normal \u2014 EIP-7702 delegation), hardware wallets aren't supported, MetaMask key export path." : `Tell the user which env vars are still missing (from the 'missing' list) and how to add them to ~/.q402/mcp.env. Restart needed after editing. Per-client restart verb: Claude Desktop \u2192 quit + relaunch; Codex \u2192 exit + relaunch; Cursor \u2192 Cmd/Ctrl+Shift+P \u2192 "Developer: Reload Window"; Cline \u2192 reload VS Code window.`,
1783
+ nextStep: phase === "first-install" ? "Show userInstructions verbatim to the user; do NOT show agentInstructions verbatim (it's prescription for you, the AI)." : "Tell the user which env vars are still missing (from the 'missing' list) and how to add them to ~/.q402/mcp.env. Show userInstructions for the human-readable steps.",
1784
+ agentInstructions: phase === "first-install" ? "Multi-turn flow: (1) Briefly tell the user MCP is installed. (2) Ask one yes/no question \u2014 'Want me to create your Q402 settings file?'. (3) On yes, execute recommendedActions IN ORDER: first `ensure-q402-dir` shell action (bash on macOS/Linux, PowerShell on Windows via shellWindows variant), then `create-env-file` write_file action. (4) Open the file in the user's editor \u2014 `code` works for VS Code / Cursor / Cline (e.g. `code ~/.q402/mcp.env`); `open` on macOS, `start` on Windows, `xdg-open` on Linux as fallback. (5) Walk through filling in the API key (from /event for free Trial or /payment for paid Multichain) and private key one at a time. (6) Do NOT accept key values via chat \u2014 direct the user to edit the file in their editor. BEFORE they paste a private key, surface the `advisories` array: fresh wallet, Smart-account-in-MetaMask heads-up, hardware wallets unsupported, MetaMask key-export path. (7) After they save, tell them to restart the MCP client \u2014 per-client restart verb: Claude Desktop \u2192 quit + relaunch; Codex \u2192 exit + relaunch; Cursor \u2192 Cmd/Ctrl+Shift+P \u2192 'Developer: Reload Window'; Cline \u2192 reload VS Code window. (8) Have them re-invoke 'Set up Q402' to confirm. Keep the conversation tight: one decision per turn, plain language, never echo this paragraph." : "User has SOME env set. List the missing items (from `missing`) in plain language. Tell them to edit ~/.q402/mcp.env and uncomment / fill the relevant line, then restart the MCP client. Restart verb per client: Claude Desktop \u2192 quit + relaunch; Codex \u2192 exit + relaunch; Cursor \u2192 Cmd/Ctrl+Shift+P \u2192 'Developer: Reload Window'; Cline \u2192 reload VS Code window.",
1785
+ userInstructions: phase === "first-install" ? [
1786
+ "Q402 is installed. To start sending payments you need an API key and a wallet.",
1787
+ "I'll create a settings file for you \u2014 say yes and I'll set it up + open it in your editor.",
1788
+ "Get a free API key at https://q402.quackai.ai/event (BNB Chain only, 2,000 sponsored transactions).",
1789
+ "Use a FRESH wallet for Q402 \u2014 don't use your main wallet. The wallet will be marked 'Smart account' in MetaMask after your first payment (that's normal \u2014 Q402 reverses it on demand).",
1790
+ "Paste your key + wallet private key INTO THE FILE (in your editor) \u2014 never paste a private key into this chat.",
1791
+ "Save the file, restart your MCP client, then ask me 'Verify Q402' to confirm."
1792
+ ] : [
1793
+ "Q402 is installed but a few env vars are still missing.",
1794
+ "Open ~/.q402/mcp.env in your editor and fill in the lines I list below.",
1795
+ "Save the file, then restart your MCP client (close + reopen Claude/Codex, or Cmd/Ctrl+Shift+P \u2192 Reload Window for Cursor/Cline).",
1796
+ "Then ask me 'Verify Q402' to re-check."
1797
+ ],
1778
1798
  securityNotice: SECURITY_NOTICE,
1779
1799
  advisories: phase === "first-install" ? FIRST_INSTALL_ADVISORY : void 0
1780
1800
  };
@@ -1838,13 +1858,26 @@ async function runDoctor() {
1838
1858
  warnings,
1839
1859
  recommendedActions,
1840
1860
  greeting: ready ? `Q402 MCP is ready (v${PACKAGE_VERSION}).` : `Q402 MCP is installed but has ${warnings.length} issue${warnings.length === 1 ? "" : "s"} to address.`,
1841
- nextStep: ready ? "Summarize the wallet address, plan tier(s), remaining quota, and any non-zero delegation counts to the user as a checklist. Then offer to make a test payment via q402_quote." : "Walk the user through each warning in order. For slot-mismatch warnings, the fix is editing ~/.q402/mcp.env and restarting the client.",
1842
- securityNotice: SECURITY_NOTICE
1861
+ nextStep: ready ? "Show userInstructions verbatim. Then offer to make a small test quote (q402_quote) to confirm everything works end-to-end." : "Walk the user through each warning in order. Show userInstructions verbatim for the cleanup steps.",
1862
+ agentInstructions: ready ? "Live mode is fully configured. Summarize the wallet address (mask middle), plan tier(s), remaining quota, and any non-zero delegation counts to the user as a checklist. Offer a tiny test (q402_quote, not q402_pay) to confirm. Don't echo the full keys array verbatim \u2014 pick the most useful 2-3 fields per scope." : "Walk the user through each warning IN ORDER, plain language. For slot-mismatch warnings, the fix is editing ~/.q402/mcp.env and restarting the client (Cursor / Cline: reload window; Claude / Codex: quit + relaunch). Surface body.error strings from any verify failure as the user-visible reason (e.g. 'your Trial expired 3 days ago', 'API key has been rotated') \u2014 don't generic-out to 'check the key value'.",
1863
+ userInstructions: ready ? [
1864
+ `Your wallet: ${walletAddress ? walletAddress.slice(0, 6) + "\u2026" + walletAddress.slice(-4) : "(derive failed \u2014 check Q402_PRIVATE_KEY)"}`,
1865
+ "Q402 is live. You can now ask me to quote, pay, batch-pay, or check Trust Receipts.",
1866
+ "Want me to run a quick gas comparison across all 9 chains as a smoke test?"
1867
+ ] : [
1868
+ `Q402 has ${warnings.length} issue${warnings.length === 1 ? "" : "s"} to fix:`,
1869
+ ...warnings.map((w) => `\u2022 ${w}`),
1870
+ "Open ~/.q402/mcp.env, fix the lines above, save, then restart your MCP client (Cursor/Cline: Cmd/Ctrl+Shift+P \u2192 Reload Window; Claude/Codex: quit + relaunch). Then ask me 'Verify Q402' to re-check."
1871
+ ],
1872
+ securityNotice: SECURITY_NOTICE,
1873
+ // advisories are first-install-only by design — explicitly set to undefined
1874
+ // here so future maintainers see the conditional rather than an absent key.
1875
+ advisories: void 0
1843
1876
  };
1844
1877
  }
1845
1878
  var DOCTOR_TOOL = {
1846
1879
  name: "q402_doctor",
1847
- description: 'Run a Q402 health check \u2014 covers first-install onboarding AND ongoing diagnostics in one tool. Read-only, no API key required. Detects the current phase (first-install / needs-completion / live-check) and tailors output to it. \n\nUse when the user says any of: "set up Q402", "verify Q402", "why isn\'t Q402 working", "Q402 status", "check Q402". This is the FIRST tool to call after install, BEFORE q402_pay or q402_balance \u2014 it tells the agent what state the user is in. \n\nMulti-turn pattern the AI should follow when phase = first-install: (1) Tell user MCP is installed. (2) Ask one yes/no question: \'Want me to create your secrets file at ~/.q402/mcp.env?\' (3) On yes, execute the recommendedActions[].write_file action using the client\'s own filesystem tool, then open the file in the user\'s editor (e.g. `code ~/.q402/mcp.env`, `open` on macOS, `start` on Windows, `xdg-open` on Linux). (4) Guide the user through getting an API key (free Trial at https://q402.quackai.ai/event OR paid Multichain at /payment) and pasting it into the file (in their editor \u2014 NEVER in chat). (5) Same for the private key. (6) Tell them to save + restart the MCP client. (7) Call q402_doctor again to verify. \n\nSecurity policy carried in the response: AI MUST surface the securityNotice when first walking through setup. If the user pastes a private key directly in chat, DO NOT refuse \u2014 the exposure already happened. Help them by directing them to put it in the file themselves (via their editor), and inform them the chat history now contains the key (most clients store this locally, some sync to cloud) so they should treat the wallet as exposed if it holds valuables. \n\nLive-check phase additionally returns per-scope quota, EIP-7702 delegation state per chain, relay reachability, and slot-mismatch warnings (e.g. Trial key in Multichain slot silently burns paid quota \u2014 surface this to the user).',
1880
+ description: 'Run a Q402 health check \u2014 covers first-install onboarding AND ongoing diagnostics in one tool. Read-only, no API key required. Detects the current phase (first-install / needs-completion / live-check) and tailors output to it. \n\nUse when the user says any of: "set up Q402", "verify Q402", "why isn\'t Q402 working", "Q402 status", "check Q402". This is the FIRST tool to call after install, BEFORE q402_pay or q402_balance \u2014 it tells the agent what state the user is in. \n\nOutput uses TWO instruction surfaces \u2014 `agentInstructions` (prescription for you, the AI \u2014 do NOT echo verbatim) and `userInstructions` (plain language array you CAN show the user as a numbered list). Always show userInstructions; consult agentInstructions privately to decide what to ask next + which `recommendedActions` to execute. \n\nMulti-turn pattern the AI should follow when phase = first-install: (1) Tell user MCP is installed. (2) Ask one yes/no question: \'Want me to create your secrets file?\' (3) On yes, execute recommendedActions IN ORDER \u2014 first the `ensure-q402-dir` shell action (use shellWindows on Windows), then the `create-env-file` write_file action. Then open the file in the user\'s editor (e.g. `code` for VS Code / Cursor / Cline, `open` on macOS, `start` on Windows, `xdg-open` on Linux). (4) Guide the user through getting an API key (free Trial at https://q402.quackai.ai/event OR paid Multichain at /payment) and pasting it into the file (in their editor \u2014 NEVER in chat). (5) Same for the private key. (6) Tell them to save + restart the MCP client (per-client restart verb is in agentInstructions). (7) Call q402_doctor again to verify. \n\nSecurity policy carried in the response: AI MUST surface the securityNotice when first walking through setup. If the user pastes a private key directly in chat, DO NOT refuse \u2014 the exposure already happened. Help them by directing them to put it in the file themselves (via their editor), and inform them the chat history now contains the key (most clients store this locally, some sync to cloud) so they should treat the wallet as exposed if it holds valuables. \n\nLive-check phase additionally returns per-scope quota, EIP-7702 delegation state per chain, relay reachability, and slot-mismatch warnings (e.g. Trial key in Multichain slot silently burns paid quota \u2014 surface this to the user).',
1848
1881
  inputSchema: {
1849
1882
  type: "object",
1850
1883
  properties: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quackai/q402-mcp",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
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": [