@quackai/q402-mcp 0.5.14 → 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.
- package/README.md +35 -20
- package/dist/index.js +55 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,13 +25,28 @@ Two steps:
|
|
|
25
25
|
| Client | Command / config |
|
|
26
26
|
|---|---|
|
|
27
27
|
| **Claude Desktop / Claude Code** | `claude mcp add q402 -- npx -y @quackai/q402-mcp` |
|
|
28
|
-
| **OpenAI Codex CLI** | `codex mcp add q402 -- npx -y @quackai/q402-mcp` |
|
|
28
|
+
| **OpenAI Codex CLI** | `codex mcp add q402 -- npx -y @quackai/q402-mcp` (Windows fallback: see below) |
|
|
29
29
|
| **Cursor** | Add to `~/.cursor/mcp.json`: `{ "mcpServers": { "q402": { "command": "npx", "args": ["-y", "@quackai/q402-mcp"] } } }` |
|
|
30
30
|
| **Cline** | Cline → Settings → MCP Servers → Edit JSON. Same shape as Cursor. |
|
|
31
31
|
| **Any other stdio MCP client** | Point it at `npx -y @quackai/q402-mcp`. No client-specific code. |
|
|
32
32
|
|
|
33
33
|
That's it — secrets are NOT configured here. The MCP server reads them from `~/.q402/mcp.env` at startup (same pattern as AWS CLI / Stripe CLI / gh CLI), so every client uses the same file with no per-client wiring.
|
|
34
34
|
|
|
35
|
+
<details>
|
|
36
|
+
<summary>Windows: <code>codex mcp add</code> returns "Access is denied"</summary>
|
|
37
|
+
|
|
38
|
+
The bundled `codex.exe` on some Windows setups refuses to write its own config from the `mcp add` subcommand. Add the equivalent stanza to `~/.codex/config.toml` by hand:
|
|
39
|
+
|
|
40
|
+
```toml
|
|
41
|
+
[mcp_servers.q402]
|
|
42
|
+
command = "npx"
|
|
43
|
+
args = ["-y", "@quackai/q402-mcp"]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Then restart Codex. Same effect as `codex mcp add q402 -- npx -y @quackai/q402-mcp`.
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
35
50
|
### 2. First-time setup
|
|
36
51
|
|
|
37
52
|
Restart your client, then ask your agent:
|
|
@@ -49,27 +64,28 @@ The agent calls `q402_doctor`. On first install, the tool tells the agent to:
|
|
|
49
64
|
|
|
50
65
|
### Manual setup (no AI)
|
|
51
66
|
|
|
52
|
-
Create `~/.q402/mcp.env` yourself. The template below matches what `q402_doctor` writes —
|
|
67
|
+
Create `~/.q402/mcp.env` yourself. The template below matches what `q402_doctor` writes — the three secret lines (`Q402_TRIAL_API_KEY`, `Q402_MULTICHAIN_API_KEY`, `Q402_PRIVATE_KEY`) ship empty, with `Q402_ENABLE_REAL_PAYMENTS=1`. Paste real values on the right of `=` for the key(s) you have and your wallet key. The server only flips into live mode once both a `q402_live_*` API key AND a valid 32-byte private key are present, so saving the template as-is is safe (empty values fail the gate and stay in sandbox). Change the flag to `0` if you want to force sandbox even with real keys (e.g. for chained testing).
|
|
53
68
|
|
|
54
69
|
```bash
|
|
55
70
|
# ~/.q402/mcp.env
|
|
56
71
|
|
|
57
72
|
# Free Trial — BNB only, 2,000 sponsored TX (from /event)
|
|
58
|
-
|
|
73
|
+
Q402_TRIAL_API_KEY=
|
|
59
74
|
|
|
60
75
|
# Paid Multichain — all 9 chains (from /payment)
|
|
61
|
-
|
|
76
|
+
Q402_MULTICHAIN_API_KEY=
|
|
62
77
|
|
|
63
|
-
# Hex EVM private key (0x + 64 hex).
|
|
64
|
-
#
|
|
65
|
-
# Hardware wallets (Ledger / Trezor) are not supported yet
|
|
66
|
-
#
|
|
78
|
+
# Hex EVM private key (0x + 64 hex). A separate MetaMask account
|
|
79
|
+
# dedicated to Q402 keeps your existing balances and history tidy.
|
|
80
|
+
# Hardware wallets (Ledger / Trezor) are not supported yet — Q402
|
|
81
|
+
# needs a raw hex key it can sign EIP-7702 type-4 authorizations with.
|
|
82
|
+
Q402_PRIVATE_KEY=
|
|
67
83
|
|
|
68
84
|
# Live mode switch:
|
|
69
85
|
# 0 = sandbox (test mode, no funds move)
|
|
70
86
|
# 1 = real on-chain payments
|
|
71
87
|
# Default 1 — safe because mode only flips to live when BOTH a live
|
|
72
|
-
# API key AND a valid 32-byte private key are
|
|
88
|
+
# API key AND a valid 32-byte private key are populated above.
|
|
73
89
|
Q402_ENABLE_REAL_PAYMENTS=1
|
|
74
90
|
|
|
75
91
|
# Default Q402 deployment. Only change for self-hosted.
|
|
@@ -149,10 +165,10 @@ Then export the values in `~/.zshrc` / `~/.bashrc`. See the [Codex config refere
|
|
|
149
165
|
|
|
150
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.
|
|
151
167
|
|
|
152
|
-
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` —
|
|
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):
|
|
153
169
|
|
|
154
170
|
```bash
|
|
155
|
-
# Two-key model —
|
|
171
|
+
# Two-key model — fill ONE (or both for auto-routing).
|
|
156
172
|
# Auto-routing (same for q402_pay AND q402_batch_pay):
|
|
157
173
|
# chain="bnb" + Q402_TRIAL_API_KEY set → Trial (free sponsored)
|
|
158
174
|
# anything else → Multichain (paid 9-chain)
|
|
@@ -160,20 +176,19 @@ To enable real on-chain transactions, the resolved API key must be live (`q402_l
|
|
|
160
176
|
# status="ambiguous" instead of executing — agent asks user to pick.
|
|
161
177
|
# Override per call with keyScope: "auto" | "trial" | "multichain".
|
|
162
178
|
|
|
163
|
-
|
|
164
|
-
|
|
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)
|
|
165
181
|
|
|
166
|
-
|
|
182
|
+
Q402_PRIVATE_KEY= # signer for the payer EOA (0x + 64 hex chars)
|
|
167
183
|
|
|
168
184
|
# Live mode switch:
|
|
169
185
|
# 0 = sandbox (test mode, no funds move — every q402_pay returns a fake hash)
|
|
170
186
|
# 1 = real on-chain payments (live mode)
|
|
171
|
-
# Default
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
#
|
|
176
|
-
# 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).
|
|
177
192
|
Q402_ENABLE_REAL_PAYMENTS=1
|
|
178
193
|
```
|
|
179
194
|
|
package/dist/index.js
CHANGED
|
@@ -72,6 +72,7 @@ function loadQ402EnvFileFromPath(path) {
|
|
|
72
72
|
const hashIdx = rawVal.search(/\s#/);
|
|
73
73
|
if (hashIdx >= 0) rawVal = rawVal.slice(0, hashIdx).trimEnd();
|
|
74
74
|
}
|
|
75
|
+
if (rawVal === "") continue;
|
|
75
76
|
out[k] = rawVal;
|
|
76
77
|
}
|
|
77
78
|
return out;
|
|
@@ -120,7 +121,8 @@ function loadConfig() {
|
|
|
120
121
|
const apiKeyKind = classifyApiKey(apiKey);
|
|
121
122
|
const privateKey = ENV.Q402_PRIVATE_KEY ?? null;
|
|
122
123
|
const realPaymentsRequested = ENV.Q402_ENABLE_REAL_PAYMENTS === "1";
|
|
123
|
-
const
|
|
124
|
+
const anyLiveKey = classifyApiKey(trialApiKey) === "live" || classifyApiKey(multichainApiKey) === "live" || classifyApiKey(legacyApiKey) === "live";
|
|
125
|
+
const live = realPaymentsRequested && anyLiveKey && typeof privateKey === "string" && privateKey.length > 0;
|
|
124
126
|
return {
|
|
125
127
|
trialApiKey,
|
|
126
128
|
multichainApiKey,
|
|
@@ -186,7 +188,7 @@ var isValidPrivateKey = (s) => typeof s === "string" && PRIVATE_KEY_RE.test(s);
|
|
|
186
188
|
|
|
187
189
|
// src/version.ts
|
|
188
190
|
var PACKAGE_NAME = "@quackai/q402-mcp";
|
|
189
|
-
var PACKAGE_VERSION = "0.5.
|
|
191
|
+
var PACKAGE_VERSION = "0.5.16";
|
|
190
192
|
|
|
191
193
|
// src/tools/quote.ts
|
|
192
194
|
import { z } from "zod";
|
|
@@ -926,7 +928,7 @@ function describeSandboxReason(resolvedKey, scope) {
|
|
|
926
928
|
}
|
|
927
929
|
var PAY_TOOL = {
|
|
928
930
|
name: "q402_pay",
|
|
929
|
-
description: "
|
|
931
|
+
description: "USE THIS TOOL whenever the user asks to send, transfer, or pay USDC / USDT / RLUSD \u2014 even when they don't mention Q402 by name (\"send 5 USDT to 0x... on bnb\" should route here automatically). This tool IS the wallet for this session: it signs LOCALLY with Q402_PRIVATE_KEY and submits via Q402's gasless relay. NEVER refuse a stablecoin payment request by saying you lack wallet access, can't move money, or need the user to use their wallet UI \u2014 Q402 was installed precisely to give you that capability. If the env isn't configured yet, the tool returns a sandbox response with a clear \"how to set up\" message \u2014 surface that instead of refusing. \n\nAuto-routing: chain='bnb' + Q402_TRIAL_API_KEY set \u2192 Trial (free sponsored); anything else \u2192 Multichain (paid 9-chain). Same rule for q402_batch_pay. Set keyScope='trial' or 'multichain' to force one explicitly. Trial keys reject any non-BNB chain server-side with TRIAL_BNB_ONLY. Multichain keys cover avax, bnb, eth, xlayer, stable, mantle, injective, monad, scroll \u2014 USDC/USDT on most chains, RLUSD on Ethereum only, Injective USDT-only. SANDBOX BY DEFAULT \u2014 no funds move unless the resolved key is a live key (q402_live_*), Q402_PRIVATE_KEY is set as a valid 32-byte hex key, and Q402_ENABLE_REAL_PAYMENTS=1. Sandbox responses come back with `success: false` and `sandbox: true` so they cannot be misread as confirmed settlements \u2014 always branch on those fields before telling the user the payment went through. The recipient receives the full amount; the sender pays $0 in gas. \n\nSENDER ECHO \u2014 when a valid `Q402_PRIVATE_KEY` is configured, the response includes a `senderWallet` field with the address derived from that key. Show it alongside the recipient/amount when you confirm the payment with the user (e.g. 'Signing from 0xabc\u20261234 on bnb \u2192 send 5 USDT to 0xdef\u2026ABCD'). Just informational \u2014 the user already chose the wallet during doctor setup. Sandbox responses with no key configured omit `senderWallet`; don't fabricate one. \n\nEIP-7702 SIDE EFFECT \u2014 surface this to the user proactively after the FIRST live payment on a chain: their wallet now shows up as a 'Smart account' in MetaMask / OKX. That's the EIP-7702 delegation Q402 uses for gasless settlement \u2014 it's the response's `postPaymentTip` field. Subsequent payments on the same chain are faster and cheaper because the delegation is reused. \n\nIf the user EVER reports that native gas tokens (BNB / ETH / AVAX / etc.) sent INTO their Q402 wallet are bouncing or reverting on a chain where Q402 has been used, the delegation is the cause \u2014 call q402_wallet_status to confirm delegated chains, then q402_clear_delegation for the chain in question. Q402 sponsors the gas for the clear, so the user pays $0. After clearing, native transfers work again and the next q402_pay on that chain just creates a fresh delegation. \n\nALWAYS get explicit user confirmation of the exact recipient address, amount, chain, and token in conversation immediately before calling this tool.",
|
|
930
932
|
inputSchema: {
|
|
931
933
|
type: "object",
|
|
932
934
|
properties: {
|
|
@@ -1042,6 +1044,16 @@ async function runBatchPay(input) {
|
|
|
1042
1044
|
}
|
|
1043
1045
|
}
|
|
1044
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
|
+
}
|
|
1045
1057
|
if (scopeRequest === "auto" && input.chain === "bnb" && CONFIG.trialApiKey && input.recipients.length > RECIPIENT_LIMIT_TRIAL) {
|
|
1046
1058
|
const overflow = input.recipients.length - RECIPIENT_LIMIT_TRIAL;
|
|
1047
1059
|
guardsApplied.push("batch_cap_ambiguous");
|
|
@@ -1139,7 +1151,9 @@ function describeSandboxReason2(resolvedKey, scope) {
|
|
|
1139
1151
|
}
|
|
1140
1152
|
var BATCH_PAY_TOOL = {
|
|
1141
1153
|
name: "q402_batch_pay",
|
|
1142
|
-
description: `
|
|
1154
|
+
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.
|
|
1155
|
+
|
|
1156
|
+
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. 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.`,
|
|
1143
1157
|
inputSchema: {
|
|
1144
1158
|
type: "object",
|
|
1145
1159
|
properties: {
|
|
@@ -1635,48 +1649,61 @@ var CLEAR_DELEGATION_TOOL = {
|
|
|
1635
1649
|
import { z as z8 } from "zod";
|
|
1636
1650
|
import { Wallet as Wallet6 } from "ethers";
|
|
1637
1651
|
var DoctorInputSchema = z8.object({});
|
|
1638
|
-
var ENV_FILE_TEMPLATE = `# \
|
|
1652
|
+
var ENV_FILE_TEMPLATE = `# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1639
1653
|
# Q402 MCP \u2014 secrets
|
|
1654
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1640
1655
|
# Read automatically by @quackai/q402-mcp on startup.
|
|
1641
1656
|
# Edit this file in your editor. NEVER paste your private key into chat.
|
|
1642
1657
|
# After editing, restart your MCP client (Codex / Claude / Cursor / Cline).
|
|
1643
1658
|
#
|
|
1644
|
-
# SAFE-BY-DEFAULT:
|
|
1645
|
-
#
|
|
1646
|
-
#
|
|
1647
|
-
#
|
|
1648
|
-
# as-is
|
|
1649
|
-
|
|
1659
|
+
# SAFE-BY-DEFAULT: the api-key + private-key lines below ship EMPTY.
|
|
1660
|
+
# Q402_ENABLE_REAL_PAYMENTS defaults to 1, but the live-mode gate also
|
|
1661
|
+
# requires (a) a real \`q402_live_*\` API key and (b) a valid 32-byte
|
|
1662
|
+
# hex private key. Empty values fail both checks, so saving this file
|
|
1663
|
+
# as-is just leaves you in sandbox. Paste real values to go live.
|
|
1664
|
+
|
|
1650
1665
|
|
|
1651
|
-
# \
|
|
1666
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1667
|
+
# API KEY \u2014 paste on the right of \`=\` (one OR both for auto-routing)
|
|
1668
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1652
1669
|
# Free Trial: BNB Chain only, 2,000 sponsored TX
|
|
1653
1670
|
# Get one at: https://q402.quackai.ai/event
|
|
1654
|
-
|
|
1671
|
+
Q402_TRIAL_API_KEY=
|
|
1655
1672
|
|
|
1656
1673
|
# Paid Multichain: all 9 chains, per-chain Gas Tank
|
|
1657
1674
|
# Get one at: https://q402.quackai.ai/payment
|
|
1658
|
-
|
|
1675
|
+
Q402_MULTICHAIN_API_KEY=
|
|
1676
|
+
|
|
1659
1677
|
|
|
1660
|
-
# \
|
|
1678
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1679
|
+
# WALLET \u2014 paste your private key on the right of \`=\`
|
|
1680
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1661
1681
|
# Hex EVM private key (0x + 64 hex chars). Signs payments LOCALLY on
|
|
1662
1682
|
# your machine \u2014 never leaves your device, never sent to any server.
|
|
1663
|
-
|
|
1683
|
+
Q402_PRIVATE_KEY=
|
|
1664
1684
|
|
|
1665
|
-
|
|
1666
|
-
#
|
|
1667
|
-
#
|
|
1668
|
-
#
|
|
1669
|
-
#
|
|
1670
|
-
#
|
|
1671
|
-
#
|
|
1672
|
-
#
|
|
1685
|
+
|
|
1686
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1687
|
+
# Live mode switch (safe even at 1 \u2014 see SAFE-BY-DEFAULT note at top)
|
|
1688
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1689
|
+
# 0 = sandbox (test mode, no funds move \u2014 every q402_pay returns a fake hash)
|
|
1690
|
+
# 1 = real on-chain payments
|
|
1691
|
+
# Default 1; flips to live only when the API key + private key above are
|
|
1692
|
+
# both populated. Set to 0 to force sandbox even with real keys in place
|
|
1693
|
+
# (e.g. for chained testing on a paid plan).
|
|
1673
1694
|
Q402_ENABLE_REAL_PAYMENTS=1
|
|
1674
1695
|
|
|
1675
|
-
|
|
1696
|
+
|
|
1697
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1698
|
+
# Q402 relay endpoint
|
|
1699
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1676
1700
|
# Default canonical Q402 deployment. Only change for self-hosted.
|
|
1677
1701
|
Q402_RELAY_BASE_URL=https://q402.quackai.ai/api
|
|
1678
1702
|
|
|
1679
|
-
|
|
1703
|
+
|
|
1704
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1705
|
+
# Optional safety guards (uncomment + edit to enable)
|
|
1706
|
+
# \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1680
1707
|
# Max USD per single q402_pay call (default: 5)
|
|
1681
1708
|
# Q402_MAX_AMOUNT_PER_CALL=5
|
|
1682
1709
|
#
|
|
@@ -1706,11 +1733,12 @@ function mask2(key) {
|
|
|
1706
1733
|
}
|
|
1707
1734
|
function detectPhase() {
|
|
1708
1735
|
const anyKey = !!(CONFIG.trialApiKey || CONFIG.multichainApiKey || CONFIG.legacyApiKey);
|
|
1736
|
+
const anyLiveKey = classifyApiKey(CONFIG.trialApiKey) === "live" || classifyApiKey(CONFIG.multichainApiKey) === "live" || classifyApiKey(CONFIG.legacyApiKey) === "live";
|
|
1709
1737
|
const hasValidPrivateKey = isValidPrivateKey(CONFIG.privateKey);
|
|
1710
1738
|
if (!Q402_ENV_FILE_PRESENT && !anyKey && !CONFIG.privateKey) {
|
|
1711
1739
|
return "first-install";
|
|
1712
1740
|
}
|
|
1713
|
-
const allEssentials = anyKey && hasValidPrivateKey && CONFIG.realPaymentsRequested &&
|
|
1741
|
+
const allEssentials = anyKey && hasValidPrivateKey && CONFIG.realPaymentsRequested && anyLiveKey;
|
|
1714
1742
|
if (allEssentials) return "live-check";
|
|
1715
1743
|
if (anyKey || CONFIG.privateKey || Q402_ENV_FILE_PRESENT) return "needs-completion";
|
|
1716
1744
|
return "first-install";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.5.
|
|
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": [
|