@quackai/q402-mcp 0.4.3 → 0.4.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/README.md +10 -7
- package/dist/index.js +33 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -76,10 +76,13 @@ command = "npx"
|
|
|
76
76
|
args = ["-y", "@quackai/q402-mcp"]
|
|
77
77
|
startup_timeout_sec = 20.0
|
|
78
78
|
env = {
|
|
79
|
-
# Two-key model (v0.4.
|
|
79
|
+
# Two-key model (v0.4.4+): set whichever applies — both is best.
|
|
80
80
|
# The server auto-routes by chain: BNB → trial key, else multichain key.
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
# Both keys use the same q402_live_ prefix — the env var name is what
|
|
82
|
+
# carries the scope, not the key string. Get the values from the
|
|
83
|
+
# dashboard (each key has its own copy button per view).
|
|
84
|
+
Q402_TRIAL_API_KEY = "q402_live_...", # BNB-only sponsored (from /event)
|
|
85
|
+
Q402_MULTICHAIN_API_KEY = "q402_live_...", # paid 8-chain (from /payment)
|
|
83
86
|
# Legacy fallback — used if neither scoped key above is set.
|
|
84
87
|
Q402_API_KEY = "q402_live_...",
|
|
85
88
|
Q402_PRIVATE_KEY = "0xabc...",
|
|
@@ -130,14 +133,14 @@ By default the MCP server operates in **sandbox mode**: `q402_pay` returns a det
|
|
|
130
133
|
To enable real on-chain transactions, the resolved API key must be live (`q402_live_*`), `Q402_PRIVATE_KEY` must be set, and `Q402_ENABLE_REAL_PAYMENTS=1`:
|
|
131
134
|
|
|
132
135
|
```bash
|
|
133
|
-
# Two-key model (v0.4.
|
|
136
|
+
# Two-key model (v0.4.4+) — set whichever applies. Both is best.
|
|
134
137
|
# Auto-routing: chain="bnb" → trial key (if set), otherwise multichain key.
|
|
135
138
|
# Override per call with keyScope: "auto" | "trial" | "multichain".
|
|
136
|
-
Q402_TRIAL_API_KEY=
|
|
139
|
+
Q402_TRIAL_API_KEY=q402_live_... # BNB-only sponsored Trial key (from /event)
|
|
137
140
|
Q402_MULTICHAIN_API_KEY=q402_live_... # paid 8-chain key (per-chain Gas Tank)
|
|
138
141
|
|
|
139
142
|
# Legacy fallback. Used for both scopes when the two above are unset —
|
|
140
|
-
# pre-v0.4.
|
|
143
|
+
# pre-v0.4.4 users keep working without any config change.
|
|
141
144
|
Q402_API_KEY=q402_live_...
|
|
142
145
|
|
|
143
146
|
Q402_PRIVATE_KEY=0xabc... # signer for the payer EOA
|
|
@@ -165,7 +168,7 @@ Combined with the `confirm: true` argument the tool requires, this means the mod
|
|
|
165
168
|
|---|---|---|
|
|
166
169
|
| `Q402_TRIAL_API_KEY` | live-pay (BNB) | BNB-only sponsored Trial key. Free at https://q402.quackai.ai/event. Used automatically for `chain="bnb"` when set. |
|
|
167
170
|
| `Q402_MULTICHAIN_API_KEY` | live-pay (8-chain) | Paid 8-chain key. Get one at https://q402.quackai.ai/payment. Used for all non-BNB chains and for BNB when no Trial key is set. |
|
|
168
|
-
| `Q402_API_KEY` | legacy fallback | Pre-v0.4.
|
|
171
|
+
| `Q402_API_KEY` | legacy fallback | Pre-v0.4.4 single-env path. Used for both scopes when the two above are unset. Keep set if you only have one key. |
|
|
169
172
|
| `Q402_PRIVATE_KEY` | live-pay | Signer for the payer EOA. **Never share. Never paste in chat.** |
|
|
170
173
|
| `Q402_ENABLE_REAL_PAYMENTS` | live-pay | Set to `1` to opt in. Any other value (or unset) → sandbox. |
|
|
171
174
|
| `Q402_MAX_AMOUNT_PER_CALL` | optional | USD-equivalent cap. Defaults to `5`. |
|
package/dist/index.js
CHANGED
|
@@ -52,31 +52,47 @@ function loadConfig() {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
var CONFIG = loadConfig();
|
|
55
|
-
function resolveApiKey(chain, scope = "auto") {
|
|
56
|
-
const effectiveScope = scope === "auto" ?
|
|
55
|
+
function resolveApiKey(chain, scope = "auto", intent = "single") {
|
|
56
|
+
const effectiveScope = scope === "auto" ? (
|
|
57
|
+
// Smart routing: batches default to multichain (trial cap=5 would
|
|
58
|
+
// silently fail any 6+ recipient batch). Single payments default to
|
|
59
|
+
// trial on BNB when a trial key is set, so the free sponsored
|
|
60
|
+
// allotment gets used naturally.
|
|
61
|
+
intent === "batch" ? "multichain" : chain === "bnb" && CONFIG.trialApiKey ? "trial" : "multichain"
|
|
62
|
+
) : scope;
|
|
57
63
|
if (effectiveScope === "trial") {
|
|
58
64
|
if (chain !== "bnb") {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
return {
|
|
66
|
+
apiKey: null,
|
|
67
|
+
scope: "trial",
|
|
68
|
+
fromLegacyFallback: false,
|
|
69
|
+
sandboxReason: `keyScope="trial" requested but chain="${chain}" \u2014 Trial keys support BNB Chain only. Drop keyScope (or set keyScope="multichain") to use the paid Multichain key on ${chain}.`
|
|
70
|
+
};
|
|
62
71
|
}
|
|
63
72
|
const key2 = CONFIG.trialApiKey ?? CONFIG.legacyApiKey;
|
|
64
73
|
if (!key2) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
return {
|
|
75
|
+
apiKey: null,
|
|
76
|
+
scope: "trial",
|
|
77
|
+
fromLegacyFallback: false,
|
|
78
|
+
sandboxReason: "keyScope='trial' requested but neither Q402_TRIAL_API_KEY nor Q402_API_KEY is set. Get a free Trial key at https://q402.quackai.ai/event."
|
|
79
|
+
};
|
|
68
80
|
}
|
|
69
81
|
return { apiKey: key2, scope: "trial", fromLegacyFallback: !CONFIG.trialApiKey };
|
|
70
82
|
}
|
|
71
83
|
const key = CONFIG.multichainApiKey ?? CONFIG.legacyApiKey;
|
|
72
84
|
if (!key) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
return {
|
|
86
|
+
apiKey: null,
|
|
87
|
+
scope: "multichain",
|
|
88
|
+
fromLegacyFallback: false,
|
|
89
|
+
sandboxReason: (scope === "multichain" ? "keyScope='multichain' requested but neither Q402_MULTICHAIN_API_KEY" : `chain="${chain}" routes to the Multichain scope but neither Q402_MULTICHAIN_API_KEY`) + " nor Q402_API_KEY is set. Activate a paid plan at https://q402.quackai.ai/payment to get one."
|
|
90
|
+
};
|
|
76
91
|
}
|
|
77
92
|
return { apiKey: key, scope: "multichain", fromLegacyFallback: !CONFIG.multichainApiKey };
|
|
78
93
|
}
|
|
79
94
|
function isLiveModeFor(resolved) {
|
|
95
|
+
if (!resolved.apiKey) return false;
|
|
80
96
|
if (!CONFIG.realPaymentsRequested) return false;
|
|
81
97
|
if (!CONFIG.privateKey) return false;
|
|
82
98
|
return resolved.apiKey.startsWith("q402_live_");
|
|
@@ -290,7 +306,7 @@ function runQuote(input) {
|
|
|
290
306
|
}
|
|
291
307
|
var QUOTE_TOOL = {
|
|
292
308
|
name: "q402_quote",
|
|
293
|
-
description: "Compare gas costs and supported tokens across the 8 chains Q402 relays for (avax, bnb, eth, xlayer, stable, mantle, injective, monad).
|
|
309
|
+
description: "Compare gas costs and supported tokens across the 8 chains Q402 relays for (avax, bnb, eth, xlayer, stable, mantle, injective, monad). Returns the full chain \xD7 token matrix unconditionally \u2014 this tool does not read any API key, so it can't filter by trial vs multichain scope. When the caller intends to settle with a Trial API Key, treat any non-BNB row as informational only (q402_pay will return 403 TRIAL_BNB_ONLY for those). Includes RLUSD on Ethereum and Injective USDT-only. Read-only \u2014 no API key needed, no funds move. Use this before q402_pay so the user can see what's available and pick a chain.",
|
|
294
310
|
// Plain JSON schema mirroring the Zod schema above; MCP servers receive parameters as JSON.
|
|
295
311
|
inputSchema: {
|
|
296
312
|
type: "object",
|
|
@@ -705,7 +721,7 @@ async function runPay(input) {
|
|
|
705
721
|
guardsApplied.push(`recipient_allowlist[${CONFIG.allowedRecipients.length}]`);
|
|
706
722
|
}
|
|
707
723
|
const scopeRequest = input.keyScope ?? "auto";
|
|
708
|
-
const resolved = resolveApiKey(input.chain, scopeRequest);
|
|
724
|
+
const resolved = resolveApiKey(input.chain, scopeRequest, "single");
|
|
709
725
|
guardsApplied.push(`scope=${resolved.scope}${resolved.fromLegacyFallback ? "(legacy)" : ""}`);
|
|
710
726
|
const live = isLiveModeFor(resolved);
|
|
711
727
|
if (!live) {
|
|
@@ -715,7 +731,7 @@ async function runPay(input) {
|
|
|
715
731
|
token: input.token
|
|
716
732
|
});
|
|
717
733
|
guardsApplied.push("mode=sandbox");
|
|
718
|
-
const setupHint = describeSandboxReason(resolved.apiKey);
|
|
734
|
+
const setupHint = resolved.sandboxReason ?? describeSandboxReason(resolved.apiKey ?? "");
|
|
719
735
|
return { result: result2, guardsApplied, setupHint };
|
|
720
736
|
}
|
|
721
737
|
const client = new Q402NodeClient({
|
|
@@ -847,7 +863,7 @@ async function runBatchPay(input) {
|
|
|
847
863
|
guardsApplied.push(`recipient_allowlist[${CONFIG.allowedRecipients.length}]`);
|
|
848
864
|
}
|
|
849
865
|
const scopeRequest = input.keyScope ?? "auto";
|
|
850
|
-
const resolved = resolveApiKey(input.chain, scopeRequest);
|
|
866
|
+
const resolved = resolveApiKey(input.chain, scopeRequest, "batch");
|
|
851
867
|
guardsApplied.push(`scope=${resolved.scope}${resolved.fromLegacyFallback ? "(legacy)" : ""}`);
|
|
852
868
|
const live = isLiveModeFor(resolved);
|
|
853
869
|
if (!live) {
|
|
@@ -855,7 +871,7 @@ async function runBatchPay(input) {
|
|
|
855
871
|
(r) => sandboxPay(chain, { to: r.to, amount: r.amount, token: input.token })
|
|
856
872
|
);
|
|
857
873
|
guardsApplied.push("mode=sandbox");
|
|
858
|
-
const reason = describeSandboxReason2(resolved.apiKey);
|
|
874
|
+
const reason = resolved.sandboxReason ?? describeSandboxReason2(resolved.apiKey ?? "");
|
|
859
875
|
return {
|
|
860
876
|
mode: "sandbox",
|
|
861
877
|
status: "sandbox",
|
|
@@ -1205,7 +1221,7 @@ var RECEIPT_TOOL = {
|
|
|
1205
1221
|
|
|
1206
1222
|
// src/index.ts
|
|
1207
1223
|
var PACKAGE_NAME = "@quackai/q402-mcp";
|
|
1208
|
-
var PACKAGE_VERSION = "0.4.
|
|
1224
|
+
var PACKAGE_VERSION = "0.4.4";
|
|
1209
1225
|
function jsonText(value) {
|
|
1210
1226
|
return { type: "text", text: JSON.stringify(value, null, 2) };
|
|
1211
1227
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "MCP server for Q402 — gasless USDC, USDT, and RLUSD payments across 8 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": [
|