@yawlabs/lemonsqueezy-mcp 0.7.0 → 0.7.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/dist/index.js +139 -35
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30179,15 +30179,29 @@ function checkDestructiveRateLimit(now = Date.now()) {
|
|
|
30179
30179
|
function isStoreAllowlistActive() {
|
|
30180
30180
|
return loadOptions().allowedStoreIds !== null;
|
|
30181
30181
|
}
|
|
30182
|
-
function
|
|
30183
|
-
if (
|
|
30184
|
-
|
|
30185
|
-
if (
|
|
30186
|
-
|
|
30187
|
-
|
|
30188
|
-
|
|
30189
|
-
|
|
30190
|
-
|
|
30182
|
+
function isPresent(value) {
|
|
30183
|
+
if (value === void 0 || value === null) return false;
|
|
30184
|
+
if (typeof value === "string" && value === "") return false;
|
|
30185
|
+
if (Array.isArray(value) && value.length === 0) return false;
|
|
30186
|
+
return true;
|
|
30187
|
+
}
|
|
30188
|
+
function checkStoreScopedToolInput(tool, input) {
|
|
30189
|
+
const toolAcceptsStoreId = "storeId" in tool.inputSchema.shape;
|
|
30190
|
+
if (toolAcceptsStoreId) {
|
|
30191
|
+
const raw = input.storeId;
|
|
30192
|
+
if (raw !== void 0 && raw !== null && raw !== "") {
|
|
30193
|
+
checkStoreAllowed(String(raw));
|
|
30194
|
+
} else if (isStoreAllowlistActive()) {
|
|
30195
|
+
throw new GuardrailError("storeId is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set");
|
|
30196
|
+
}
|
|
30197
|
+
}
|
|
30198
|
+
if (tool.requiredFilters && tool.requiredFilters.length > 0 && isStoreAllowlistActive()) {
|
|
30199
|
+
const anyPresent = tool.requiredFilters.some((key) => isPresent(input[key]));
|
|
30200
|
+
if (!anyPresent) {
|
|
30201
|
+
throw new GuardrailError(
|
|
30202
|
+
`At least one of [${tool.requiredFilters.join(", ")}] is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set`
|
|
30203
|
+
);
|
|
30204
|
+
}
|
|
30191
30205
|
}
|
|
30192
30206
|
}
|
|
30193
30207
|
function isDestructiveCall(tool, input) {
|
|
@@ -30252,10 +30266,46 @@ function logEvent(entry) {
|
|
|
30252
30266
|
}
|
|
30253
30267
|
}
|
|
30254
30268
|
|
|
30269
|
+
// src/redact.ts
|
|
30270
|
+
var SECRET_KEY_RE = /^(secret|password|token|api[_-]?key|bearer|authorization|signing[_-]?secret)$/i;
|
|
30271
|
+
var REDACTED = "[REDACTED]";
|
|
30272
|
+
var CIRCULAR = "[CIRCULAR]";
|
|
30273
|
+
var MAX_DEPTH = 32;
|
|
30274
|
+
function isPlainObject3(value) {
|
|
30275
|
+
if (value === null || typeof value !== "object") return false;
|
|
30276
|
+
const proto = Object.getPrototypeOf(value);
|
|
30277
|
+
return proto === Object.prototype || proto === null;
|
|
30278
|
+
}
|
|
30279
|
+
function redactInner(value, visited, depth) {
|
|
30280
|
+
if (depth > MAX_DEPTH) return CIRCULAR;
|
|
30281
|
+
if (value === null || typeof value !== "object") return value;
|
|
30282
|
+
if (Array.isArray(value)) {
|
|
30283
|
+
if (visited.has(value)) return CIRCULAR;
|
|
30284
|
+
visited.add(value);
|
|
30285
|
+
return value.map((item) => redactInner(item, visited, depth + 1));
|
|
30286
|
+
}
|
|
30287
|
+
if (!isPlainObject3(value)) return value;
|
|
30288
|
+
if (visited.has(value)) return CIRCULAR;
|
|
30289
|
+
visited.add(value);
|
|
30290
|
+
const out = {};
|
|
30291
|
+
for (const [key, val] of Object.entries(value)) {
|
|
30292
|
+
if (SECRET_KEY_RE.test(key)) {
|
|
30293
|
+
out[key] = REDACTED;
|
|
30294
|
+
} else {
|
|
30295
|
+
out[key] = redactInner(val, visited, depth + 1);
|
|
30296
|
+
}
|
|
30297
|
+
}
|
|
30298
|
+
return out;
|
|
30299
|
+
}
|
|
30300
|
+
function redactSecrets(input) {
|
|
30301
|
+
return redactInner(input, /* @__PURE__ */ new WeakSet(), 0);
|
|
30302
|
+
}
|
|
30303
|
+
|
|
30255
30304
|
// src/retry.ts
|
|
30256
30305
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
30257
30306
|
var DEFAULT_RETRY_WAIT_MS = 1e3;
|
|
30258
30307
|
var MAX_RETRY_WAIT_MS = 3e4;
|
|
30308
|
+
var OVERALL_DEADLINE_MS = 9e4;
|
|
30259
30309
|
var DEFAULT_MAX_ATTEMPTS = 4;
|
|
30260
30310
|
var BASE_BACKOFF_MS = 250;
|
|
30261
30311
|
var JITTER_FRACTION = 0.25;
|
|
@@ -30275,6 +30325,19 @@ function isAbortTimeoutError(err) {
|
|
|
30275
30325
|
const e = err;
|
|
30276
30326
|
return e.name === "TimeoutError" || e.name === "AbortError" || e.code === "ABORT_ERR";
|
|
30277
30327
|
}
|
|
30328
|
+
function isRetryTimeoutError(err) {
|
|
30329
|
+
if (!err || typeof err !== "object") return false;
|
|
30330
|
+
const e = err;
|
|
30331
|
+
return e.name === "TimeoutError" && typeof e.elapsedMs === "number" && typeof e.attempts === "number";
|
|
30332
|
+
}
|
|
30333
|
+
function makeRetryTimeoutError(elapsedMs, attempts, cause) {
|
|
30334
|
+
const err = new Error("Request timed out");
|
|
30335
|
+
err.name = "TimeoutError";
|
|
30336
|
+
err.elapsedMs = elapsedMs;
|
|
30337
|
+
err.attempts = attempts;
|
|
30338
|
+
if (cause !== void 0) err.cause = cause;
|
|
30339
|
+
return err;
|
|
30340
|
+
}
|
|
30278
30341
|
function backoffDelay(attempt, rand = Math.random) {
|
|
30279
30342
|
const base = BASE_BACKOFF_MS * 2 ** (attempt - 1);
|
|
30280
30343
|
const jitter = rand() * base * JITTER_FRACTION;
|
|
@@ -30286,31 +30349,54 @@ async function fetchWithRetry(url2, init, opts) {
|
|
|
30286
30349
|
const sleep = opts.sleep ?? defaultSleep;
|
|
30287
30350
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
30288
30351
|
const rand = opts.rand ?? Math.random;
|
|
30352
|
+
const deadlineMs = opts.deadlineMs ?? OVERALL_DEADLINE_MS;
|
|
30353
|
+
const now = opts.now ?? Date.now;
|
|
30354
|
+
const startedAt = now();
|
|
30355
|
+
const deadlineAt = startedAt + deadlineMs;
|
|
30356
|
+
let attempts = 0;
|
|
30289
30357
|
let lastError;
|
|
30358
|
+
let lastResponse;
|
|
30290
30359
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
30360
|
+
if (attempt > 1 && now() >= deadlineAt) {
|
|
30361
|
+
if (lastResponse) return lastResponse;
|
|
30362
|
+
throw makeRetryTimeoutError(now() - startedAt, attempts, lastError);
|
|
30363
|
+
}
|
|
30364
|
+
attempts = attempt;
|
|
30291
30365
|
try {
|
|
30292
30366
|
const res = await fetchImpl(url2, { ...init, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
30367
|
+
lastResponse = res;
|
|
30293
30368
|
if (res.status === 429) {
|
|
30294
30369
|
if (attempt === maxAttempts) return res;
|
|
30295
30370
|
const waitMs = parseRetryAfterMs(res.headers.get("retry-after"));
|
|
30296
30371
|
if (waitMs > MAX_RETRY_WAIT_MS) return res;
|
|
30372
|
+
if (now() + waitMs >= deadlineAt) return res;
|
|
30297
30373
|
await sleep(waitMs);
|
|
30298
30374
|
continue;
|
|
30299
30375
|
}
|
|
30300
30376
|
if (res.status >= 500 && res.status < 600 && opts.idempotent && attempt < maxAttempts) {
|
|
30301
|
-
|
|
30377
|
+
const waitMs = backoffDelay(attempt, rand);
|
|
30378
|
+
if (now() + waitMs >= deadlineAt) return res;
|
|
30379
|
+
await sleep(waitMs);
|
|
30302
30380
|
continue;
|
|
30303
30381
|
}
|
|
30304
30382
|
return res;
|
|
30305
30383
|
} catch (err) {
|
|
30306
30384
|
lastError = err;
|
|
30307
30385
|
if (isAbortTimeoutError(err)) {
|
|
30308
|
-
if (!opts.idempotent || attempt === maxAttempts)
|
|
30309
|
-
|
|
30386
|
+
if (!opts.idempotent || attempt === maxAttempts) {
|
|
30387
|
+
throw makeRetryTimeoutError(now() - startedAt, attempts, err);
|
|
30388
|
+
}
|
|
30389
|
+
const waitMs = backoffDelay(attempt, rand);
|
|
30390
|
+
if (now() + waitMs >= deadlineAt) {
|
|
30391
|
+
throw makeRetryTimeoutError(now() - startedAt, attempts, err);
|
|
30392
|
+
}
|
|
30393
|
+
await sleep(waitMs);
|
|
30310
30394
|
continue;
|
|
30311
30395
|
}
|
|
30312
30396
|
if (err instanceof TypeError && opts.idempotent && attempt < maxAttempts) {
|
|
30313
|
-
|
|
30397
|
+
const waitMs = backoffDelay(attempt, rand);
|
|
30398
|
+
if (now() + waitMs >= deadlineAt) throw err;
|
|
30399
|
+
await sleep(waitMs);
|
|
30314
30400
|
continue;
|
|
30315
30401
|
}
|
|
30316
30402
|
throw err;
|
|
@@ -30433,6 +30519,14 @@ function buildQuery(params) {
|
|
|
30433
30519
|
function decorateError(error48, requestId) {
|
|
30434
30520
|
return requestId ? `${error48} (request_id: ${requestId})` : error48;
|
|
30435
30521
|
}
|
|
30522
|
+
function formatTimeoutMessage(err, fallbackElapsedMs) {
|
|
30523
|
+
if (isRetryTimeoutError(err)) {
|
|
30524
|
+
const seconds2 = Math.max(1, Math.round(err.elapsedMs / 1e3));
|
|
30525
|
+
return `Request timed out after ${seconds2}s (${err.attempts} attempts)`;
|
|
30526
|
+
}
|
|
30527
|
+
const seconds = Math.max(1, Math.round(fallbackElapsedMs / 1e3));
|
|
30528
|
+
return `Request timed out after ${seconds}s (1 attempts)`;
|
|
30529
|
+
}
|
|
30436
30530
|
async function apiRequest(method, path, body) {
|
|
30437
30531
|
const start = Date.now();
|
|
30438
30532
|
const apiKey = await loadApiKey();
|
|
@@ -30453,7 +30547,7 @@ async function apiRequest(method, path, body) {
|
|
|
30453
30547
|
} catch (err) {
|
|
30454
30548
|
const latency_ms2 = Date.now() - start;
|
|
30455
30549
|
if (isAbortTimeoutError(err)) {
|
|
30456
|
-
const error48 =
|
|
30550
|
+
const error48 = formatTimeoutMessage(err, latency_ms2);
|
|
30457
30551
|
logEvent({ event: "http_call", method, path, status: "timeout", latency_ms: latency_ms2, error: error48 });
|
|
30458
30552
|
return { ok: false, status: 0, error: error48 };
|
|
30459
30553
|
}
|
|
@@ -30540,7 +30634,7 @@ async function licenseRequest(path, body) {
|
|
|
30540
30634
|
} catch (err) {
|
|
30541
30635
|
const latency_ms2 = Date.now() - start;
|
|
30542
30636
|
if (isAbortTimeoutError(err)) {
|
|
30543
|
-
const error48 =
|
|
30637
|
+
const error48 = formatTimeoutMessage(err, latency_ms2);
|
|
30544
30638
|
logEvent({ event: "http_call", method: "POST", path, status: "timeout", latency_ms: latency_ms2, error: error48 });
|
|
30545
30639
|
return { ok: false, status: 0, error: error48 };
|
|
30546
30640
|
}
|
|
@@ -30663,7 +30757,7 @@ var affiliateTools = [
|
|
|
30663
30757
|
},
|
|
30664
30758
|
{
|
|
30665
30759
|
name: "ls_list_affiliates",
|
|
30666
|
-
description: "List all affiliates for the authenticated user's stores, optionally filtered by user email. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
30760
|
+
description: "List all affiliates for the authenticated user's stores, optionally filtered by user email. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool can still return affiliates tied to non-allowed stores -- the endpoint has no parent ID filter to scope by. Pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
30667
30761
|
annotations: {
|
|
30668
30762
|
title: "List affiliates",
|
|
30669
30763
|
readOnlyHint: true,
|
|
@@ -30733,7 +30827,7 @@ var checkoutTools = [
|
|
|
30733
30827
|
variantId: lsIdSchema.describe("The variant ID for the product being purchased"),
|
|
30734
30828
|
customPrice: external_exports3.number().int().min(0).optional().describe("Custom price in cents (overrides the variant price)"),
|
|
30735
30829
|
enabledVariants: external_exports3.array(lsIdSchema).optional().describe("Array of variant IDs to show on the checkout (for products with multiple variants)"),
|
|
30736
|
-
email: external_exports3.string().max(
|
|
30830
|
+
email: external_exports3.string().email().max(320).optional().describe("Prefill customer email"),
|
|
30737
30831
|
name: external_exports3.string().max(1e4).optional().describe("Prefill customer name"),
|
|
30738
30832
|
billingAddressCountry: external_exports3.string().max(1e4).optional().describe("Prefill billing country (ISO 3166-1 alpha-2)"),
|
|
30739
30833
|
billingAddressZip: external_exports3.string().max(1e4).optional().describe("Prefill billing ZIP/postal code"),
|
|
@@ -30940,7 +31034,7 @@ var discountRedemptionTools = [
|
|
|
30940
31034
|
},
|
|
30941
31035
|
{
|
|
30942
31036
|
name: "ls_list_discount_redemptions",
|
|
30943
|
-
description: "List all discount redemptions, optionally filtered by discount or order. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31037
|
+
description: "List all discount redemptions, optionally filtered by discount or order. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: discountId, orderId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
30944
31038
|
annotations: {
|
|
30945
31039
|
title: "List discount redemptions",
|
|
30946
31040
|
readOnlyHint: true,
|
|
@@ -30955,6 +31049,7 @@ var discountRedemptionTools = [
|
|
|
30955
31049
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
30956
31050
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
30957
31051
|
}),
|
|
31052
|
+
requiredFilters: ["discountId", "orderId"],
|
|
30958
31053
|
handler: listHandler("/discount-redemptions", { discountId: "discount_id", orderId: "order_id" })
|
|
30959
31054
|
}
|
|
30960
31055
|
];
|
|
@@ -31092,7 +31187,7 @@ var fileTools = [
|
|
|
31092
31187
|
},
|
|
31093
31188
|
{
|
|
31094
31189
|
name: "ls_list_files",
|
|
31095
|
-
description: "List all files, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31190
|
+
description: "List all files, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: variantId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31096
31191
|
annotations: {
|
|
31097
31192
|
title: "List files",
|
|
31098
31193
|
readOnlyHint: true,
|
|
@@ -31106,6 +31201,7 @@ var fileTools = [
|
|
|
31106
31201
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31107
31202
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31108
31203
|
}),
|
|
31204
|
+
requiredFilters: ["variantId"],
|
|
31109
31205
|
handler: listHandler("/files", { variantId: "variant_id" })
|
|
31110
31206
|
}
|
|
31111
31207
|
];
|
|
@@ -31130,7 +31226,7 @@ var licenseKeyInstanceTools = [
|
|
|
31130
31226
|
},
|
|
31131
31227
|
{
|
|
31132
31228
|
name: "ls_list_license_key_instances",
|
|
31133
|
-
description: "List all license key instances (activations), optionally filtered by license key. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31229
|
+
description: "List all license key instances (activations), optionally filtered by license key. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: licenseKeyId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31134
31230
|
annotations: {
|
|
31135
31231
|
title: "List license key instances",
|
|
31136
31232
|
readOnlyHint: true,
|
|
@@ -31144,6 +31240,7 @@ var licenseKeyInstanceTools = [
|
|
|
31144
31240
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31145
31241
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31146
31242
|
}),
|
|
31243
|
+
requiredFilters: ["licenseKeyId"],
|
|
31147
31244
|
handler: listHandler("/license-key-instances", { licenseKeyId: "license_key_id" })
|
|
31148
31245
|
}
|
|
31149
31246
|
];
|
|
@@ -31206,11 +31303,14 @@ var licenseKeyTools = [
|
|
|
31206
31303
|
idempotentHint: true,
|
|
31207
31304
|
openWorldHint: true
|
|
31208
31305
|
},
|
|
31209
|
-
// Disabling a license key revokes a customer's access.
|
|
31210
|
-
//
|
|
31211
|
-
//
|
|
31212
|
-
//
|
|
31213
|
-
|
|
31306
|
+
// Disabling a license key revokes a customer's access outright. Changing
|
|
31307
|
+
// the activation limit can also revoke access -- setting it to 0, or to
|
|
31308
|
+
// any value below the customer's current activation count, kicks
|
|
31309
|
+
// already-activated instances offline. We can't tell from the input alone
|
|
31310
|
+
// whether a given limit change shrinks or grows, so treat ANY
|
|
31311
|
+
// `activationLimit` change as destructive alongside `disabled: true`.
|
|
31312
|
+
// Benign edits (expiry) stay on the regular path.
|
|
31313
|
+
isDestructive: (input) => input.disabled === true || input.activationLimit !== void 0,
|
|
31214
31314
|
inputSchema: external_exports3.object({
|
|
31215
31315
|
licenseKeyId: lsIdSchema.describe("The license key ID to update"),
|
|
31216
31316
|
activationLimit: external_exports3.number().int().min(0).optional().describe("Maximum number of activations allowed (0 = unlimited)"),
|
|
@@ -31319,7 +31419,7 @@ var orderItemTools = [
|
|
|
31319
31419
|
},
|
|
31320
31420
|
{
|
|
31321
31421
|
name: "ls_list_order_items",
|
|
31322
|
-
description: "List all order items, optionally filtered by order or product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31422
|
+
description: "List all order items, optionally filtered by order or product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: orderId, productId, variantId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31323
31423
|
annotations: {
|
|
31324
31424
|
title: "List order items",
|
|
31325
31425
|
readOnlyHint: true,
|
|
@@ -31335,6 +31435,7 @@ var orderItemTools = [
|
|
|
31335
31435
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31336
31436
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31337
31437
|
}),
|
|
31438
|
+
requiredFilters: ["orderId", "productId", "variantId"],
|
|
31338
31439
|
handler: listHandler("/order-items", { orderId: "order_id", productId: "product_id", variantId: "variant_id" })
|
|
31339
31440
|
}
|
|
31340
31441
|
];
|
|
@@ -31458,7 +31559,7 @@ var priceTools = [
|
|
|
31458
31559
|
},
|
|
31459
31560
|
{
|
|
31460
31561
|
name: "ls_list_prices",
|
|
31461
|
-
description: "List all prices, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31562
|
+
description: "List all prices, optionally filtered by variant. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: variantId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31462
31563
|
annotations: {
|
|
31463
31564
|
title: "List prices",
|
|
31464
31565
|
readOnlyHint: true,
|
|
@@ -31472,6 +31573,7 @@ var priceTools = [
|
|
|
31472
31573
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31473
31574
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31474
31575
|
}),
|
|
31576
|
+
requiredFilters: ["variantId"],
|
|
31475
31577
|
handler: listHandler("/prices", { variantId: "variant_id" })
|
|
31476
31578
|
}
|
|
31477
31579
|
];
|
|
@@ -31683,7 +31785,7 @@ var subscriptionItemTools = [
|
|
|
31683
31785
|
},
|
|
31684
31786
|
{
|
|
31685
31787
|
name: "ls_list_subscription_items",
|
|
31686
|
-
description: "List all subscription items, optionally filtered by subscription or price. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31788
|
+
description: "List all subscription items, optionally filtered by subscription or price. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: subscriptionId, priceId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31687
31789
|
annotations: {
|
|
31688
31790
|
title: "List subscription items",
|
|
31689
31791
|
readOnlyHint: true,
|
|
@@ -31698,6 +31800,7 @@ var subscriptionItemTools = [
|
|
|
31698
31800
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31699
31801
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31700
31802
|
}),
|
|
31803
|
+
requiredFilters: ["subscriptionId", "priceId"],
|
|
31701
31804
|
handler: listHandler("/subscription-items", { subscriptionId: "subscription_id", priceId: "price_id" })
|
|
31702
31805
|
},
|
|
31703
31806
|
{
|
|
@@ -31887,7 +31990,7 @@ var usageRecordTools = [
|
|
|
31887
31990
|
},
|
|
31888
31991
|
{
|
|
31889
31992
|
name: "ls_list_usage_records",
|
|
31890
|
-
description: "List all usage records, optionally filtered by subscription item. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
31993
|
+
description: "List all usage records, optionally filtered by subscription item. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: subscriptionItemId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31891
31994
|
annotations: {
|
|
31892
31995
|
title: "List usage records",
|
|
31893
31996
|
readOnlyHint: true,
|
|
@@ -31901,6 +32004,7 @@ var usageRecordTools = [
|
|
|
31901
32004
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31902
32005
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31903
32006
|
}),
|
|
32007
|
+
requiredFilters: ["subscriptionItemId"],
|
|
31904
32008
|
handler: listHandler("/usage-records", { subscriptionItemId: "subscription_item_id" })
|
|
31905
32009
|
},
|
|
31906
32010
|
{
|
|
@@ -31980,7 +32084,7 @@ var variantTools = [
|
|
|
31980
32084
|
},
|
|
31981
32085
|
{
|
|
31982
32086
|
name: "ls_list_variants",
|
|
31983
|
-
description: "List all variants, optionally filtered by product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total.",
|
|
32087
|
+
description: "List all variants, optionally filtered by product. Results are paginated \u2014 check meta.page in the response for currentPage, lastPage, and total. Cross-store note: when LEMONSQUEEZY_ALLOWED_STORE_IDS is set, this tool requires at least one of: productId. Even with that set, pair with a scoped LemonSqueezy API key for true cross-store enforcement -- the API key's visibility is the true boundary.",
|
|
31984
32088
|
annotations: {
|
|
31985
32089
|
title: "List variants",
|
|
31986
32090
|
readOnlyHint: true,
|
|
@@ -31994,6 +32098,7 @@ var variantTools = [
|
|
|
31994
32098
|
pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
|
|
31995
32099
|
pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
|
|
31996
32100
|
}),
|
|
32101
|
+
requiredFilters: ["productId"],
|
|
31997
32102
|
handler: listHandler("/variants", { productId: "product_id" })
|
|
31998
32103
|
}
|
|
31999
32104
|
];
|
|
@@ -32118,7 +32223,7 @@ var webhookTools = [
|
|
|
32118
32223
|
];
|
|
32119
32224
|
|
|
32120
32225
|
// src/index.ts
|
|
32121
|
-
var version2 = true ? "0.7.
|
|
32226
|
+
var version2 = true ? "0.7.1" : (await null).createRequire(import.meta.url)("../package.json").version;
|
|
32122
32227
|
var subcommand = process.argv[2];
|
|
32123
32228
|
if (subcommand === "version" || subcommand === "--version") {
|
|
32124
32229
|
console.log(version2);
|
|
@@ -32152,7 +32257,6 @@ var server = new McpServer({
|
|
|
32152
32257
|
version: version2
|
|
32153
32258
|
});
|
|
32154
32259
|
for (const tool of allTools) {
|
|
32155
|
-
const toolAcceptsStoreId = "storeId" in tool.inputSchema.shape;
|
|
32156
32260
|
server.tool(
|
|
32157
32261
|
tool.name,
|
|
32158
32262
|
tool.description,
|
|
@@ -32163,7 +32267,7 @@ for (const tool of allTools) {
|
|
|
32163
32267
|
const start = Date.now();
|
|
32164
32268
|
try {
|
|
32165
32269
|
if (isDestructive) checkDestructiveRateLimit();
|
|
32166
|
-
checkStoreScopedToolInput(
|
|
32270
|
+
checkStoreScopedToolInput(tool, input);
|
|
32167
32271
|
const result = await tool.handler(input);
|
|
32168
32272
|
const response = result;
|
|
32169
32273
|
const latency_ms = Date.now() - start;
|
|
@@ -32175,7 +32279,7 @@ for (const tool of allTools) {
|
|
|
32175
32279
|
request_id: response.requestId,
|
|
32176
32280
|
error: response.ok ? void 0 : response.error,
|
|
32177
32281
|
audit: isDestructive ? true : void 0,
|
|
32178
|
-
inputs: isDestructive ? input : void 0
|
|
32282
|
+
inputs: isDestructive ? redactSecrets(input) : void 0
|
|
32179
32283
|
});
|
|
32180
32284
|
if (!response.ok) {
|
|
32181
32285
|
return {
|
|
@@ -32202,7 +32306,7 @@ for (const tool of allTools) {
|
|
|
32202
32306
|
latency_ms,
|
|
32203
32307
|
error: message,
|
|
32204
32308
|
audit: isDestructive ? true : void 0,
|
|
32205
|
-
inputs: isDestructive ? input : void 0
|
|
32309
|
+
inputs: isDestructive ? redactSecrets(input) : void 0
|
|
32206
32310
|
});
|
|
32207
32311
|
return {
|
|
32208
32312
|
content: [{ type: "text", text: `Error: ${message}` }],
|