@quackai/q402-mcp 0.8.32 → 0.8.34
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 +2 -2
- package/dist/index.js +51 -3
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -184,9 +184,9 @@ Then export the values in `~/.zshrc` / `~/.bashrc`. See the [Codex config refere
|
|
|
184
184
|
| `q402_yield_positions` | api key | Show the Agent Wallet's open Q402 Yield positions (balance, principal, accrued interest, APY) + total supplied in USD. Mode C. |
|
|
185
185
|
| `q402_yield_deposit` | live mode | Supply the Agent Wallet's USDC/USDT into Aave V3 (Q402 Yield) to earn supply APY. Mode C, BNB-only. Requires `confirm: true`; sandbox-by-default. |
|
|
186
186
|
| `q402_yield_withdraw` | live mode | Withdraw supplied USDC/USDT out of Aave V3 back to the Agent Wallet (`amount: "max"` = full position). Mode C, BNB-only. Requires `confirm: true`; sandbox-by-default. |
|
|
187
|
-
| `q402_request_create` | api key | Publish a payment request (invoice). No funds move
|
|
187
|
+
| `q402_request_create` | api key | Publish a payment request (invoice). No funds move; returns a shareable `/pay` link + `req_…` id. Recipient defaults to the Agent Wallet. |
|
|
188
188
|
| `q402_request_status` | none | Look up a payment request by `req_…` id (amount, token, chain, recipient, status). Read-only; `notFound` instead of throwing. |
|
|
189
|
-
| `q402_request_pay` | live mode | Pay a request gaslessly from the payer's own Agent Wallet (Mode C). Terms come from the stored request
|
|
189
|
+
| `q402_request_pay` | live mode | Pay a request gaslessly from the payer's own Agent Wallet (Mode C). Terms come from the stored request, so they can't be redirected. Two-phase consent (same as `q402_pay`). |
|
|
190
190
|
|
|
191
191
|
`q402_pay` + `q402_batch_pay` + `q402_bridge_send` + `q402_yield_deposit` + `q402_yield_withdraw` + `q402_request_pay` require explicit in-chat confirmation. Batch confirmation = full batch, not per-row.
|
|
192
192
|
|
package/dist/index.js
CHANGED
|
@@ -211,7 +211,7 @@ var isValidPrivateKey = (s) => typeof s === "string" && PRIVATE_KEY_RE.test(s);
|
|
|
211
211
|
// package.json
|
|
212
212
|
var package_default = {
|
|
213
213
|
name: "@quackai/q402-mcp",
|
|
214
|
-
version: "0.8.
|
|
214
|
+
version: "0.8.34",
|
|
215
215
|
description: "MCP server for Q402 \u2014 gasless USDC/USDT/RLUSD payments on 10 EVM chains + Chainlink CCIP USDC bridge on the eth/avax/arbitrum triangle, callable from Claude (Desktop / Code), OpenAI Codex CLI, and any other Model Context Protocol client.",
|
|
216
216
|
mcpName: "io.github.bitgett/q402-mcp",
|
|
217
217
|
keywords: [
|
|
@@ -279,7 +279,9 @@ var package_default = {
|
|
|
279
279
|
access: "public"
|
|
280
280
|
},
|
|
281
281
|
overrides: {
|
|
282
|
-
esbuild: "^0.28.1"
|
|
282
|
+
esbuild: "^0.28.1",
|
|
283
|
+
ws: "^8.21.0",
|
|
284
|
+
hono: "^4.12.25"
|
|
283
285
|
}
|
|
284
286
|
};
|
|
285
287
|
|
|
@@ -1422,6 +1424,10 @@ var PAY_TOOL = {
|
|
|
1422
1424
|
const: true,
|
|
1423
1425
|
description: "MUST be true and only set after the user has confirmed this exact payment in chat. When hookParams is set, confirm what it does to the money too: the split RECIPIENTS and shares (funds go there, not `to`) and any oracle condition gating settlement \u2014 not just the top-level recipient + amount."
|
|
1424
1426
|
},
|
|
1427
|
+
consentToken: {
|
|
1428
|
+
type: "string",
|
|
1429
|
+
description: "Two-phase consent. Omit on the FIRST call to get a needs_confirmation preview plus a consentToken (no funds move); re-call with the SAME args plus this token to execute. Re-derived from the payment params, so a previewed payment cannot be swapped for a different one. confirm:true alone does NOT send."
|
|
1430
|
+
},
|
|
1425
1431
|
hookParams: {
|
|
1426
1432
|
type: "object",
|
|
1427
1433
|
description: "Q402 Hook params (server-managed Agent Wallet only). recipientAgentId (ReputationGate), condition (ConditionalOracle price/time gate), or splits (MultiPayeeSplit fan-out, bps sum 10000).",
|
|
@@ -1958,6 +1964,10 @@ TWO-PHASE CONSENT: confirm:true alone does NOT send. Call this tool first WITHOU
|
|
|
1958
1964
|
type: "boolean",
|
|
1959
1965
|
const: true,
|
|
1960
1966
|
description: "MUST be true and only set after the user has confirmed the entire batch in chat."
|
|
1967
|
+
},
|
|
1968
|
+
consentToken: {
|
|
1969
|
+
type: "string",
|
|
1970
|
+
description: "Two-phase consent. Omit on the FIRST call to get a needs_confirmation preview of every recipient + amount plus a consentToken (no funds move); re-call with the SAME args plus this token to execute. Re-derived from the batch, so the previewed batch cannot be swapped. confirm:true alone does NOT send."
|
|
1961
1971
|
}
|
|
1962
1972
|
},
|
|
1963
1973
|
required: ["chain", "token", "recipients", "confirm"],
|
|
@@ -4945,7 +4955,10 @@ import { z as z27 } from "zod";
|
|
|
4945
4955
|
var RequestPayInputSchema = z27.object({
|
|
4946
4956
|
requestId: z27.string().regex(/^req_[0-9a-f]{24}$/, "requestId must match req_<24-hex>").describe("The payment request to pay (req_ + 24 hex). Get it from a /pay link, a 402 response, or whoever billed you."),
|
|
4947
4957
|
confirm: z27.literal(true).describe(
|
|
4948
|
-
"REQUIRED. Must be literally `true`.
|
|
4958
|
+
"REQUIRED. Must be literally `true`. Acknowledges this moves real funds from your Agent Wallet."
|
|
4959
|
+
),
|
|
4960
|
+
consentToken: z27.string().optional().describe(
|
|
4961
|
+
'Two-phase consent, identical to q402_pay. Call FIRST WITHOUT it: the tool moves no money and returns status="needs_consent" with a `preview` of the exact payment plus a `consentToken`. Relay the preview to the user, get an explicit yes, then re-call with the SAME requestId PLUS this consentToken. The token is re-derived from the request\'s terms, so a previewed payment cannot be swapped for a different one. confirm:true alone does NOT fire a payment.'
|
|
4949
4962
|
),
|
|
4950
4963
|
walletId: z27.string().optional().describe("Optional lowercased Agent Wallet address to pay from when you hold multiple. Defaults to Q402_AGENT_WALLET_ADDRESS, then the server default.")
|
|
4951
4964
|
});
|
|
@@ -4973,6 +4986,37 @@ async function runRequestPay(input) {
|
|
|
4973
4986
|
if (CONFIG.allowedRecipients.length > 0 && !CONFIG.allowedRecipients.includes(req.recipient.toLowerCase())) {
|
|
4974
4987
|
return { ok: false, status: "not_payable", requestId: req.id, txHash: null, receiptId: null, ...terms, error: "RECIPIENT_NOT_ALLOWED", message: `Recipient ${req.recipient} is not in Q402_ALLOWED_RECIPIENTS.` };
|
|
4975
4988
|
}
|
|
4989
|
+
const consentIntent = {
|
|
4990
|
+
t: "request_pay",
|
|
4991
|
+
requestId: req.id,
|
|
4992
|
+
to: req.recipient.toLowerCase(),
|
|
4993
|
+
amount: req.amount,
|
|
4994
|
+
token: req.token,
|
|
4995
|
+
chain: req.chain,
|
|
4996
|
+
// Bind the funding source too — the user is consenting to pay from THIS
|
|
4997
|
+
// wallet, so swapping walletId after the preview must void consent. Mirrors
|
|
4998
|
+
// q402_pay's consentIntent. Empty string = the server-default Agent Wallet
|
|
4999
|
+
// (resolved at settle time); pinning a specific wallet re-triggers consent.
|
|
5000
|
+
wid: (input.walletId ?? "").toLowerCase()
|
|
5001
|
+
};
|
|
5002
|
+
const consent = checkConsent(consentIntent, input.consentToken);
|
|
5003
|
+
if (!consent.ok) {
|
|
5004
|
+
const fromNote = input.walletId ? ` from wallet ${input.walletId}` : "";
|
|
5005
|
+
return {
|
|
5006
|
+
ok: false,
|
|
5007
|
+
status: "needs_consent",
|
|
5008
|
+
requestId: req.id,
|
|
5009
|
+
txHash: null,
|
|
5010
|
+
receiptId: null,
|
|
5011
|
+
...terms,
|
|
5012
|
+
message: "Relay this preview to the user and get an explicit yes, then re-call with the same requestId plus consentToken. No funds moved.",
|
|
5013
|
+
needsConsent: {
|
|
5014
|
+
status: "needs_confirmation",
|
|
5015
|
+
preview: `Pay ${req.amount} ${req.token} to ${req.recipient} on ${req.chain}${fromNote} (request ${req.id}).`,
|
|
5016
|
+
consentToken: consent.expected
|
|
5017
|
+
}
|
|
5018
|
+
};
|
|
5019
|
+
}
|
|
4976
5020
|
const resolved = resolveApiKey(req.chain, "auto");
|
|
4977
5021
|
if (!resolved.apiKey || !resolved.apiKey.startsWith("q402_live_")) {
|
|
4978
5022
|
return {
|
|
@@ -5039,6 +5083,10 @@ var REQUEST_PAY_TOOL = {
|
|
|
5039
5083
|
walletId: {
|
|
5040
5084
|
type: "string",
|
|
5041
5085
|
description: "Optional. Agent Wallet address to pay from. Defaults to the configured / server-default wallet."
|
|
5086
|
+
},
|
|
5087
|
+
consentToken: {
|
|
5088
|
+
type: "string",
|
|
5089
|
+
description: "Two-phase consent. Omit on the FIRST call to get a needs_confirmation preview plus a consentToken (no funds move); re-call with the SAME requestId plus this token to execute. Re-derived from the request terms + funding wallet, so a previewed payment cannot be swapped for a different one."
|
|
5042
5090
|
}
|
|
5043
5091
|
},
|
|
5044
5092
|
required: ["requestId", "confirm"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.34",
|
|
4
4
|
"description": "MCP server for Q402 — gasless USDC/USDT/RLUSD payments on 10 EVM chains + Chainlink CCIP USDC bridge on the eth/avax/arbitrum triangle, 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": [
|
|
@@ -68,6 +68,8 @@
|
|
|
68
68
|
"access": "public"
|
|
69
69
|
},
|
|
70
70
|
"overrides": {
|
|
71
|
-
"esbuild": "^0.28.1"
|
|
71
|
+
"esbuild": "^0.28.1",
|
|
72
|
+
"ws": "^8.21.0",
|
|
73
|
+
"hono": "^4.12.25"
|
|
72
74
|
}
|
|
73
75
|
}
|