@quackai/q402-mcp 0.5.15 → 0.5.16

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 +10 -11
  2. package/dist/index.js +15 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -165,10 +165,10 @@ Then export the values in `~/.zshrc` / `~/.bashrc`. See the [Codex config refere
165
165
 
166
166
  By default the MCP server operates in **sandbox mode**: `q402_pay` returns a random fake transaction hash with `success: false` and `sandbox: true`, no funds move, no gas-tank credit is consumed. That makes it safe to plug into any MCP client without worrying about an accidental payment — if the agent misreads the conversation and fires `q402_pay` before you intended, nothing moves AND the response cannot be mistaken for a confirmed settlement.
167
167
 
168
- To enable real on-chain transactions, the resolved API key must be live (`q402_live_*`), `Q402_PRIVATE_KEY` must be set to a valid 32-byte hex key, and `Q402_ENABLE_REAL_PAYMENTS=1`. The block below is the template `q402_doctor` writes to `~/.q402/mcp.env` — every secret line is commented out and the live flag defaults to `1`. Uncomment the lines you need and paste real values in your editor; the live-mode gate only flips once a real key + valid PK are present, so saving the template as-is stays in sandbox. Change the flag to `0` if you want to force sandbox even with real keys (e.g. for chained testing on a paid plan):
168
+ To enable real on-chain transactions, the resolved API key must be live (`q402_live_*`), `Q402_PRIVATE_KEY` must be set to a valid 32-byte hex key, and `Q402_ENABLE_REAL_PAYMENTS=1`. The block below is the template `q402_doctor` writes to `~/.q402/mcp.env` — the three secret lines ship empty (no `#` to remove, just paste the value on the right of `=`) and the live flag defaults to `1`. The live-mode gate only flips once a real key + valid 32-byte PK are populated, so saving the template as-is stays in sandbox automatically. Change the flag to `0` if you want to force sandbox even with real keys (e.g. for chained testing on a paid plan):
169
169
 
170
170
  ```bash
171
- # Two-key model — uncomment ONE (or both for auto-routing).
171
+ # Two-key model — fill ONE (or both for auto-routing).
172
172
  # Auto-routing (same for q402_pay AND q402_batch_pay):
173
173
  # chain="bnb" + Q402_TRIAL_API_KEY set → Trial (free sponsored)
174
174
  # anything else → Multichain (paid 9-chain)
@@ -176,20 +176,19 @@ To enable real on-chain transactions, the resolved API key must be live (`q402_l
176
176
  # status="ambiguous" instead of executing — agent asks user to pick.
177
177
  # Override per call with keyScope: "auto" | "trial" | "multichain".
178
178
 
179
- # Q402_TRIAL_API_KEY=q402_live_... # BNB-only sponsored Trial key (from /event)
180
- # Q402_MULTICHAIN_API_KEY=q402_live_... # paid 9-chain key (per-chain Gas Tank)
179
+ Q402_TRIAL_API_KEY= # BNB-only sponsored Trial key (from /event)
180
+ Q402_MULTICHAIN_API_KEY= # paid 9-chain key (per-chain Gas Tank)
181
181
 
182
- # Q402_PRIVATE_KEY=0x... # signer for the payer EOA (32-byte hex)
182
+ Q402_PRIVATE_KEY= # signer for the payer EOA (0x + 64 hex chars)
183
183
 
184
184
  # Live mode switch:
185
185
  # 0 = sandbox (test mode, no funds move — every q402_pay returns a fake hash)
186
186
  # 1 = real on-chain payments (live mode)
187
- # Default is 1: real payments enabled. Safe because mode only flips
188
- # to live when BOTH a live API key (q402_live_*) AND a valid 32-byte
189
- # private key are set above. Placeholders ("0x...") are rejected by
190
- # the live-mode gate, so partial setups stay in sandbox with a hint.
191
- # Change to 0 to force sandbox even with real keys (e.g. for chained
192
- # testing on a paid plan).
187
+ # Default 1: real payments enabled. Safe because mode only flips to live
188
+ # when BOTH a live API key (q402_live_*) AND a valid 32-byte private
189
+ # key are populated above. Empty values fail the gate, so partial setups
190
+ # stay in sandbox with a hint. Change to 0 to force sandbox even with
191
+ # real keys (e.g. for chained testing on a paid plan).
193
192
  Q402_ENABLE_REAL_PAYMENTS=1
194
193
  ```
195
194
 
package/dist/index.js CHANGED
@@ -121,7 +121,8 @@ function loadConfig() {
121
121
  const apiKeyKind = classifyApiKey(apiKey);
122
122
  const privateKey = ENV.Q402_PRIVATE_KEY ?? null;
123
123
  const realPaymentsRequested = ENV.Q402_ENABLE_REAL_PAYMENTS === "1";
124
- const live = realPaymentsRequested && apiKeyKind === "live" && typeof privateKey === "string" && privateKey.length > 0;
124
+ const anyLiveKey = classifyApiKey(trialApiKey) === "live" || classifyApiKey(multichainApiKey) === "live" || classifyApiKey(legacyApiKey) === "live";
125
+ const live = realPaymentsRequested && anyLiveKey && typeof privateKey === "string" && privateKey.length > 0;
125
126
  return {
126
127
  trialApiKey,
127
128
  multichainApiKey,
@@ -187,7 +188,7 @@ var isValidPrivateKey = (s) => typeof s === "string" && PRIVATE_KEY_RE.test(s);
187
188
 
188
189
  // src/version.ts
189
190
  var PACKAGE_NAME = "@quackai/q402-mcp";
190
- var PACKAGE_VERSION = "0.5.15";
191
+ var PACKAGE_VERSION = "0.5.16";
191
192
 
192
193
  // src/tools/quote.ts
193
194
  import { z } from "zod";
@@ -1043,6 +1044,16 @@ async function runBatchPay(input) {
1043
1044
  }
1044
1045
  }
1045
1046
  const scopeRequest = input.keyScope ?? "auto";
1047
+ if (scopeRequest === "trial" && input.recipients.length > RECIPIENT_LIMIT_TRIAL) {
1048
+ guardsApplied.push("trial_cap_exceeded");
1049
+ return {
1050
+ mode: "none",
1051
+ status: "trial_cap_exceeded",
1052
+ guardsApplied,
1053
+ senderWallet,
1054
+ setupHint: `keyScope="trial" caps at ${RECIPIENT_LIMIT_TRIAL} recipients per call (BNB-only sponsored). Your batch has ${input.recipients.length}. Either trim to the first ${RECIPIENT_LIMIT_TRIAL} recipients and re-invoke with keyScope="trial", or send the full batch on the paid Multichain key by re-invoking with keyScope="multichain" (charges the paid pool + Gas Tank, up to ${RECIPIENT_LIMIT_PAID} per call).`
1055
+ };
1056
+ }
1046
1057
  if (scopeRequest === "auto" && input.chain === "bnb" && CONFIG.trialApiKey && input.recipients.length > RECIPIENT_LIMIT_TRIAL) {
1047
1058
  const overflow = input.recipients.length - RECIPIENT_LIMIT_TRIAL;
1048
1059
  guardsApplied.push("batch_cap_ambiguous");
@@ -1722,11 +1733,12 @@ function mask2(key) {
1722
1733
  }
1723
1734
  function detectPhase() {
1724
1735
  const anyKey = !!(CONFIG.trialApiKey || CONFIG.multichainApiKey || CONFIG.legacyApiKey);
1736
+ const anyLiveKey = classifyApiKey(CONFIG.trialApiKey) === "live" || classifyApiKey(CONFIG.multichainApiKey) === "live" || classifyApiKey(CONFIG.legacyApiKey) === "live";
1725
1737
  const hasValidPrivateKey = isValidPrivateKey(CONFIG.privateKey);
1726
1738
  if (!Q402_ENV_FILE_PRESENT && !anyKey && !CONFIG.privateKey) {
1727
1739
  return "first-install";
1728
1740
  }
1729
- const allEssentials = anyKey && hasValidPrivateKey && CONFIG.realPaymentsRequested && CONFIG.apiKeyKind === "live";
1741
+ const allEssentials = anyKey && hasValidPrivateKey && CONFIG.realPaymentsRequested && anyLiveKey;
1730
1742
  if (allEssentials) return "live-check";
1731
1743
  if (anyKey || CONFIG.privateKey || Q402_ENV_FILE_PRESENT) return "needs-completion";
1732
1744
  return "first-install";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quackai/q402-mcp",
3
- "version": "0.5.15",
3
+ "version": "0.5.16",
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": [