@quackai/q402-mcp 0.8.9 → 0.8.11
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 +1 -1
- package/dist/index.js +134 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -177,7 +177,7 @@ Then export the values in `~/.zshrc` / `~/.bashrc`. See the [Codex config refere
|
|
|
177
177
|
| `q402_recurring_skip_next` | api key | Skip only the next scheduled fire. |
|
|
178
178
|
| `q402_recurring_cancel` | api key | Permanently stop a rule. |
|
|
179
179
|
| `q402_bridge_quote` | none | Quote a Chainlink CCIP USDC bridge across eth/avax/arbitrum. Returns LINK + native fee. |
|
|
180
|
-
| `q402_bridge_send` |
|
|
180
|
+
| `q402_bridge_send` | live mode | Execute a CCIP bridge from the user's Agent Wallet. Mode C only (server-managed). Sandbox-by-default; `sandbox: false` + live Multichain key + `Q402_ENABLE_REAL_PAYMENTS=1` fires a real on-chain bridge. |
|
|
181
181
|
| `q402_bridge_history` | not yet wired | Pointer to the dashboard. Returns `{ implemented: false, dashboardUrl, dashboardPath }` — read-only guidance until owner-sig auth lands in MCP. |
|
|
182
182
|
| `q402_bridge_gas_tank` | not yet wired | Static guidance + dashboard pointer for the Bridge Gas Tank top-up flow. Live balance lookup needs owner-sig auth (dashboard for now). |
|
|
183
183
|
|
package/dist/index.js
CHANGED
|
@@ -211,7 +211,7 @@ var isValidPrivateKey = (s) => typeof s === "string" && PRIVATE_KEY_RE.test(s);
|
|
|
211
211
|
|
|
212
212
|
// src/version.ts
|
|
213
213
|
var PACKAGE_NAME = "@quackai/q402-mcp";
|
|
214
|
-
var PACKAGE_VERSION = "0.8.
|
|
214
|
+
var PACKAGE_VERSION = "0.8.11";
|
|
215
215
|
|
|
216
216
|
// src/tools/quote.ts
|
|
217
217
|
import { z } from "zod";
|
|
@@ -2897,23 +2897,23 @@ var BridgeSendInputSchema = z11.object({
|
|
|
2897
2897
|
src: z11.enum(["eth", "avax", "arbitrum"]).describe("Source chain"),
|
|
2898
2898
|
dst: z11.enum(["eth", "avax", "arbitrum"]).describe("Destination chain"),
|
|
2899
2899
|
// `^\d+$` accepts "0" which is a no-op bridge. Require at least one
|
|
2900
|
-
// non-zero digit
|
|
2901
|
-
//
|
|
2902
|
-
// "success" envelope in sandbox.
|
|
2900
|
+
// non-zero digit so an accidental amount=0 fails locally instead of
|
|
2901
|
+
// returning a synthetic "success" envelope in sandbox.
|
|
2903
2902
|
amount: z11.string().regex(/^\d*[1-9]\d*$/).describe("USDC amount in raw 6-decimal units, > 0"),
|
|
2904
|
-
walletId: z11.string().describe("Agentic Wallet ID (from q402_agentic_info)"),
|
|
2905
|
-
feeToken: z11.enum(["LINK", "native"
|
|
2906
|
-
sandbox: z11.boolean().optional().describe("Sandbox mode (default true). Set to false for live bridge.")
|
|
2903
|
+
walletId: z11.string().optional().describe("Agentic Wallet ID (from q402_agentic_info). Optional \u2014 defaults to the owner's default Agent Wallet."),
|
|
2904
|
+
feeToken: z11.enum(["LINK", "native"]).optional().describe("Fee token. Defaults to LINK (~10% cheaper than native)."),
|
|
2905
|
+
sandbox: z11.boolean().optional().describe("Sandbox mode (default true). Set to false for a live on-chain bridge."),
|
|
2906
|
+
maxFeeRaw: z11.string().regex(/^\d+$/).optional().describe("Optional client-side fee cap in raw 18-dec wei. Server still clamps to its 10% slippage ceiling; clients may LOWER but not RAISE.")
|
|
2907
2907
|
}).refine((d) => d.src !== d.dst, {
|
|
2908
2908
|
// Local Zod rejection saves a network round-trip + a Q402 backend log
|
|
2909
|
-
// entry. The
|
|
2910
|
-
//
|
|
2909
|
+
// entry. The bridge route also rejects same-chain bridges but the
|
|
2910
|
+
// agent only finds out after burning a request.
|
|
2911
2911
|
message: "src must differ from dst",
|
|
2912
2912
|
path: ["dst"]
|
|
2913
2913
|
});
|
|
2914
2914
|
var BRIDGE_SEND_TOOL = {
|
|
2915
2915
|
name: "q402_bridge_send",
|
|
2916
|
-
description: "
|
|
2916
|
+
description: "Execute a Chainlink CCIP USDC bridge across the 3-chain triangle (eth/avax/arbitrum) on behalf of the user's server-managed Agentic Wallet (Mode C). Sandbox-by-default \u2014 returns a synthetic messageId unless `sandbox: false` is passed AND Q402_ENABLE_REAL_PAYMENTS=1 AND a live Multichain API key is configured. The server signs ccipSend with the Agent Wallet's encrypted PK, auto-funds source-chain gas from the user's Gas Tank, and debits both the auto- fund cost and the CCIP fee per the bridge's settled receipt. Recommended flow: q402_bridge_quote first \u2192 confirm cost with the user \u2192 q402_bridge_send with sandbox: false. Live mode needs a Multichain subscription; trial keys are rejected. If the bridge returns AGENT_WALLET_DELEGATED, run q402_clear_delegation on the source chain first.",
|
|
2917
2917
|
inputSchema: {
|
|
2918
2918
|
type: "object",
|
|
2919
2919
|
properties: {
|
|
@@ -2929,50 +2929,149 @@ var BRIDGE_SEND_TOOL = {
|
|
|
2929
2929
|
},
|
|
2930
2930
|
amount: {
|
|
2931
2931
|
type: "string",
|
|
2932
|
-
pattern: "
|
|
2933
|
-
description: "USDC amount in raw 6-decimal units (e.g. '1000000' = 1 USDC). Integer string
|
|
2932
|
+
pattern: "^\\d*[1-9]\\d*$",
|
|
2933
|
+
description: "USDC amount in raw 6-decimal units (e.g. '1000000' = 1 USDC). Integer string, > 0."
|
|
2934
2934
|
},
|
|
2935
2935
|
walletId: {
|
|
2936
2936
|
type: "string",
|
|
2937
|
-
description: "Agentic Wallet ID (from q402_agentic_info)."
|
|
2937
|
+
description: "Agentic Wallet ID (from q402_agentic_info). Optional \u2014 defaults to the owner's default Agent Wallet when omitted."
|
|
2938
2938
|
},
|
|
2939
2939
|
feeToken: {
|
|
2940
2940
|
type: "string",
|
|
2941
|
-
enum: ["LINK", "native"
|
|
2942
|
-
description: "Fee token. Default: LINK (~10% cheaper).
|
|
2941
|
+
enum: ["LINK", "native"],
|
|
2942
|
+
description: "Fee token. Default: LINK (~10% cheaper)."
|
|
2943
2943
|
},
|
|
2944
2944
|
sandbox: {
|
|
2945
2945
|
type: "boolean",
|
|
2946
|
-
description: "Sandbox
|
|
2946
|
+
description: "Sandbox mode (default true). Set to false for a real on-chain bridge."
|
|
2947
|
+
},
|
|
2948
|
+
maxFeeRaw: {
|
|
2949
|
+
type: "string",
|
|
2950
|
+
pattern: "^[0-9]+$",
|
|
2951
|
+
description: "Optional client-side fee cap in raw 18-dec wei."
|
|
2947
2952
|
}
|
|
2948
2953
|
},
|
|
2949
|
-
required: ["src", "dst", "amount"
|
|
2954
|
+
required: ["src", "dst", "amount"]
|
|
2950
2955
|
}
|
|
2951
2956
|
};
|
|
2957
|
+
function sandbox(input, note) {
|
|
2958
|
+
return {
|
|
2959
|
+
sandbox: true,
|
|
2960
|
+
messageId: "0x" + "00".repeat(32),
|
|
2961
|
+
txHash: "0x" + "00".repeat(32),
|
|
2962
|
+
note,
|
|
2963
|
+
src: input.src,
|
|
2964
|
+
dst: input.dst,
|
|
2965
|
+
amount: input.amount
|
|
2966
|
+
};
|
|
2967
|
+
}
|
|
2952
2968
|
async function runBridgeSend(input) {
|
|
2953
|
-
|
|
2954
|
-
|
|
2969
|
+
if (input.sandbox !== false) {
|
|
2970
|
+
return {
|
|
2971
|
+
content: [{
|
|
2972
|
+
type: "text",
|
|
2973
|
+
text: JSON.stringify(
|
|
2974
|
+
sandbox(input, "Sandbox response. Pass `sandbox: false` AND set Q402_ENABLE_REAL_PAYMENTS=1 (with a live Q402_MULTICHAIN_API_KEY) to fire a real bridge."),
|
|
2975
|
+
null,
|
|
2976
|
+
2
|
|
2977
|
+
)
|
|
2978
|
+
}]
|
|
2979
|
+
};
|
|
2980
|
+
}
|
|
2981
|
+
const resolved = resolveApiKey(input.src, "multichain");
|
|
2982
|
+
if (!resolved.apiKey) {
|
|
2983
|
+
return {
|
|
2984
|
+
content: [{
|
|
2985
|
+
type: "text",
|
|
2986
|
+
text: JSON.stringify(
|
|
2987
|
+
sandbox(input, resolved.sandboxReason ?? "No live Multichain API key configured. Set Q402_MULTICHAIN_API_KEY to a q402_live_\u2026 key from https://q402.quackai.ai/payment."),
|
|
2988
|
+
null,
|
|
2989
|
+
2
|
|
2990
|
+
)
|
|
2991
|
+
}]
|
|
2992
|
+
};
|
|
2993
|
+
}
|
|
2994
|
+
if (!resolved.apiKey.startsWith("q402_live_")) {
|
|
2995
|
+
return {
|
|
2996
|
+
content: [{
|
|
2997
|
+
type: "text",
|
|
2998
|
+
text: JSON.stringify(
|
|
2999
|
+
sandbox(input, "Resolved API key is not a live key. Set Q402_MULTICHAIN_API_KEY to a q402_live_\u2026 key."),
|
|
3000
|
+
null,
|
|
3001
|
+
2
|
|
3002
|
+
)
|
|
3003
|
+
}]
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
if (!CONFIG.realPaymentsRequested) {
|
|
3007
|
+
return {
|
|
3008
|
+
content: [{
|
|
3009
|
+
type: "text",
|
|
3010
|
+
text: JSON.stringify(
|
|
3011
|
+
sandbox(input, "Q402_ENABLE_REAL_PAYMENTS is not set to 1. Set the env var to fire a real bridge."),
|
|
3012
|
+
null,
|
|
3013
|
+
2
|
|
3014
|
+
)
|
|
3015
|
+
}]
|
|
3016
|
+
};
|
|
3017
|
+
}
|
|
3018
|
+
const walletId = typeof input.walletId === "string" && input.walletId.length > 0 ? input.walletId.toLowerCase() : CONFIG.walletId ?? void 0;
|
|
3019
|
+
const feeToken = input.feeToken === "native" ? "native" : "LINK";
|
|
3020
|
+
let resp;
|
|
3021
|
+
try {
|
|
3022
|
+
resp = await fetch(`${CONFIG.relayBaseUrl}/wallet/agentic/bridge`, {
|
|
3023
|
+
method: "POST",
|
|
3024
|
+
headers: { "Content-Type": "application/json" },
|
|
3025
|
+
body: JSON.stringify({
|
|
3026
|
+
apiKey: resolved.apiKey,
|
|
3027
|
+
...walletId ? { walletId } : {},
|
|
3028
|
+
src: input.src,
|
|
3029
|
+
dst: input.dst,
|
|
3030
|
+
amount: input.amount,
|
|
3031
|
+
feeToken,
|
|
3032
|
+
...input.maxFeeRaw ? { maxFeeRaw: input.maxFeeRaw } : {}
|
|
3033
|
+
}),
|
|
3034
|
+
signal: AbortSignal.timeout(9e4)
|
|
3035
|
+
});
|
|
3036
|
+
} catch (e) {
|
|
3037
|
+
return {
|
|
3038
|
+
content: [{
|
|
3039
|
+
type: "text",
|
|
3040
|
+
text: `Bridge fetch failed: ${e instanceof Error ? e.message : String(e)}. Retry; if the relay 60s budget timed out, the bridge may still be in flight \u2014 check the dashboard's Bridge History or CCIP Explorer before re-firing.`
|
|
3041
|
+
}],
|
|
3042
|
+
isError: true
|
|
3043
|
+
};
|
|
3044
|
+
}
|
|
3045
|
+
const data = await resp.json().catch(() => ({}));
|
|
3046
|
+
if (!resp.ok || !data.success) {
|
|
2955
3047
|
return {
|
|
2956
3048
|
content: [{
|
|
2957
3049
|
type: "text",
|
|
2958
3050
|
text: JSON.stringify({
|
|
2959
|
-
sandbox:
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
note: "Sandbox response. To execute a real bridge, pass `sandbox: false` AND ensure the server has Q402_ENABLE_REAL_PAYMENTS=1.",
|
|
2963
|
-
src: input.src,
|
|
2964
|
-
dst: input.dst,
|
|
2965
|
-
amount: input.amount
|
|
3051
|
+
sandbox: false,
|
|
3052
|
+
httpStatus: resp.status,
|
|
3053
|
+
...data
|
|
2966
3054
|
}, null, 2)
|
|
2967
|
-
}]
|
|
3055
|
+
}],
|
|
3056
|
+
isError: true
|
|
2968
3057
|
};
|
|
2969
3058
|
}
|
|
2970
3059
|
return {
|
|
2971
3060
|
content: [{
|
|
2972
3061
|
type: "text",
|
|
2973
|
-
text:
|
|
2974
|
-
|
|
2975
|
-
|
|
3062
|
+
text: JSON.stringify({
|
|
3063
|
+
sandbox: false,
|
|
3064
|
+
success: true,
|
|
3065
|
+
messageId: data.messageId,
|
|
3066
|
+
txHash: data.txHash,
|
|
3067
|
+
feeWhole: data.feeWhole,
|
|
3068
|
+
feeToken: data.feeToken,
|
|
3069
|
+
ccipExplorer: data.ccipExplorer,
|
|
3070
|
+
srcExplorer: data.srcExplorer,
|
|
3071
|
+
...data.agentFundTxHash ? { agentFundTxHash: data.agentFundTxHash, agentFundEth: data.agentFundEth } : {},
|
|
3072
|
+
note: "Bridge submitted on source chain. CCIP delivery to destination chain typically takes 8-25 minutes. Track via the ccipExplorer URL above."
|
|
3073
|
+
}, null, 2)
|
|
3074
|
+
}]
|
|
2976
3075
|
};
|
|
2977
3076
|
}
|
|
2978
3077
|
|
|
@@ -3801,8 +3900,11 @@ async function main() {
|
|
|
3801
3900
|
RECURRING_CANCEL_TOOL,
|
|
3802
3901
|
CLEAR_DELEGATION_TOOL,
|
|
3803
3902
|
// CCIP bridge surface — USDC routing on the eth/avax/arbitrum
|
|
3804
|
-
// triangle. Bridge_send
|
|
3805
|
-
// through the
|
|
3903
|
+
// triangle. Bridge_send goes LIVE on Mode C since 0.8.10 (Mode A/B
|
|
3904
|
+
// still fall through to sandbox since the route's API-key auth
|
|
3905
|
+
// path only exists for the server-managed Agent Wallet). History
|
|
3906
|
+
// + Gas Tank tools remain dashboard-pointer until session-binding
|
|
3907
|
+
// exposes owner-sig auth from MCP.
|
|
3806
3908
|
BRIDGE_QUOTE_TOOL,
|
|
3807
3909
|
BRIDGE_SEND_TOOL,
|
|
3808
3910
|
BRIDGE_HISTORY_TOOL,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.11",
|
|
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": [
|