@quackai/q402-mcp 0.3.14 → 0.4.1
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 +192 -192
- package/dist/index.js +31 -15
- package/package.json +69 -69
package/README.md
CHANGED
|
@@ -1,192 +1,192 @@
|
|
|
1
|
-
# @quackai/q402-mcp
|
|
2
|
-
|
|
3
|
-
> MCP server for Q402 — gasless USDC, USDT, and RLUSD payments across
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/@quackai/q402-mcp)
|
|
6
|
-
[](./LICENSE)
|
|
7
|
-
|
|
8
|
-
> **🎟️ Free trial available (2026-05-19 → 2026-06-30)** — 2,000 gasless transactions on BNB Chain (USDC + USDT), 30-day window, no card. One wallet signature: <https://q402.quackai.ai>.
|
|
9
|
-
>
|
|
10
|
-
> **Trial-scope policy:** API keys minted under the free-trial program (`plan: "trial"`) are restricted to BNB Chain with USDC/USDT — server-side enforcement, returns `403 TRIAL_BNB_ONLY` otherwise. **Paid API keys see the full
|
|
11
|
-
|
|
12
|
-
Claude can now reason about stablecoin payments end to end — quote a transfer across
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Quick start
|
|
17
|
-
|
|
18
|
-
The server speaks stdio MCP, so any MCP-compatible client can use it. The two paths verified end-to-end today are **Claude (Desktop / Code)** and **OpenAI Codex CLI**.
|
|
19
|
-
|
|
20
|
-
### Claude Desktop / Claude Code
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
claude mcp add q402 -- npx -y @quackai/q402-mcp
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Or edit `claude_desktop_config.json` directly:
|
|
27
|
-
|
|
28
|
-
```json
|
|
29
|
-
{
|
|
30
|
-
"mcpServers": {
|
|
31
|
-
"q402": {
|
|
32
|
-
"command": "npx",
|
|
33
|
-
"args": ["-y", "@quackai/q402-mcp"]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Restart Claude Desktop and ask:
|
|
40
|
-
|
|
41
|
-
> *"Compare gas costs to send 50 USDC to vitalik.eth across all
|
|
42
|
-
|
|
43
|
-
### OpenAI Codex CLI
|
|
44
|
-
|
|
45
|
-
Three install paths — pick the one that matches your workflow.
|
|
46
|
-
|
|
47
|
-
**(a) Codex plugin marketplace** (recommended — bundles the MCP config so users don't write TOML):
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
codex plugin marketplace add bitgett/q402-mcp
|
|
51
|
-
codex /plugins # browse and install "q402"
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
This repo carries a Codex plugin manifest at [`.codex-plugin/plugin.json`](./.codex-plugin/plugin.json) and a marketplace catalog at [`.agents/plugins/marketplace.json`](./.agents/plugins/marketplace.json), so any signed-in Codex user can register it as a marketplace source and install with one click.
|
|
55
|
-
|
|
56
|
-
**(b) Single MCP server via `codex mcp add`** (no plugin wrapper — just register the stdio server):
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
codex mcp add q402 -- npx -y @quackai/q402-mcp
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**(c) Direct `~/.codex/config.toml` edit** (`.codex/config.toml` for per-project scope):
|
|
63
|
-
|
|
64
|
-
```toml
|
|
65
|
-
[mcp_servers.q402]
|
|
66
|
-
command = "npx"
|
|
67
|
-
args = ["-y", "@quackai/q402-mcp"]
|
|
68
|
-
startup_timeout_sec = 20.0
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
To enable real on-chain payments, pass the three live-mode env vars **explicitly** under `env` — Codex does **not** forward host env vars by default:
|
|
72
|
-
|
|
73
|
-
```toml
|
|
74
|
-
[mcp_servers.q402]
|
|
75
|
-
command = "npx"
|
|
76
|
-
args = ["-y", "@quackai/q402-mcp"]
|
|
77
|
-
startup_timeout_sec = 20.0
|
|
78
|
-
env = {
|
|
79
|
-
Q402_API_KEY = "q402_live_...",
|
|
80
|
-
Q402_PRIVATE_KEY = "0xabc...",
|
|
81
|
-
Q402_ENABLE_REAL_PAYMENTS = "1",
|
|
82
|
-
Q402_MAX_AMOUNT_PER_CALL = "5",
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
> If you'd rather not inline secrets in `config.toml`, use the `env_vars` allow-list form to forward specific names from your shell environment instead — see the [Codex config reference](https://developers.openai.com/codex/config-reference) for the full schema.
|
|
87
|
-
|
|
88
|
-
Then run `codex` and ask the same kind of question. The first call may take a few seconds while `npx` warms its cache; subsequent calls are instant.
|
|
89
|
-
|
|
90
|
-
### Any other MCP client
|
|
91
|
-
|
|
92
|
-
The server has no client-specific code. If your client speaks stdio MCP, point it at `npx -y @quackai/q402-mcp` and the
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
>
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Tools exposed
|
|
101
|
-
|
|
102
|
-
| Tool | Auth | Purpose |
|
|
103
|
-
|---|---|---|
|
|
104
|
-
| `q402_quote` | none | Compare gas cost and supported tokens across chains. Read-only. |
|
|
105
|
-
| `q402_balance` | API key | Verify the API key and report its plan tier + remaining quota credits (live vs sandbox). |
|
|
106
|
-
| `q402_pay` | API key + private key + flag | Send a gasless payment to a single recipient. **Sandbox by default** — see [Sandbox vs live mode](#sandbox-vs-live-mode). |
|
|
107
|
-
| `q402_batch_pay` | API key + private key + flag | Send a gasless payment to **multiple** recipients in one call on a single chain × token. Trial keys: 5 rows max. Paid keys: 20 rows max. **Supported chains: avax, bnb, eth, mantle, injective** (default EIP-7702 mode). xlayer + stable are NOT batchable — use `q402_pay` in a loop for those. Same sandbox gating as `q402_pay`. **Rate-limit note:** the inner `/api/relay` budget (30/min per key) is consumed per row, so a paid 20-row batch leaves ~10 inner slots for the next minute. |
|
|
108
|
-
| `q402_receipt` | none | Look up a Trust Receipt by `rct_…` id and locally verify its ECDSA signature against the relayer EOA. Returns the public settlement record + a `verified` boolean. *receiptId-only today; tx-hash lookup reserved for a future release.* |
|
|
109
|
-
|
|
110
|
-
`q402_pay` and `q402_batch_pay` follow a "confirm in chat first" contract: the tool description instructs the model to never call it without explicit user approval of the recipient address(es), amount(s), chain, and token. For batch calls the user must approve the **full batch**, not the individual rows.
|
|
111
|
-
|
|
112
|
-
`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:
|
|
113
|
-
|
|
114
|
-
> *"Pay 0.10 USDT on BNB to vitalik.eth, then verify the receipt."*
|
|
115
|
-
> *"Is `rct_afa5f50bc49a65ebba3b28ab` a real Q402 receipt? Verify the signature."*
|
|
116
|
-
|
|
117
|
-
> 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.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## Sandbox vs live mode
|
|
122
|
-
|
|
123
|
-
By default the MCP server operates in **sandbox mode**: `q402_pay` returns a deterministic-looking fake transaction hash, no funds move, no gas-tank credit is consumed. That makes it safe to plug into any MCP client without worrying about an LLM hallucinating a payment.
|
|
124
|
-
|
|
125
|
-
To enable real on-chain transactions, **all three** environment variables must be set:
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
Q402_API_KEY=q402_live_... # live-tier key from /dashboard
|
|
129
|
-
Q402_PRIVATE_KEY=0xabc... # signer for the payer EOA
|
|
130
|
-
Q402_ENABLE_REAL_PAYMENTS=1 # explicit opt-in
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Anything missing → automatic sandbox fallback with a hint pointing at what to set.
|
|
134
|
-
|
|
135
|
-
### Hard caps
|
|
136
|
-
|
|
137
|
-
Two additional guards run before every payment regardless of mode:
|
|
138
|
-
|
|
139
|
-
| Env var | Default | Effect |
|
|
140
|
-
|---|---|---|
|
|
141
|
-
| `Q402_MAX_AMOUNT_PER_CALL` | `5` | Reject any single call where `amount > N` USD-equivalent. |
|
|
142
|
-
| `Q402_ALLOWED_RECIPIENTS` | (empty = off) | Comma-separated address allowlist. When set, all other recipients are rejected. |
|
|
143
|
-
|
|
144
|
-
Combined with the `confirm: true` argument the tool requires, this means the model needs (a) explicit user OK in chat, (b) amount ≤ cap, (c) recipient on allowlist if one exists, (d) all three live-mode env vars set, before a single wei moves.
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
## Configuration reference
|
|
149
|
-
|
|
150
|
-
| Env var | Required for | Notes |
|
|
151
|
-
|---|---|---|
|
|
152
|
-
| `Q402_API_KEY` | balance, live-pay | Issue at https://q402.quackai.ai/dashboard. `q402_test_*` keys keep sandbox on. |
|
|
153
|
-
| `Q402_PRIVATE_KEY` | live-pay | Signer for the payer EOA. **Never share. Never paste in chat.** |
|
|
154
|
-
| `Q402_ENABLE_REAL_PAYMENTS` | live-pay | Set to `1` to opt in. Any other value (or unset) → sandbox. |
|
|
155
|
-
| `Q402_MAX_AMOUNT_PER_CALL` | optional | USD-equivalent cap. Defaults to `5`. |
|
|
156
|
-
| `Q402_ALLOWED_RECIPIENTS` | optional | Comma-separated lowercase addresses. Defaults to no allowlist. |
|
|
157
|
-
| `Q402_RELAY_BASE_URL` | optional | Defaults to `https://q402.quackai.ai/api`. Override for self-hosted Q402. |
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## Supported chains
|
|
162
|
-
|
|
163
|
-
| Chain | Chain ID | Token(s) | Notes |
|
|
164
|
-
|---|---|---|---|
|
|
165
|
-
| BNB Chain | 56 | USDC, USDT | |
|
|
166
|
-
| Ethereum | 1 | USDC, USDT, **RLUSD** | L1 — gas is volatile, quote is a snapshot. RLUSD (Ripple USD, NY DFS regulated, decimals 18) Ethereum-only. |
|
|
167
|
-
| Avalanche C-Chain | 43114 | USDC, USDT | |
|
|
168
|
-
| X Layer | 196 | USDC, USDT | |
|
|
169
|
-
| Stable | 988 | USDT0 (USDC and USDT both alias) | Gas paid in USDT0. |
|
|
170
|
-
| Mantle | 5000 | USDC, USDT0 | LayerZero OFT USDT0 since 2025-11-27. |
|
|
171
|
-
| Injective EVM | 1776 | USDT only | Native USDC via Circle CCTP announced for Q2 2026. |
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## Why this exists
|
|
176
|
-
|
|
177
|
-
x402 standardised "402 Payment Required" semantics for AI agents but the official Coinbase facilitator only covers a few chains and assumes ERC-3009 token support — which excludes BNB USDT, Mantle USDT0, Injective USDT, and the chains where most stablecoin volume actually lives.
|
|
178
|
-
|
|
179
|
-
Q402 implements the same payer experience (single signature, $0 gas, instant settlement) on all 7 of those chains using EIP-7702 delegated execution, which works with any ERC-20. This MCP server makes that infrastructure addressable from Claude itself.
|
|
180
|
-
|
|
181
|
-
If you want to dig into how the wire protocol differs from x402, see [Q402 docs](https://q402.quackai.ai/docs).
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## Repository
|
|
186
|
-
|
|
187
|
-
Source code: https://github.com/bitgett/q402-mcp
|
|
188
|
-
Issues / requests: https://github.com/bitgett/q402-mcp/issues
|
|
189
|
-
|
|
190
|
-
## License
|
|
191
|
-
|
|
192
|
-
Apache-2.0 — see [LICENSE](./LICENSE).
|
|
1
|
+
# @quackai/q402-mcp
|
|
2
|
+
|
|
3
|
+
> 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.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@quackai/q402-mcp)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
> **🎟️ Free trial available (2026-05-19 → 2026-06-30)** — 2,000 gasless transactions on BNB Chain (USDC + USDT), 30-day window, no card. One wallet signature: <https://q402.quackai.ai>.
|
|
9
|
+
>
|
|
10
|
+
> **Trial-scope policy:** API keys minted under the free-trial program (`plan: "trial"`) are restricted to BNB Chain with USDC/USDT — server-side enforcement, returns `403 TRIAL_BNB_ONLY` otherwise. **Paid API keys see the full 8-chain matrix at all times.**
|
|
11
|
+
|
|
12
|
+
Claude can now reason about stablecoin payments end to end — quote a transfer across 8 chains, pick the cheapest route, and (optionally) settle the transaction over [Q402](https://q402.quackai.ai)'s EIP-7702 relayer infrastructure. The recipient receives the full amount; the sender pays $0 in gas.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
The server speaks stdio MCP, so any MCP-compatible client can use it. The two paths verified end-to-end today are **Claude (Desktop / Code)** and **OpenAI Codex CLI**.
|
|
19
|
+
|
|
20
|
+
### Claude Desktop / Claude Code
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
claude mcp add q402 -- npx -y @quackai/q402-mcp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or edit `claude_desktop_config.json` directly:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"q402": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "@quackai/q402-mcp"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Restart Claude Desktop and ask:
|
|
40
|
+
|
|
41
|
+
> *"Compare gas costs to send 50 USDC to vitalik.eth across all 8 Q402 chains."*
|
|
42
|
+
|
|
43
|
+
### OpenAI Codex CLI
|
|
44
|
+
|
|
45
|
+
Three install paths — pick the one that matches your workflow.
|
|
46
|
+
|
|
47
|
+
**(a) Codex plugin marketplace** (recommended — bundles the MCP config so users don't write TOML):
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
codex plugin marketplace add bitgett/q402-mcp
|
|
51
|
+
codex /plugins # browse and install "q402"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This repo carries a Codex plugin manifest at [`.codex-plugin/plugin.json`](./.codex-plugin/plugin.json) and a marketplace catalog at [`.agents/plugins/marketplace.json`](./.agents/plugins/marketplace.json), so any signed-in Codex user can register it as a marketplace source and install with one click.
|
|
55
|
+
|
|
56
|
+
**(b) Single MCP server via `codex mcp add`** (no plugin wrapper — just register the stdio server):
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
codex mcp add q402 -- npx -y @quackai/q402-mcp
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**(c) Direct `~/.codex/config.toml` edit** (`.codex/config.toml` for per-project scope):
|
|
63
|
+
|
|
64
|
+
```toml
|
|
65
|
+
[mcp_servers.q402]
|
|
66
|
+
command = "npx"
|
|
67
|
+
args = ["-y", "@quackai/q402-mcp"]
|
|
68
|
+
startup_timeout_sec = 20.0
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
To enable real on-chain payments, pass the three live-mode env vars **explicitly** under `env` — Codex does **not** forward host env vars by default:
|
|
72
|
+
|
|
73
|
+
```toml
|
|
74
|
+
[mcp_servers.q402]
|
|
75
|
+
command = "npx"
|
|
76
|
+
args = ["-y", "@quackai/q402-mcp"]
|
|
77
|
+
startup_timeout_sec = 20.0
|
|
78
|
+
env = {
|
|
79
|
+
Q402_API_KEY = "q402_live_...",
|
|
80
|
+
Q402_PRIVATE_KEY = "0xabc...",
|
|
81
|
+
Q402_ENABLE_REAL_PAYMENTS = "1",
|
|
82
|
+
Q402_MAX_AMOUNT_PER_CALL = "5",
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> If you'd rather not inline secrets in `config.toml`, use the `env_vars` allow-list form to forward specific names from your shell environment instead — see the [Codex config reference](https://developers.openai.com/codex/config-reference) for the full schema.
|
|
87
|
+
|
|
88
|
+
Then run `codex` and ask the same kind of question. The first call may take a few seconds while `npx` warms its cache; subsequent calls are instant.
|
|
89
|
+
|
|
90
|
+
### Any other MCP client
|
|
91
|
+
|
|
92
|
+
The server has no client-specific code. If your client speaks stdio MCP, point it at `npx -y @quackai/q402-mcp` and the five tools listed below will appear.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
> `Q402_RELAY_BASE_URL` overrides the relay endpoint. Set it explicitly when running against a self-hosted Q402 deployment or a non-canonical environment.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Tools exposed
|
|
101
|
+
|
|
102
|
+
| Tool | Auth | Purpose |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| `q402_quote` | none | Compare gas cost and supported tokens across chains. Read-only. |
|
|
105
|
+
| `q402_balance` | API key | Verify the API key and report its plan tier + remaining quota credits (live vs sandbox). |
|
|
106
|
+
| `q402_pay` | API key + private key + flag | Send a gasless payment to a single recipient. **Sandbox by default** — see [Sandbox vs live mode](#sandbox-vs-live-mode). |
|
|
107
|
+
| `q402_batch_pay` | API key + private key + flag | Send a gasless payment to **multiple** recipients in one call on a single chain × token. Trial keys: 5 rows max. Paid keys: 20 rows max. **Supported chains: avax, bnb, eth, mantle, injective, monad** (default EIP-7702 mode). xlayer + stable are NOT batchable — use `q402_pay` in a loop for those. Same sandbox gating as `q402_pay`. **Rate-limit note:** the inner `/api/relay` budget (30/min per key) is consumed per row, so a paid 20-row batch leaves ~10 inner slots for the next minute. |
|
|
108
|
+
| `q402_receipt` | none | Look up a Trust Receipt by `rct_…` id and locally verify its ECDSA signature against the relayer EOA. Returns the public settlement record + a `verified` boolean. *receiptId-only today; tx-hash lookup reserved for a future release.* |
|
|
109
|
+
|
|
110
|
+
`q402_pay` and `q402_batch_pay` follow a "confirm in chat first" contract: the tool description instructs the model to never call it without explicit user approval of the recipient address(es), amount(s), chain, and token. For batch calls the user must approve the **full batch**, not the individual rows.
|
|
111
|
+
|
|
112
|
+
`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:
|
|
113
|
+
|
|
114
|
+
> *"Pay 0.10 USDT on BNB to vitalik.eth, then verify the receipt."*
|
|
115
|
+
> *"Is `rct_afa5f50bc49a65ebba3b28ab` a real Q402 receipt? Verify the signature."*
|
|
116
|
+
|
|
117
|
+
> 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.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Sandbox vs live mode
|
|
122
|
+
|
|
123
|
+
By default the MCP server operates in **sandbox mode**: `q402_pay` returns a deterministic-looking fake transaction hash, no funds move, no gas-tank credit is consumed. That makes it safe to plug into any MCP client without worrying about an LLM hallucinating a payment.
|
|
124
|
+
|
|
125
|
+
To enable real on-chain transactions, **all three** environment variables must be set:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
Q402_API_KEY=q402_live_... # live-tier key from /dashboard
|
|
129
|
+
Q402_PRIVATE_KEY=0xabc... # signer for the payer EOA
|
|
130
|
+
Q402_ENABLE_REAL_PAYMENTS=1 # explicit opt-in
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Anything missing → automatic sandbox fallback with a hint pointing at what to set.
|
|
134
|
+
|
|
135
|
+
### Hard caps
|
|
136
|
+
|
|
137
|
+
Two additional guards run before every payment regardless of mode:
|
|
138
|
+
|
|
139
|
+
| Env var | Default | Effect |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| `Q402_MAX_AMOUNT_PER_CALL` | `5` | Reject any single call where `amount > N` USD-equivalent. |
|
|
142
|
+
| `Q402_ALLOWED_RECIPIENTS` | (empty = off) | Comma-separated address allowlist. When set, all other recipients are rejected. |
|
|
143
|
+
|
|
144
|
+
Combined with the `confirm: true` argument the tool requires, this means the model needs (a) explicit user OK in chat, (b) amount ≤ cap, (c) recipient on allowlist if one exists, (d) all three live-mode env vars set, before a single wei moves.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Configuration reference
|
|
149
|
+
|
|
150
|
+
| Env var | Required for | Notes |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| `Q402_API_KEY` | balance, live-pay | Issue at https://q402.quackai.ai/dashboard. `q402_test_*` keys keep sandbox on. |
|
|
153
|
+
| `Q402_PRIVATE_KEY` | live-pay | Signer for the payer EOA. **Never share. Never paste in chat.** |
|
|
154
|
+
| `Q402_ENABLE_REAL_PAYMENTS` | live-pay | Set to `1` to opt in. Any other value (or unset) → sandbox. |
|
|
155
|
+
| `Q402_MAX_AMOUNT_PER_CALL` | optional | USD-equivalent cap. Defaults to `5`. |
|
|
156
|
+
| `Q402_ALLOWED_RECIPIENTS` | optional | Comma-separated lowercase addresses. Defaults to no allowlist. |
|
|
157
|
+
| `Q402_RELAY_BASE_URL` | optional | Defaults to `https://q402.quackai.ai/api`. Override for self-hosted Q402. |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Supported chains
|
|
162
|
+
|
|
163
|
+
| Chain | Chain ID | Token(s) | Notes |
|
|
164
|
+
|---|---|---|---|
|
|
165
|
+
| BNB Chain | 56 | USDC, USDT | |
|
|
166
|
+
| Ethereum | 1 | USDC, USDT, **RLUSD** | L1 — gas is volatile, quote is a snapshot. RLUSD (Ripple USD, NY DFS regulated, decimals 18) Ethereum-only. |
|
|
167
|
+
| Avalanche C-Chain | 43114 | USDC, USDT | |
|
|
168
|
+
| X Layer | 196 | USDC, USDT | |
|
|
169
|
+
| Stable | 988 | USDT0 (USDC and USDT both alias) | Gas paid in USDT0. |
|
|
170
|
+
| Mantle | 5000 | USDC, USDT0 | LayerZero OFT USDT0 since 2025-11-27. |
|
|
171
|
+
| Injective EVM | 1776 | USDT only | Native USDC via Circle CCTP announced for Q2 2026. |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Why this exists
|
|
176
|
+
|
|
177
|
+
x402 standardised "402 Payment Required" semantics for AI agents but the official Coinbase facilitator only covers a few chains and assumes ERC-3009 token support — which excludes BNB USDT, Mantle USDT0, Injective USDT, and the chains where most stablecoin volume actually lives.
|
|
178
|
+
|
|
179
|
+
Q402 implements the same payer experience (single signature, $0 gas, instant settlement) on all 7 of those chains using EIP-7702 delegated execution, which works with any ERC-20. This MCP server makes that infrastructure addressable from Claude itself.
|
|
180
|
+
|
|
181
|
+
If you want to dig into how the wire protocol differs from x402, see [Q402 docs](https://q402.quackai.ai/docs).
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Repository
|
|
186
|
+
|
|
187
|
+
Source code: https://github.com/bitgett/q402-mcp
|
|
188
|
+
Issues / requests: https://github.com/bitgett/q402-mcp/issues
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
Apache-2.0 — see [LICENSE](./LICENSE).
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
|
|
11
11
|
// src/config.ts
|
|
12
12
|
import { isAddress } from "ethers";
|
|
13
|
-
var DEFAULT_RELAY_BASE = "https://q402
|
|
13
|
+
var DEFAULT_RELAY_BASE = "https://q402.quackai.ai/api";
|
|
14
14
|
var DEFAULT_MAX_AMOUNT = 5;
|
|
15
15
|
function classifyApiKey(k) {
|
|
16
16
|
if (!k) return "missing";
|
|
@@ -58,7 +58,8 @@ var CHAIN_KEYS = [
|
|
|
58
58
|
"xlayer",
|
|
59
59
|
"stable",
|
|
60
60
|
"mantle",
|
|
61
|
-
"injective"
|
|
61
|
+
"injective",
|
|
62
|
+
"monad"
|
|
62
63
|
];
|
|
63
64
|
var CHAIN_CONFIG = {
|
|
64
65
|
avax: {
|
|
@@ -161,6 +162,20 @@ var CHAIN_CONFIG = {
|
|
|
161
162
|
supportedTokens: ["USDT"],
|
|
162
163
|
approxGasCostUsd: 4e-3,
|
|
163
164
|
note: "USDT only until Circle CCTP native USDC ships (announced for Q2 2026)."
|
|
165
|
+
},
|
|
166
|
+
monad: {
|
|
167
|
+
key: "monad",
|
|
168
|
+
name: "Monad",
|
|
169
|
+
chainId: 143,
|
|
170
|
+
domainName: "Q402 Monad",
|
|
171
|
+
implContract: "0x39Ba9520718eE069D7f72882FF4C28a5Ea8a2acC",
|
|
172
|
+
gasToken: "MON",
|
|
173
|
+
explorer: "https://monadscan.com",
|
|
174
|
+
// Native Circle USDC via CCTP V2 (not bridged) + USDT0 (LayerZero OFT).
|
|
175
|
+
usdc: { address: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603", decimals: 6 },
|
|
176
|
+
usdt: { address: "0xe7cd86e13AC4309349F30B3435a9d337750fC82D", decimals: 6 },
|
|
177
|
+
supportedTokens: ["USDC", "USDT"],
|
|
178
|
+
approxGasCostUsd: 2e-3
|
|
164
179
|
}
|
|
165
180
|
};
|
|
166
181
|
var BNB_FOCUS_MODE = false;
|
|
@@ -198,8 +213,8 @@ var QuoteInputSchema = z.object({
|
|
|
198
213
|
token: z.enum(["USDC", "USDT", "RLUSD"]).optional().describe(
|
|
199
214
|
'Optional token filter. USDC / USDT are supported on most chains; RLUSD (Ripple USD, NY DFS regulated, decimals 18) is Ethereum-only \u2014 passing RLUSD here narrows the quote to chain="eth".'
|
|
200
215
|
),
|
|
201
|
-
chain: z.enum(["avax", "bnb", "eth", "xlayer", "stable", "mantle", "injective"]).optional().describe(
|
|
202
|
-
"Optional chain filter. When omitted, all
|
|
216
|
+
chain: z.enum(["avax", "bnb", "eth", "xlayer", "stable", "mantle", "injective", "monad"]).optional().describe(
|
|
217
|
+
"Optional chain filter. When omitted, all 8 chains are compared and ranked by gas cost."
|
|
203
218
|
)
|
|
204
219
|
});
|
|
205
220
|
function quoteForChain(cfg) {
|
|
@@ -240,7 +255,7 @@ function runQuote(input) {
|
|
|
240
255
|
}
|
|
241
256
|
var QUOTE_TOOL = {
|
|
242
257
|
name: "q402_quote",
|
|
243
|
-
description: "Compare gas costs and supported tokens across the
|
|
258
|
+
description: "Compare gas costs and supported tokens across the 8 chains Q402 relays for (avax, bnb, eth, xlayer, stable, mantle, injective, monad). Trial-tier API keys see BNB-only quotes (q402_pay enforces the same scope server-side); paid-tier keys see the full matrix including 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 sees what's currently routable on their tier.",
|
|
244
259
|
// Plain JSON schema mirroring the Zod schema above; MCP servers receive parameters as JSON.
|
|
245
260
|
inputSchema: {
|
|
246
261
|
type: "object",
|
|
@@ -257,7 +272,7 @@ var QUOTE_TOOL = {
|
|
|
257
272
|
chain: {
|
|
258
273
|
type: "string",
|
|
259
274
|
enum: CHAIN_KEYS,
|
|
260
|
-
description: "Optional chain filter; omit to compare all
|
|
275
|
+
description: "Optional chain filter; omit to compare all 8."
|
|
261
276
|
}
|
|
262
277
|
},
|
|
263
278
|
required: ["amount"],
|
|
@@ -281,11 +296,12 @@ import {
|
|
|
281
296
|
var DEFAULT_RPC = {
|
|
282
297
|
1: "https://ethereum.publicnode.com",
|
|
283
298
|
56: "https://bsc-dataseed1.binance.org/",
|
|
284
|
-
|
|
299
|
+
143: "https://rpc.monad.xyz",
|
|
285
300
|
196: "https://rpc.xlayer.tech",
|
|
286
301
|
988: "https://rpc.stable.xyz",
|
|
302
|
+
1776: "https://sentry.evm-rpc.injective.network/",
|
|
287
303
|
5e3: "https://rpc.mantle.xyz",
|
|
288
|
-
|
|
304
|
+
43114: "https://api.avax.network/ext/bc/C/rpc"
|
|
289
305
|
};
|
|
290
306
|
var TRANSFER_AUTH_TYPES = {
|
|
291
307
|
TransferAuthorization: [
|
|
@@ -480,7 +496,7 @@ var Q402NodeClient = class _Q402NodeClient {
|
|
|
480
496
|
}
|
|
481
497
|
if (chain.key === "xlayer" || chain.key === "stable") {
|
|
482
498
|
throw new Error(
|
|
483
|
-
`batchPay does not yet support chain "${chain.key}". Supported batch chains: avax, bnb, eth, mantle, injective (default EIP-7702 mode). For "${chain.key}" use pay() in a client-side loop.`
|
|
499
|
+
`batchPay does not yet support chain "${chain.key}". Supported batch chains: avax, bnb, eth, mantle, injective, monad (default EIP-7702 mode). For "${chain.key}" use pay() in a client-side loop.`
|
|
484
500
|
);
|
|
485
501
|
}
|
|
486
502
|
const rpcUrl = this.opts.rpcUrl ?? DEFAULT_RPC[chain.chainId];
|
|
@@ -606,7 +622,7 @@ function sandboxPay(chain, input) {
|
|
|
606
622
|
|
|
607
623
|
// src/tools/pay.ts
|
|
608
624
|
var PayInputSchema = z2.object({
|
|
609
|
-
chain: z2.enum(["avax", "bnb", "eth", "xlayer", "stable", "mantle", "injective"]),
|
|
625
|
+
chain: z2.enum(["avax", "bnb", "eth", "xlayer", "stable", "mantle", "injective", "monad"]),
|
|
610
626
|
to: z2.string().refine(isAddress2, "to must be a valid 0x-prefixed EVM address").describe("Recipient EVM address (0x + 40 hex)."),
|
|
611
627
|
amount: z2.string().regex(/^\d+(\.\d+)?$/, "amount must be a positive decimal string").describe('Human-readable decimal amount, e.g. "5.00".'),
|
|
612
628
|
token: z2.enum(["USDC", "USDT", "RLUSD"]).describe(
|
|
@@ -684,7 +700,7 @@ function describeSandboxReason() {
|
|
|
684
700
|
}
|
|
685
701
|
var PAY_TOOL = {
|
|
686
702
|
name: "q402_pay",
|
|
687
|
-
description: `Send a gasless USDC, USDT, or RLUSD payment via Q402. Scope depends on the API key tier: trial keys (q402_live_* with plan='trial') are restricted to chain: "bnb" + token "USDC" or "USDT" (server returns TRIAL_BNB_ONLY for anything else). Paid keys can relay across the full
|
|
703
|
+
description: `Send a gasless USDC, USDT, or RLUSD payment via Q402. Scope depends on the API key tier: trial keys (q402_live_* with plan='trial') are restricted to chain: "bnb" + token "USDC" or "USDT" (server returns TRIAL_BNB_ONLY for anything else). Paid keys can relay across the full 8-chain matrix \u2014 avax, bnb, eth, xlayer, stable, mantle, injective, monad \u2014 with USDC/USDT supported on most chains, RLUSD on Ethereum only, and Injective USDT-only. SANDBOX BY DEFAULT \u2014 no funds move unless Q402_API_KEY (live tier), Q402_PRIVATE_KEY, and Q402_ENABLE_REAL_PAYMENTS=1 are all set. The recipient receives the full amount; the sender pays $0 in gas. ALWAYS get explicit user confirmation of the exact recipient address, amount, chain, and token in conversation immediately before calling this tool.`,
|
|
688
704
|
inputSchema: {
|
|
689
705
|
type: "object",
|
|
690
706
|
properties: {
|
|
@@ -724,7 +740,7 @@ var RECIPIENT_LIMIT_TRIAL = 5;
|
|
|
724
740
|
var RECIPIENT_LIMIT_PAID = 20;
|
|
725
741
|
var CLIENT_RECIPIENT_CAP = RECIPIENT_LIMIT_PAID;
|
|
726
742
|
var BatchPayInputSchema = z3.object({
|
|
727
|
-
chain: z3.enum(["avax", "bnb", "eth", "mantle", "injective"]),
|
|
743
|
+
chain: z3.enum(["avax", "bnb", "eth", "mantle", "injective", "monad"]),
|
|
728
744
|
token: z3.enum(["USDC", "USDT", "RLUSD"]).describe(
|
|
729
745
|
"Stablecoin symbol. USDC / USDT supported on most chains (Injective is USDT-only). RLUSD (Ripple USD, NY DFS regulated, decimals 18) is Ethereum-only. The same token applies to every recipient in the batch."
|
|
730
746
|
),
|
|
@@ -843,7 +859,7 @@ function describeSandboxReason2() {
|
|
|
843
859
|
}
|
|
844
860
|
var BATCH_PAY_TOOL = {
|
|
845
861
|
name: "q402_batch_pay",
|
|
846
|
-
description: `Send gasless payments to MULTIPLE recipients on a single chain \xD7 token in one call. Trial keys (q402_live_* with plan='trial'): max ${RECIPIENT_LIMIT_TRIAL} recipients per call, BNB Chain + USDC/USDT only. Paid keys: max ${RECIPIENT_LIMIT_PAID} recipients per call across
|
|
862
|
+
description: `Send gasless payments to MULTIPLE recipients on a single chain \xD7 token in one call. Trial keys (q402_live_* with plan='trial'): max ${RECIPIENT_LIMIT_TRIAL} recipients per call, BNB Chain + USDC/USDT only. Paid keys: max ${RECIPIENT_LIMIT_PAID} recipients per call across 6 EIP-7702 default chains (avax, bnb, eth, mantle, injective, monad). xlayer + stable are NOT batchable \u2014 use q402_pay in a loop. SANDBOX BY DEFAULT \u2014 real on-chain TX only when Q402_API_KEY (live), Q402_PRIVATE_KEY, and Q402_ENABLE_REAL_PAYMENTS=1 are all set. Every recipient receives the full amount; the sender pays $0 in gas for the entire batch. 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.`,
|
|
847
863
|
inputSchema: {
|
|
848
864
|
type: "object",
|
|
849
865
|
properties: {
|
|
@@ -852,7 +868,7 @@ var BATCH_PAY_TOOL = {
|
|
|
852
868
|
// Narrower than the full chain set — xlayer and stable are NOT batchable
|
|
853
869
|
// (chain-specific nonce field shapes). Use q402_pay in a loop for
|
|
854
870
|
// those chains.
|
|
855
|
-
enum: ["avax", "bnb", "eth", "mantle", "injective"],
|
|
871
|
+
enum: ["avax", "bnb", "eth", "mantle", "injective", "monad"],
|
|
856
872
|
description: "Target chain. Applies to every recipient in the batch. xlayer + stable are NOT supported here \u2014 use q402_pay in a loop."
|
|
857
873
|
},
|
|
858
874
|
token: {
|
|
@@ -1104,7 +1120,7 @@ var RECEIPT_TOOL = {
|
|
|
1104
1120
|
|
|
1105
1121
|
// src/index.ts
|
|
1106
1122
|
var PACKAGE_NAME = "@quackai/q402-mcp";
|
|
1107
|
-
var PACKAGE_VERSION = "0.
|
|
1123
|
+
var PACKAGE_VERSION = "0.4.1";
|
|
1108
1124
|
function jsonText(value) {
|
|
1109
1125
|
return { type: "text", text: JSON.stringify(value, null, 2) };
|
|
1110
1126
|
}
|
package/package.json
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Q402 — gasless USDC, USDT, and RLUSD payments across
|
|
5
|
-
"mcpName": "io.github.bitgett/q402-mcp",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"mcp",
|
|
8
|
-
"model-context-protocol",
|
|
9
|
-
"claude",
|
|
10
|
-
"claude-desktop",
|
|
11
|
-
"claude-code",
|
|
12
|
-
"codex",
|
|
13
|
-
"openai-codex",
|
|
14
|
-
"cline",
|
|
15
|
-
"q402",
|
|
16
|
-
"x402",
|
|
17
|
-
"stablecoin",
|
|
18
|
-
"usdc",
|
|
19
|
-
"usdt",
|
|
20
|
-
"rlusd",
|
|
21
|
-
"ripple",
|
|
22
|
-
"gasless",
|
|
23
|
-
"eip-7702",
|
|
24
|
-
"payments",
|
|
25
|
-
"ai-agents"
|
|
26
|
-
],
|
|
27
|
-
"type": "module",
|
|
28
|
-
"main": "dist/index.js",
|
|
29
|
-
"bin": {
|
|
30
|
-
"q402-mcp": "dist/index.js"
|
|
31
|
-
},
|
|
32
|
-
"files": [
|
|
33
|
-
"dist",
|
|
34
|
-
"README.md",
|
|
35
|
-
"LICENSE"
|
|
36
|
-
],
|
|
37
|
-
"engines": {
|
|
38
|
-
"node": ">=18.18"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "tsup",
|
|
42
|
-
"dev": "tsup --watch",
|
|
43
|
-
"prepublishOnly": "npm run build",
|
|
44
|
-
"start": "node dist/index.js"
|
|
45
|
-
},
|
|
46
|
-
"dependencies": {
|
|
47
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
-
"ethers": "^6.16.0",
|
|
49
|
-
"zod": "^3.23.8"
|
|
50
|
-
},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"@types/node": "^20.11.0",
|
|
53
|
-
"tsup": "^8.3.0",
|
|
54
|
-
"typescript": "^5.5.0"
|
|
55
|
-
},
|
|
56
|
-
"repository": {
|
|
57
|
-
"type": "git",
|
|
58
|
-
"url": "git+https://github.com/bitgett/q402-mcp.git"
|
|
59
|
-
},
|
|
60
|
-
"homepage": "https://q402.quackai.ai/claude",
|
|
61
|
-
"bugs": {
|
|
62
|
-
"url": "https://github.com/bitgett/q402-mcp/issues"
|
|
63
|
-
},
|
|
64
|
-
"license": "Apache-2.0",
|
|
65
|
-
"author": "David Lee <davidlee@quackai.ai>",
|
|
66
|
-
"publishConfig": {
|
|
67
|
-
"access": "public"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@quackai/q402-mcp",
|
|
3
|
+
"version": "0.4.1",
|
|
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
|
+
"mcpName": "io.github.bitgett/q402-mcp",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"mcp",
|
|
8
|
+
"model-context-protocol",
|
|
9
|
+
"claude",
|
|
10
|
+
"claude-desktop",
|
|
11
|
+
"claude-code",
|
|
12
|
+
"codex",
|
|
13
|
+
"openai-codex",
|
|
14
|
+
"cline",
|
|
15
|
+
"q402",
|
|
16
|
+
"x402",
|
|
17
|
+
"stablecoin",
|
|
18
|
+
"usdc",
|
|
19
|
+
"usdt",
|
|
20
|
+
"rlusd",
|
|
21
|
+
"ripple",
|
|
22
|
+
"gasless",
|
|
23
|
+
"eip-7702",
|
|
24
|
+
"payments",
|
|
25
|
+
"ai-agents"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "dist/index.js",
|
|
29
|
+
"bin": {
|
|
30
|
+
"q402-mcp": "dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18.18"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"dev": "tsup --watch",
|
|
43
|
+
"prepublishOnly": "npm run build",
|
|
44
|
+
"start": "node dist/index.js"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
+
"ethers": "^6.16.0",
|
|
49
|
+
"zod": "^3.23.8"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^20.11.0",
|
|
53
|
+
"tsup": "^8.3.0",
|
|
54
|
+
"typescript": "^5.5.0"
|
|
55
|
+
},
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/bitgett/q402-mcp.git"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://q402.quackai.ai/claude",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/bitgett/q402-mcp/issues"
|
|
63
|
+
},
|
|
64
|
+
"license": "Apache-2.0",
|
|
65
|
+
"author": "David Lee <davidlee@quackai.ai>",
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
}
|
|
69
|
+
}
|