@quackai/q402-mcp 0.2.0 → 0.3.0
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 +9 -3
- package/dist/index.js +30 -9
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @quackai/q402-mcp
|
|
2
2
|
|
|
3
|
-
> MCP server for Q402 — gasless USDC and
|
|
3
|
+
> MCP server for Q402 — gasless USDC, USDT, and RLUSD payments across 7 EVM chains, callable directly from Claude Desktop and any other Model Context Protocol client.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@quackai/q402-mcp)
|
|
6
6
|
[](./LICENSE)
|
|
@@ -41,11 +41,17 @@ You'll get a ranked breakdown immediately — no API key, no signup, no funds at
|
|
|
41
41
|
| Tool | Auth | Purpose |
|
|
42
42
|
|---|---|---|
|
|
43
43
|
| `q402_quote` | none | Compare gas cost and supported tokens across chains. Read-only. |
|
|
44
|
-
| `q402_balance` | API key | Verify the API key and report its plan tier (live vs sandbox). |
|
|
44
|
+
| `q402_balance` | API key | Verify the API key and report its plan tier + remaining quota credits (live vs sandbox). |
|
|
45
45
|
| `q402_pay` | API key + private key + flag | Send a gasless payment. **Sandbox by default** — see [Sandbox vs live mode](#sandbox-vs-live-mode). |
|
|
46
|
+
| `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.* |
|
|
46
47
|
|
|
47
48
|
`q402_pay` follows a "confirm in chat first" contract: the tool description instructs the model to never call it without explicit user approval of the recipient address, amount, chain, and token.
|
|
48
49
|
|
|
50
|
+
`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:
|
|
51
|
+
|
|
52
|
+
> *"Pay 0.10 USDT on BNB to vitalik.eth, then verify the receipt."*
|
|
53
|
+
> *"Is `rct_afa5f50bc49a65ebba3b28ab` a real Q402 receipt? Verify the signature."*
|
|
54
|
+
|
|
49
55
|
> 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.
|
|
50
56
|
|
|
51
57
|
---
|
|
@@ -95,7 +101,7 @@ Combined with the `confirm: true` argument the tool requires, this means the mod
|
|
|
95
101
|
| Chain | Chain ID | Token(s) | Notes |
|
|
96
102
|
|---|---|---|---|
|
|
97
103
|
| BNB Chain | 56 | USDC, USDT | |
|
|
98
|
-
| Ethereum | 1 | USDC, USDT | L1 — gas is volatile, quote is a snapshot. |
|
|
104
|
+
| Ethereum | 1 | USDC, USDT, **RLUSD** | L1 — gas is volatile, quote is a snapshot. RLUSD (Ripple USD, NY DFS regulated, decimals 18) Ethereum-only. |
|
|
99
105
|
| Avalanche C-Chain | 43114 | USDC, USDT | |
|
|
100
106
|
| X Layer | 196 | USDC, USDT | |
|
|
101
107
|
| Stable | 988 | USDT0 (USDC and USDT both alias) | Gas paid in USDT0. |
|
package/dist/index.js
CHANGED
|
@@ -71,6 +71,7 @@ var CHAIN_CONFIG = {
|
|
|
71
71
|
explorer: "https://snowtrace.io",
|
|
72
72
|
usdc: { address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", decimals: 6 },
|
|
73
73
|
usdt: { address: "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", decimals: 6 },
|
|
74
|
+
supportedTokens: ["USDC", "USDT"],
|
|
74
75
|
approxGasCostUsd: 3e-3
|
|
75
76
|
},
|
|
76
77
|
bnb: {
|
|
@@ -83,6 +84,7 @@ var CHAIN_CONFIG = {
|
|
|
83
84
|
explorer: "https://bscscan.com",
|
|
84
85
|
usdc: { address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", decimals: 18 },
|
|
85
86
|
usdt: { address: "0x55d398326f99059fF775485246999027B3197955", decimals: 18 },
|
|
87
|
+
supportedTokens: ["USDC", "USDT"],
|
|
86
88
|
approxGasCostUsd: 1e-3
|
|
87
89
|
},
|
|
88
90
|
eth: {
|
|
@@ -95,8 +97,12 @@ var CHAIN_CONFIG = {
|
|
|
95
97
|
explorer: "https://etherscan.io",
|
|
96
98
|
usdc: { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", decimals: 6 },
|
|
97
99
|
usdt: { address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", decimals: 6 },
|
|
100
|
+
// Ripple USD (RLUSD) — NY DFS regulated, decimals 18, UUPS proxy.
|
|
101
|
+
// Ethereum-only; other chains' supportedTokens omits RLUSD.
|
|
102
|
+
rlusd: { address: "0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD", decimals: 18 },
|
|
103
|
+
supportedTokens: ["USDC", "USDT", "RLUSD"],
|
|
98
104
|
approxGasCostUsd: 1.2,
|
|
99
|
-
note: "L1 \u2014 gas is volatile; quote is a snapshot, expect 5\u201310x swings during congestion."
|
|
105
|
+
note: "L1 \u2014 gas is volatile; quote is a snapshot, expect 5\u201310x swings during congestion. RLUSD supported here only."
|
|
100
106
|
},
|
|
101
107
|
xlayer: {
|
|
102
108
|
key: "xlayer",
|
|
@@ -108,6 +114,7 @@ var CHAIN_CONFIG = {
|
|
|
108
114
|
explorer: "https://www.oklink.com/xlayer",
|
|
109
115
|
usdc: { address: "0x74b7F16337b8972027F6196A17a631aC6dE26d22", decimals: 6 },
|
|
110
116
|
usdt: { address: "0x1E4a5963aBFD975d8c9021ce480b42188849D41D", decimals: 6 },
|
|
117
|
+
supportedTokens: ["USDC", "USDT"],
|
|
111
118
|
approxGasCostUsd: 2e-3
|
|
112
119
|
},
|
|
113
120
|
stable: {
|
|
@@ -121,6 +128,7 @@ var CHAIN_CONFIG = {
|
|
|
121
128
|
// USDT0 (the only token on Stable) — both USDC and USDT API tokens resolve here.
|
|
122
129
|
usdc: { address: "0x779ded0c9e1022225f8e0630b35a9b54be713736", decimals: 18 },
|
|
123
130
|
usdt: { address: "0x779ded0c9e1022225f8e0630b35a9b54be713736", decimals: 18 },
|
|
131
|
+
supportedTokens: ["USDC", "USDT"],
|
|
124
132
|
approxGasCostUsd: 5e-4,
|
|
125
133
|
note: "Gas is paid in USDT0; both USDC and USDT API inputs alias to USDT0."
|
|
126
134
|
},
|
|
@@ -135,6 +143,7 @@ var CHAIN_CONFIG = {
|
|
|
135
143
|
usdc: { address: "0x09Bc4E0D864854c6aFB6eB9A9cdF58aC190D0dF9", decimals: 6 },
|
|
136
144
|
// USDT0 (LayerZero OFT) — Mantle ecosystem default since the 2025-11-27 migration.
|
|
137
145
|
usdt: { address: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736", decimals: 6 },
|
|
146
|
+
supportedTokens: ["USDC", "USDT"],
|
|
138
147
|
approxGasCostUsd: 2e-3
|
|
139
148
|
},
|
|
140
149
|
injective: {
|
|
@@ -160,13 +169,23 @@ function getChain(key) {
|
|
|
160
169
|
return cfg;
|
|
161
170
|
}
|
|
162
171
|
function tokenFor(cfg, token) {
|
|
172
|
+
if (token === "RLUSD") {
|
|
173
|
+
if (!cfg.rlusd) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`RLUSD is not supported on ${cfg.name} (key=${cfg.key}). RLUSD is currently Ethereum-only.`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return cfg.rlusd;
|
|
179
|
+
}
|
|
163
180
|
return token === "USDC" ? cfg.usdc : cfg.usdt;
|
|
164
181
|
}
|
|
165
182
|
|
|
166
183
|
// src/tools/quote.ts
|
|
167
184
|
var QuoteInputSchema = z.object({
|
|
168
185
|
amount: z.string().regex(/^\d+(\.\d+)?$/, 'amount must be a positive decimal string like "5.00"').describe('Human-readable decimal amount the user intends to send (e.g. "5", "50.00").'),
|
|
169
|
-
token: z.enum(["USDC", "USDT"]).optional().describe(
|
|
186
|
+
token: z.enum(["USDC", "USDT", "RLUSD"]).optional().describe(
|
|
187
|
+
'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".'
|
|
188
|
+
),
|
|
170
189
|
chain: z.enum(["avax", "bnb", "eth", "xlayer", "stable", "mantle", "injective"]).optional().describe(
|
|
171
190
|
"Optional chain filter. When omitted, all 7 chains are compared and ranked by gas cost."
|
|
172
191
|
)
|
|
@@ -424,7 +443,9 @@ var PayInputSchema = z2.object({
|
|
|
424
443
|
chain: z2.enum(["avax", "bnb", "eth", "xlayer", "stable", "mantle", "injective"]),
|
|
425
444
|
to: z2.string().refine(isAddress2, "to must be a valid 0x-prefixed EVM address").describe("Recipient EVM address (0x + 40 hex)."),
|
|
426
445
|
amount: z2.string().regex(/^\d+(\.\d+)?$/, "amount must be a positive decimal string").describe('Human-readable decimal amount, e.g. "5.00".'),
|
|
427
|
-
token: z2.enum(["USDC", "USDT"])
|
|
446
|
+
token: z2.enum(["USDC", "USDT", "RLUSD"]).describe(
|
|
447
|
+
"Stablecoin symbol. USDC / USDT supported on most chains (Injective is USDT-only). RLUSD (Ripple USD, NY DFS regulated, decimals 18) is Ethereum-only."
|
|
448
|
+
),
|
|
428
449
|
confirm: z2.literal(true).describe(
|
|
429
450
|
"MUST be true. Prove the user explicitly approved this exact recipient and amount in the conversation right before this tool was called. Setting this to true on behalf of the user without confirmation is a violation of the tool contract."
|
|
430
451
|
)
|
|
@@ -580,7 +601,7 @@ var ReceiptShape = z4.object({
|
|
|
580
601
|
chain: z4.string(),
|
|
581
602
|
payer: z4.string(),
|
|
582
603
|
recipient: z4.string(),
|
|
583
|
-
token: z4.enum(["USDC", "USDT"]),
|
|
604
|
+
token: z4.enum(["USDC", "USDT", "RLUSD"]),
|
|
584
605
|
tokenAmount: z4.string(),
|
|
585
606
|
tokenAmountRaw: z4.string(),
|
|
586
607
|
method: z4.enum(["eip7702", "eip3009", "eip7702_xlayer", "eip7702_stable"]),
|
|
@@ -658,7 +679,7 @@ function pageBase() {
|
|
|
658
679
|
}
|
|
659
680
|
async function runReceipt(input) {
|
|
660
681
|
const apiBase = receiptApiBase();
|
|
661
|
-
|
|
682
|
+
const receiptId = input.receiptId ?? null;
|
|
662
683
|
if (!receiptId && input.txHash) {
|
|
663
684
|
return {
|
|
664
685
|
receiptId: null,
|
|
@@ -713,19 +734,19 @@ async function runReceipt(input) {
|
|
|
713
734
|
}
|
|
714
735
|
var RECEIPT_TOOL = {
|
|
715
736
|
name: "q402_receipt",
|
|
716
|
-
description: "Look up a Q402 Trust Receipt by its rct_\u2026
|
|
737
|
+
description: "Look up a Q402 Trust Receipt by its rct_\u2026 receiptId and return the settlement record + a locally-verified ECDSA boolean (the tool re-runs the same canonical-JSON + EIP-191 recovery the receipt page does in the browser). Read-only; no API key required. Use after q402_pay to give the user a shareable verified-by-Q402 URL, or to independently verify a receipt id someone shared with you. **receiptId is required**; passing only txHash returns notFound (tx \u2192 receiptId lookup is reserved for a future release).",
|
|
717
738
|
inputSchema: {
|
|
718
739
|
type: "object",
|
|
719
740
|
properties: {
|
|
720
741
|
receiptId: {
|
|
721
742
|
type: "string",
|
|
722
743
|
pattern: "^rct_[0-9a-f]{24}$",
|
|
723
|
-
description: "Receipt id (rct_ + 24 hex chars). Returned by q402_pay; also visible at the end of any /receipt/ URL."
|
|
744
|
+
description: "Receipt id (rct_ + 24 hex chars). Returned by q402_pay; also visible at the end of any /receipt/ URL. This is the only path that resolves today."
|
|
724
745
|
},
|
|
725
746
|
txHash: {
|
|
726
747
|
type: "string",
|
|
727
748
|
pattern: "^0x[0-9a-fA-F]{64}$",
|
|
728
|
-
description: "
|
|
749
|
+
description: "Reserved for a future tx \u2192 receipt index. Today this is unimplemented and the tool returns notFound when only txHash is provided. Pass receiptId instead."
|
|
729
750
|
}
|
|
730
751
|
},
|
|
731
752
|
additionalProperties: false
|
|
@@ -734,7 +755,7 @@ var RECEIPT_TOOL = {
|
|
|
734
755
|
|
|
735
756
|
// src/index.ts
|
|
736
757
|
var PACKAGE_NAME = "@quackai/q402-mcp";
|
|
737
|
-
var PACKAGE_VERSION = "0.
|
|
758
|
+
var PACKAGE_VERSION = "0.3.0";
|
|
738
759
|
function jsonText(value) {
|
|
739
760
|
return { type: "text", text: JSON.stringify(value, null, 2) };
|
|
740
761
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Q402 — gasless USDC and
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "MCP server for Q402 — gasless USDC, USDT, and RLUSD payments across 7 EVM chains, callable directly from Claude Desktop and any other Model Context Protocol client.",
|
|
5
5
|
"mcpName": "io.github.bitgett/q402-mcp",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"stablecoin",
|
|
13
13
|
"usdc",
|
|
14
14
|
"usdt",
|
|
15
|
+
"rlusd",
|
|
16
|
+
"ripple",
|
|
15
17
|
"gasless",
|
|
16
18
|
"eip-7702",
|
|
17
19
|
"payments",
|