@quackai/q402-mcp 0.6.6 → 0.7.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/dist/index.js +265 -1
- package/package.json +1 -1
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.
|
|
214
|
+
var PACKAGE_VERSION = "0.7.0";
|
|
215
215
|
|
|
216
216
|
// src/tools/quote.ts
|
|
217
217
|
import { z } from "zod";
|
|
@@ -2971,6 +2971,255 @@ async function runRecurringFires(input) {
|
|
|
2971
2971
|
}
|
|
2972
2972
|
}
|
|
2973
2973
|
|
|
2974
|
+
// src/tools/recurring-pause.ts
|
|
2975
|
+
import { z as z14 } from "zod";
|
|
2976
|
+
var RecurringPauseInputSchema = z14.object({
|
|
2977
|
+
ruleId: z14.string().min(1).describe(
|
|
2978
|
+
"Rule id to pause. Obtain from q402_recurring_list \u2014 each entry's `ruleId` field. Pausing is immediate and reversible."
|
|
2979
|
+
),
|
|
2980
|
+
walletId: z14.string().optional().describe(
|
|
2981
|
+
"Optional lowercased Agent Wallet address when the user holds multiple wallets. Defaults to Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet."
|
|
2982
|
+
)
|
|
2983
|
+
});
|
|
2984
|
+
var RECURRING_PAUSE_TOOL = {
|
|
2985
|
+
name: "q402_recurring_pause",
|
|
2986
|
+
description: `Pause an active recurring-payment rule. Takes a ruleId (from q402_recurring_list). The rule transitions to status "paused" \u2014 the cron skips it on every tick until you resume. Fully reversible via q402_recurring_resume. Use this when the user says 'pause my Friday payout' or 'hold on, stop my recurring rule for now' \u2014 gentler than cancel, no re-authoring required. Authenticated by the paid Multichain API key (same gate as create/cancel). Read q402_recurring_list first to find the matching ruleId.`,
|
|
2987
|
+
inputSchema: {
|
|
2988
|
+
type: "object",
|
|
2989
|
+
properties: {
|
|
2990
|
+
ruleId: {
|
|
2991
|
+
type: "string",
|
|
2992
|
+
description: "Rule id from q402_recurring_list. Required."
|
|
2993
|
+
},
|
|
2994
|
+
walletId: {
|
|
2995
|
+
type: "string",
|
|
2996
|
+
description: "Optional. Lowercased Agent Wallet address when the user holds multiple wallets. Defaults to Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet on the server."
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
required: ["ruleId"],
|
|
3000
|
+
additionalProperties: false
|
|
3001
|
+
}
|
|
3002
|
+
};
|
|
3003
|
+
async function runRecurringPause(input) {
|
|
3004
|
+
const base = CONFIG.relayBaseUrl;
|
|
3005
|
+
const dashboardUrl = base.replace(/\/api$/, "") + "/dashboard?tab=agent";
|
|
3006
|
+
if (!CONFIG.apiKey || !CONFIG.apiKey.startsWith("q402_live_")) {
|
|
3007
|
+
return {
|
|
3008
|
+
ok: false,
|
|
3009
|
+
walletId: null,
|
|
3010
|
+
rule: null,
|
|
3011
|
+
error: "API_KEY_REQUIRED",
|
|
3012
|
+
message: "No live Q402 API key configured. Run q402_doctor to set one up.",
|
|
3013
|
+
dashboardUrl
|
|
3014
|
+
};
|
|
3015
|
+
}
|
|
3016
|
+
const explicitWalletId = typeof input.walletId === "string" && input.walletId.length > 0 ? input.walletId.toLowerCase() : CONFIG.walletId;
|
|
3017
|
+
try {
|
|
3018
|
+
const res = await fetch(`${base}/wallet/agentic/recurring-by-key`, {
|
|
3019
|
+
method: "POST",
|
|
3020
|
+
headers: { "Content-Type": "application/json" },
|
|
3021
|
+
body: JSON.stringify({
|
|
3022
|
+
apiKey: CONFIG.apiKey,
|
|
3023
|
+
action: "pause",
|
|
3024
|
+
ruleId: input.ruleId,
|
|
3025
|
+
...explicitWalletId ? { walletId: explicitWalletId } : {}
|
|
3026
|
+
})
|
|
3027
|
+
});
|
|
3028
|
+
const data = await res.json().catch(() => ({}));
|
|
3029
|
+
if (!res.ok) {
|
|
3030
|
+
return {
|
|
3031
|
+
ok: false,
|
|
3032
|
+
walletId: explicitWalletId,
|
|
3033
|
+
rule: null,
|
|
3034
|
+
error: data.error ?? `HTTP_${res.status}`,
|
|
3035
|
+
message: data.message ?? `Pause failed with HTTP ${res.status}.`,
|
|
3036
|
+
dashboardUrl
|
|
3037
|
+
};
|
|
3038
|
+
}
|
|
3039
|
+
return {
|
|
3040
|
+
ok: true,
|
|
3041
|
+
walletId: data.walletId ?? explicitWalletId,
|
|
3042
|
+
rule: data.rule ?? null,
|
|
3043
|
+
dashboardUrl
|
|
3044
|
+
};
|
|
3045
|
+
} catch (e) {
|
|
3046
|
+
return {
|
|
3047
|
+
ok: false,
|
|
3048
|
+
walletId: explicitWalletId,
|
|
3049
|
+
rule: null,
|
|
3050
|
+
error: "NETWORK_ERROR",
|
|
3051
|
+
message: e instanceof Error ? e.message : String(e),
|
|
3052
|
+
dashboardUrl
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
// src/tools/recurring-resume.ts
|
|
3058
|
+
import { z as z15 } from "zod";
|
|
3059
|
+
var RecurringResumeInputSchema = z15.object({
|
|
3060
|
+
ruleId: z15.string().min(1).describe(
|
|
3061
|
+
"Rule id to resume. Obtain from q402_recurring_list \u2014 each entry's `ruleId` field. Resume is immediate; nextRunAt advances to the next valid slot."
|
|
3062
|
+
),
|
|
3063
|
+
walletId: z15.string().optional().describe(
|
|
3064
|
+
"Optional lowercased Agent Wallet address when the user holds multiple wallets. Defaults to Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet."
|
|
3065
|
+
)
|
|
3066
|
+
});
|
|
3067
|
+
var RECURRING_RESUME_TOOL = {
|
|
3068
|
+
name: "q402_recurring_resume",
|
|
3069
|
+
description: "Resume a paused or stopped recurring-payment rule. Takes a ruleId (from q402_recurring_list). Supported transitions: paused \u2192 active, paused-by-archive \u2192 active (after restoring the wallet), and fired-cap-exceeded \u2192 active (after raising the per-tx cap or re-subscribing). nextRunAt is advanced to the next valid slot so the rule doesn't immediately fire on a stale schedule. Cancelled rules cannot be resumed \u2014 re-author via q402_recurring_create. Authenticated by the paid Multichain API key.",
|
|
3070
|
+
inputSchema: {
|
|
3071
|
+
type: "object",
|
|
3072
|
+
properties: {
|
|
3073
|
+
ruleId: {
|
|
3074
|
+
type: "string",
|
|
3075
|
+
description: "Rule id from q402_recurring_list. Required."
|
|
3076
|
+
},
|
|
3077
|
+
walletId: {
|
|
3078
|
+
type: "string",
|
|
3079
|
+
description: "Optional. Lowercased Agent Wallet address when the user holds multiple wallets. Defaults to Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet on the server."
|
|
3080
|
+
}
|
|
3081
|
+
},
|
|
3082
|
+
required: ["ruleId"],
|
|
3083
|
+
additionalProperties: false
|
|
3084
|
+
}
|
|
3085
|
+
};
|
|
3086
|
+
async function runRecurringResume(input) {
|
|
3087
|
+
const base = CONFIG.relayBaseUrl;
|
|
3088
|
+
const dashboardUrl = base.replace(/\/api$/, "") + "/dashboard?tab=agent";
|
|
3089
|
+
if (!CONFIG.apiKey || !CONFIG.apiKey.startsWith("q402_live_")) {
|
|
3090
|
+
return {
|
|
3091
|
+
ok: false,
|
|
3092
|
+
walletId: null,
|
|
3093
|
+
rule: null,
|
|
3094
|
+
error: "API_KEY_REQUIRED",
|
|
3095
|
+
message: "No live Q402 API key configured. Run q402_doctor to set one up.",
|
|
3096
|
+
dashboardUrl
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
const explicitWalletId = typeof input.walletId === "string" && input.walletId.length > 0 ? input.walletId.toLowerCase() : CONFIG.walletId;
|
|
3100
|
+
try {
|
|
3101
|
+
const res = await fetch(`${base}/wallet/agentic/recurring-by-key`, {
|
|
3102
|
+
method: "POST",
|
|
3103
|
+
headers: { "Content-Type": "application/json" },
|
|
3104
|
+
body: JSON.stringify({
|
|
3105
|
+
apiKey: CONFIG.apiKey,
|
|
3106
|
+
action: "resume",
|
|
3107
|
+
ruleId: input.ruleId,
|
|
3108
|
+
...explicitWalletId ? { walletId: explicitWalletId } : {}
|
|
3109
|
+
})
|
|
3110
|
+
});
|
|
3111
|
+
const data = await res.json().catch(() => ({}));
|
|
3112
|
+
if (!res.ok) {
|
|
3113
|
+
return {
|
|
3114
|
+
ok: false,
|
|
3115
|
+
walletId: explicitWalletId,
|
|
3116
|
+
rule: null,
|
|
3117
|
+
error: data.error ?? `HTTP_${res.status}`,
|
|
3118
|
+
message: data.message ?? `Resume failed with HTTP ${res.status}.`,
|
|
3119
|
+
dashboardUrl
|
|
3120
|
+
};
|
|
3121
|
+
}
|
|
3122
|
+
return {
|
|
3123
|
+
ok: true,
|
|
3124
|
+
walletId: data.walletId ?? explicitWalletId,
|
|
3125
|
+
rule: data.rule ?? null,
|
|
3126
|
+
dashboardUrl
|
|
3127
|
+
};
|
|
3128
|
+
} catch (e) {
|
|
3129
|
+
return {
|
|
3130
|
+
ok: false,
|
|
3131
|
+
walletId: explicitWalletId,
|
|
3132
|
+
rule: null,
|
|
3133
|
+
error: "NETWORK_ERROR",
|
|
3134
|
+
message: e instanceof Error ? e.message : String(e),
|
|
3135
|
+
dashboardUrl
|
|
3136
|
+
};
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
// src/tools/recurring-skip-next.ts
|
|
3141
|
+
import { z as z16 } from "zod";
|
|
3142
|
+
var RecurringSkipNextInputSchema = z16.object({
|
|
3143
|
+
ruleId: z16.string().min(1).describe(
|
|
3144
|
+
"Rule id whose next scheduled fire to skip. Obtain from q402_recurring_list \u2014 each entry's `ruleId` field."
|
|
3145
|
+
),
|
|
3146
|
+
walletId: z16.string().optional().describe(
|
|
3147
|
+
"Optional lowercased Agent Wallet address when the user holds multiple wallets. Defaults to Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet."
|
|
3148
|
+
)
|
|
3149
|
+
});
|
|
3150
|
+
var RECURRING_SKIP_NEXT_TOOL = {
|
|
3151
|
+
name: "q402_recurring_skip_next",
|
|
3152
|
+
description: "Skip ONLY the next scheduled fire of a recurring-payment rule. Cadence is preserved \u2014 the fire after the skipped one runs normally. Use this when the user says 'skip the next Friday payout, Alice is on holiday' or 'don't fire this month's subscription, charge it next month'. The rule must be in active status; paused / cancelled rules must be resumed first. Authenticated by the paid Multichain API key. Call q402_recurring_list first to confirm the ruleId and current schedule.",
|
|
3153
|
+
inputSchema: {
|
|
3154
|
+
type: "object",
|
|
3155
|
+
properties: {
|
|
3156
|
+
ruleId: {
|
|
3157
|
+
type: "string",
|
|
3158
|
+
description: "Rule id from q402_recurring_list. Required."
|
|
3159
|
+
},
|
|
3160
|
+
walletId: {
|
|
3161
|
+
type: "string",
|
|
3162
|
+
description: "Optional. Lowercased Agent Wallet address when the user holds multiple wallets. Defaults to Q402_AGENT_WALLET_ADDRESS env, then the owner's default wallet on the server."
|
|
3163
|
+
}
|
|
3164
|
+
},
|
|
3165
|
+
required: ["ruleId"],
|
|
3166
|
+
additionalProperties: false
|
|
3167
|
+
}
|
|
3168
|
+
};
|
|
3169
|
+
async function runRecurringSkipNext(input) {
|
|
3170
|
+
const base = CONFIG.relayBaseUrl;
|
|
3171
|
+
const dashboardUrl = base.replace(/\/api$/, "") + "/dashboard?tab=agent";
|
|
3172
|
+
if (!CONFIG.apiKey || !CONFIG.apiKey.startsWith("q402_live_")) {
|
|
3173
|
+
return {
|
|
3174
|
+
ok: false,
|
|
3175
|
+
walletId: null,
|
|
3176
|
+
rule: null,
|
|
3177
|
+
error: "API_KEY_REQUIRED",
|
|
3178
|
+
message: "No live Q402 API key configured. Run q402_doctor to set one up.",
|
|
3179
|
+
dashboardUrl
|
|
3180
|
+
};
|
|
3181
|
+
}
|
|
3182
|
+
const explicitWalletId = typeof input.walletId === "string" && input.walletId.length > 0 ? input.walletId.toLowerCase() : CONFIG.walletId;
|
|
3183
|
+
try {
|
|
3184
|
+
const res = await fetch(`${base}/wallet/agentic/recurring-by-key`, {
|
|
3185
|
+
method: "POST",
|
|
3186
|
+
headers: { "Content-Type": "application/json" },
|
|
3187
|
+
body: JSON.stringify({
|
|
3188
|
+
apiKey: CONFIG.apiKey,
|
|
3189
|
+
action: "skip-next",
|
|
3190
|
+
ruleId: input.ruleId,
|
|
3191
|
+
...explicitWalletId ? { walletId: explicitWalletId } : {}
|
|
3192
|
+
})
|
|
3193
|
+
});
|
|
3194
|
+
const data = await res.json().catch(() => ({}));
|
|
3195
|
+
if (!res.ok) {
|
|
3196
|
+
return {
|
|
3197
|
+
ok: false,
|
|
3198
|
+
walletId: explicitWalletId,
|
|
3199
|
+
rule: null,
|
|
3200
|
+
error: data.error ?? `HTTP_${res.status}`,
|
|
3201
|
+
message: data.message ?? `Skip-next failed with HTTP ${res.status}.`,
|
|
3202
|
+
dashboardUrl
|
|
3203
|
+
};
|
|
3204
|
+
}
|
|
3205
|
+
return {
|
|
3206
|
+
ok: true,
|
|
3207
|
+
walletId: data.walletId ?? explicitWalletId,
|
|
3208
|
+
rule: data.rule ?? null,
|
|
3209
|
+
dashboardUrl
|
|
3210
|
+
};
|
|
3211
|
+
} catch (e) {
|
|
3212
|
+
return {
|
|
3213
|
+
ok: false,
|
|
3214
|
+
walletId: explicitWalletId,
|
|
3215
|
+
rule: null,
|
|
3216
|
+
error: "NETWORK_ERROR",
|
|
3217
|
+
message: e instanceof Error ? e.message : String(e),
|
|
3218
|
+
dashboardUrl
|
|
3219
|
+
};
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
|
|
2974
3223
|
// src/index.ts
|
|
2975
3224
|
function jsonText(value) {
|
|
2976
3225
|
return { type: "text", text: JSON.stringify(value, null, 2) };
|
|
@@ -2995,6 +3244,9 @@ async function main() {
|
|
|
2995
3244
|
RECURRING_LIST_TOOL,
|
|
2996
3245
|
RECURRING_CREATE_TOOL,
|
|
2997
3246
|
RECURRING_FIRES_TOOL,
|
|
3247
|
+
RECURRING_PAUSE_TOOL,
|
|
3248
|
+
RECURRING_RESUME_TOOL,
|
|
3249
|
+
RECURRING_SKIP_NEXT_TOOL,
|
|
2998
3250
|
RECURRING_CANCEL_TOOL,
|
|
2999
3251
|
CLEAR_DELEGATION_TOOL
|
|
3000
3252
|
]
|
|
@@ -3055,6 +3307,18 @@ async function main() {
|
|
|
3055
3307
|
const parsed = RecurringFiresInputSchema.parse(args ?? {});
|
|
3056
3308
|
return { content: [jsonText(await runRecurringFires(parsed))] };
|
|
3057
3309
|
}
|
|
3310
|
+
case "q402_recurring_pause": {
|
|
3311
|
+
const parsed = RecurringPauseInputSchema.parse(args ?? {});
|
|
3312
|
+
return { content: [jsonText(await runRecurringPause(parsed))] };
|
|
3313
|
+
}
|
|
3314
|
+
case "q402_recurring_resume": {
|
|
3315
|
+
const parsed = RecurringResumeInputSchema.parse(args ?? {});
|
|
3316
|
+
return { content: [jsonText(await runRecurringResume(parsed))] };
|
|
3317
|
+
}
|
|
3318
|
+
case "q402_recurring_skip_next": {
|
|
3319
|
+
const parsed = RecurringSkipNextInputSchema.parse(args ?? {});
|
|
3320
|
+
return { content: [jsonText(await runRecurringSkipNext(parsed))] };
|
|
3321
|
+
}
|
|
3058
3322
|
default:
|
|
3059
3323
|
return {
|
|
3060
3324
|
isError: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quackai/q402-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
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": [
|