@yawlabs/lemonsqueezy-mcp 0.6.2 → 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.
Files changed (3) hide show
  1. package/README.md +7 -7
  2. package/dist/index.js +275 -122
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -173,11 +173,11 @@ All configuration is via environment variables. Only `LEMONSQUEEZY_API_KEY` (or
173
173
  | Variable | Purpose |
174
174
  | --- | --- |
175
175
  | `LEMONSQUEEZY_API_KEY` | LemonSqueezy API token. |
176
- | `LEMONSQUEEZY_API_KEY_COMMAND` | Command whose stdout produces the API key. Overrides `LEMONSQUEEZY_API_KEY`. Output is cached for 1 hour. Use this to pull short-lived credentials from a vault (`op read`, `gcloud secrets versions access`, etc.) without writing them to env vars. |
177
- | `LEMONSQUEEZY_ALLOWED_STORE_IDS` | Comma-separated allowlist of store IDs. When set: (1) any tool whose input includes a `storeId` rejects calls to a non-allowed store; (2) tools that *accept* a `storeId` filter (e.g. `ls_list_orders`, `ls_list_subscriptions`) require it — calls without one are blocked so a missing filter cannot return data from every store the API key can see. Tools with no `storeId` field at all (e.g. `ls_refund_order`, `ls_list_stores`) are not gated by this — pair with `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS` and `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT`. |
176
+ | `LEMONSQUEEZY_API_KEY_COMMAND` | Command whose stdout produces the API key. Overrides `LEMONSQUEEZY_API_KEY`. Output is cached for 1 hour. Use this to pull short-lived credentials from a vault (`op read`, `gcloud secrets versions access`, etc.) without writing them to env vars. The cache is keyed by the command string, so changing it mid-process refreshes on the next request; it is also invalidated automatically on a 401/403 from the API, so a key rotated upstream takes effect on the next call without waiting for the TTL. |
177
+ | `LEMONSQUEEZY_ALLOWED_STORE_IDS` | Comma-separated allowlist of store IDs. When set: (1) any tool whose input includes a `storeId` rejects calls to a non-allowed store; (2) tools that *accept* a `storeId` filter (e.g. `ls_list_orders`, `ls_list_subscriptions`) require it — calls without one are blocked so a missing filter cannot return data from every store the API key can see. Tools with no `storeId` field at all (e.g. `ls_refund_order`, `ls_cancel_subscription`, `ls_archive_customer`, `ls_delete_webhook`, `ls_delete_discount`, `ls_update_license_key`, `ls_list_stores`) route by their own resource ID and are **not** gated by this allowlist. For those, the only authoritative store boundary is the API key itself — pair this setting with a LemonSqueezy API key scoped to the same store(s), and pair with `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS` / `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` for additional defense in depth. |
178
178
  | `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS` | Rejects `ls_refund_order` and `ls_refund_subscription_invoice` calls above this amount. |
179
- | `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` | Max destructive tool calls per 60-second rolling window. In-process limit — per MCP server instance, not global; each `npx` cold start resets the window. Counts include `ls_update_license_key` calls that set `disabled: true`. |
180
- | `LEMONSQUEEZY_LOG=json` | Emit one JSON log line to stderr per tool and HTTP call. Destructive calls are tagged `audit: true` and include their inputs. |
179
+ | `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` | Max destructive tool calls per 60-second rolling window. In-process limit — per MCP server instance, not global; each `npx` cold start resets the window. Counts include `ls_update_license_key` calls that set `disabled: true`, and `ls_update_subscription` calls that pause or switch plan. |
180
+ | `LEMONSQUEEZY_LOG` | Structured-log verbosity to stderr. Set to `all` (or legacy `json`) to log every tool and HTTP call, `audit` to log only destructive-call audit entries plus errors (recommended for production), `error` to log only failures. Unset: no logs. Destructive calls are tagged `audit: true` and include their inputs. |
181
181
 
182
182
  ### Logging format
183
183
 
@@ -191,11 +191,11 @@ HTTP errors include the upstream `X-Request-Id` when present, so support tickets
191
191
 
192
192
  For unattended/agentic use against a live store, we recommend:
193
193
 
194
- 1. Set `LEMONSQUEEZY_ALLOWED_STORE_IDS` to the specific store(s) the agent may touch.
194
+ 1. Use a LemonSqueezy API key scoped to the specific store(s) the agent may touch — this is the only authoritative store boundary for tools that route by their own resource ID (refunds, cancels, archive, delete-webhook, etc.). Set `LEMONSQUEEZY_ALLOWED_STORE_IDS` to the same set as a defense-in-depth gate on the tools that *do* take a `storeId`.
195
195
  2. Set `LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS` to a per-call cap well below any single-refund expectation.
196
196
  3. Set `LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT` to a small number (e.g. 5/min) as a runaway-agent circuit breaker.
197
- 4. Set `LEMONSQUEEZY_LOG=json` and ship stderr to your log aggregator. Alert on `status: "guardrail_block"` or elevated error rates per tool.
198
- 5. Run `LEMONSQUEEZY_API_KEY_COMMAND` against a vault-backed secret so credentials can rotate without restarting the server process.
197
+ 4. Set `LEMONSQUEEZY_LOG=audit` and ship stderr to your log aggregator. The `audit` level keeps every destructive-call entry plus errors but drops successful reads so log volume stays bounded over weeks of operation. Alert on `status: "guardrail_block"` or elevated error rates per tool. Use `LEMONSQUEEZY_LOG=all` while debugging.
198
+ 5. Run `LEMONSQUEEZY_API_KEY_COMMAND` against a vault-backed secret so credentials can rotate without restarting the server process. The API client invalidates its in-process key cache automatically on a 401/403, so a rotated upstream key picks up on the next request rather than waiting on the 1h TTL.
199
199
 
200
200
  What the server does **not** do and you must own at the caller level:
201
201
 
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 checkStoreScopedToolInput(toolAcceptsStoreId, input) {
30183
- if (!toolAcceptsStoreId) return;
30184
- const raw = input.storeId;
30185
- if (raw !== void 0 && raw !== null && raw !== "") {
30186
- checkStoreAllowed(String(raw));
30187
- return;
30188
- }
30189
- if (isStoreAllowlistActive()) {
30190
- throw new GuardrailError("storeId is required when LEMONSQUEEZY_ALLOWED_STORE_IDS is set");
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) {
@@ -30196,11 +30210,35 @@ function isDestructiveCall(tool, input) {
30196
30210
  }
30197
30211
 
30198
30212
  // src/logger.ts
30199
- function isEnabled() {
30200
- return process.env.LEMONSQUEEZY_LOG === "json";
30213
+ function getLogLevel() {
30214
+ const v = process.env.LEMONSQUEEZY_LOG;
30215
+ if (v === "json" || v === "all") return "all";
30216
+ if (v === "audit") return "audit";
30217
+ if (v === "error") return "error";
30218
+ return "off";
30219
+ }
30220
+ var ERROR_STATUS_TAGS = /* @__PURE__ */ new Set(["error", "exception", "guardrail_block", "timeout", "network_error"]);
30221
+ function isErrorEntry(entry) {
30222
+ if (entry.error !== void 0) return true;
30223
+ if (typeof entry.status === "string") return ERROR_STATUS_TAGS.has(entry.status);
30224
+ if (typeof entry.status === "number") return entry.status >= 400;
30225
+ return false;
30226
+ }
30227
+ function shouldLog(entry, level) {
30228
+ switch (level) {
30229
+ case "off":
30230
+ return false;
30231
+ case "all":
30232
+ return true;
30233
+ case "audit":
30234
+ return entry.audit === true || isErrorEntry(entry);
30235
+ case "error":
30236
+ return isErrorEntry(entry);
30237
+ }
30201
30238
  }
30202
30239
  function logEvent(entry) {
30203
- if (!isEnabled()) return;
30240
+ const level = getLogLevel();
30241
+ if (!shouldLog(entry, level)) return;
30204
30242
  try {
30205
30243
  const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry });
30206
30244
  process.stderr.write(`${line}
@@ -30228,10 +30266,46 @@ function logEvent(entry) {
30228
30266
  }
30229
30267
  }
30230
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
+
30231
30304
  // src/retry.ts
30232
30305
  var REQUEST_TIMEOUT_MS = 3e4;
30233
30306
  var DEFAULT_RETRY_WAIT_MS = 1e3;
30234
30307
  var MAX_RETRY_WAIT_MS = 3e4;
30308
+ var OVERALL_DEADLINE_MS = 9e4;
30235
30309
  var DEFAULT_MAX_ATTEMPTS = 4;
30236
30310
  var BASE_BACKOFF_MS = 250;
30237
30311
  var JITTER_FRACTION = 0.25;
@@ -30251,6 +30325,19 @@ function isAbortTimeoutError(err) {
30251
30325
  const e = err;
30252
30326
  return e.name === "TimeoutError" || e.name === "AbortError" || e.code === "ABORT_ERR";
30253
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
+ }
30254
30341
  function backoffDelay(attempt, rand = Math.random) {
30255
30342
  const base = BASE_BACKOFF_MS * 2 ** (attempt - 1);
30256
30343
  const jitter = rand() * base * JITTER_FRACTION;
@@ -30262,31 +30349,54 @@ async function fetchWithRetry(url2, init, opts) {
30262
30349
  const sleep = opts.sleep ?? defaultSleep;
30263
30350
  const fetchImpl = opts.fetchImpl ?? fetch;
30264
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;
30265
30357
  let lastError;
30358
+ let lastResponse;
30266
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;
30267
30365
  try {
30268
30366
  const res = await fetchImpl(url2, { ...init, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
30367
+ lastResponse = res;
30269
30368
  if (res.status === 429) {
30270
30369
  if (attempt === maxAttempts) return res;
30271
30370
  const waitMs = parseRetryAfterMs(res.headers.get("retry-after"));
30272
30371
  if (waitMs > MAX_RETRY_WAIT_MS) return res;
30372
+ if (now() + waitMs >= deadlineAt) return res;
30273
30373
  await sleep(waitMs);
30274
30374
  continue;
30275
30375
  }
30276
30376
  if (res.status >= 500 && res.status < 600 && opts.idempotent && attempt < maxAttempts) {
30277
- await sleep(backoffDelay(attempt, rand));
30377
+ const waitMs = backoffDelay(attempt, rand);
30378
+ if (now() + waitMs >= deadlineAt) return res;
30379
+ await sleep(waitMs);
30278
30380
  continue;
30279
30381
  }
30280
30382
  return res;
30281
30383
  } catch (err) {
30282
30384
  lastError = err;
30283
30385
  if (isAbortTimeoutError(err)) {
30284
- if (!opts.idempotent || attempt === maxAttempts) throw err;
30285
- await sleep(backoffDelay(attempt, rand));
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);
30286
30394
  continue;
30287
30395
  }
30288
30396
  if (err instanceof TypeError && opts.idempotent && attempt < maxAttempts) {
30289
- await sleep(backoffDelay(attempt, rand));
30397
+ const waitMs = backoffDelay(attempt, rand);
30398
+ if (now() + waitMs >= deadlineAt) throw err;
30399
+ await sleep(waitMs);
30290
30400
  continue;
30291
30401
  }
30292
30402
  throw err;
@@ -30330,10 +30440,21 @@ function parseCommand(cmd) {
30330
30440
  if (parts.length === 0) throw new Error("LEMONSQUEEZY_API_KEY_COMMAND is empty");
30331
30441
  return { command: parts[0], args: parts.slice(1) };
30332
30442
  }
30443
+ function fromCache(fingerprint) {
30444
+ if (cached2 && cached2.fingerprint === fingerprint && cached2.expiresAt > Date.now()) {
30445
+ return cached2.key;
30446
+ }
30447
+ return null;
30448
+ }
30449
+ function intoCache(fingerprint, key) {
30450
+ cached2 = { fingerprint, key, expiresAt: Date.now() + CACHE_TTL_MS };
30451
+ }
30333
30452
  async function loadApiKey() {
30334
- if (cached2 && cached2.expiresAt > Date.now()) return cached2.key;
30335
30453
  const cmdStr = process.env.LEMONSQUEEZY_API_KEY_COMMAND;
30336
30454
  if (cmdStr && cmdStr.trim() !== "") {
30455
+ const fingerprint2 = `cmd:${cmdStr}`;
30456
+ const hit2 = fromCache(fingerprint2);
30457
+ if (hit2 !== null) return hit2;
30337
30458
  const { command, args } = parseCommand(cmdStr);
30338
30459
  let stdout;
30339
30460
  try {
@@ -30346,23 +30467,31 @@ async function loadApiKey() {
30346
30467
  const msg = err instanceof Error ? err.message : String(err);
30347
30468
  throw new Error(`LEMONSQUEEZY_API_KEY_COMMAND failed: ${msg}`);
30348
30469
  }
30349
- const key2 = stdout.trim();
30350
- if (!key2) throw new Error("LEMONSQUEEZY_API_KEY_COMMAND produced empty output");
30351
- cached2 = { key: key2, expiresAt: Date.now() + CACHE_TTL_MS };
30352
- return key2;
30470
+ const key = stdout.trim();
30471
+ if (!key) throw new Error("LEMONSQUEEZY_API_KEY_COMMAND produced empty output");
30472
+ intoCache(fingerprint2, key);
30473
+ return key;
30353
30474
  }
30354
- const key = process.env.LEMONSQUEEZY_API_KEY;
30355
- if (!key) {
30475
+ const raw = process.env.LEMONSQUEEZY_API_KEY;
30476
+ if (!raw) {
30356
30477
  throw new Error("LEMONSQUEEZY_API_KEY or LEMONSQUEEZY_API_KEY_COMMAND environment variable is required.");
30357
30478
  }
30358
- if (key.trim() === "") {
30479
+ if (raw.trim() === "") {
30359
30480
  throw new Error("LEMONSQUEEZY_API_KEY is set but empty. Provide a valid API key.");
30360
30481
  }
30361
- return key;
30482
+ const fingerprint = `env:${raw}`;
30483
+ const hit = fromCache(fingerprint);
30484
+ if (hit !== null) return hit;
30485
+ intoCache(fingerprint, raw);
30486
+ return raw;
30487
+ }
30488
+ function invalidateApiKeyCache() {
30489
+ cached2 = null;
30362
30490
  }
30363
30491
 
30364
30492
  // src/api.ts
30365
30493
  var BASE_URL = "https://api.lemonsqueezy.com/v1";
30494
+ var lsIdSchema = external_exports3.string().max(1e4).regex(/^[1-9]\d*$/, "ID must be a positive integer string (e.g. '12345')");
30366
30495
  function encodePath(segment) {
30367
30496
  return encodeURIComponent(String(segment));
30368
30497
  }
@@ -30390,6 +30519,14 @@ function buildQuery(params) {
30390
30519
  function decorateError(error48, requestId) {
30391
30520
  return requestId ? `${error48} (request_id: ${requestId})` : error48;
30392
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
+ }
30393
30530
  async function apiRequest(method, path, body) {
30394
30531
  const start = Date.now();
30395
30532
  const apiKey = await loadApiKey();
@@ -30410,7 +30547,7 @@ async function apiRequest(method, path, body) {
30410
30547
  } catch (err) {
30411
30548
  const latency_ms2 = Date.now() - start;
30412
30549
  if (isAbortTimeoutError(err)) {
30413
- const error48 = `Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s`;
30550
+ const error48 = formatTimeoutMessage(err, latency_ms2);
30414
30551
  logEvent({ event: "http_call", method, path, status: "timeout", latency_ms: latency_ms2, error: error48 });
30415
30552
  return { ok: false, status: 0, error: error48 };
30416
30553
  }
@@ -30421,6 +30558,9 @@ async function apiRequest(method, path, body) {
30421
30558
  const latency_ms = Date.now() - start;
30422
30559
  const requestId = res.headers.get("x-request-id") ?? void 0;
30423
30560
  if (!res.ok) {
30561
+ if (res.status === 401 || res.status === 403) {
30562
+ invalidateApiKeyCache();
30563
+ }
30424
30564
  const errorBody = await res.text();
30425
30565
  try {
30426
30566
  const parsed = JSON.parse(errorBody);
@@ -30494,7 +30634,7 @@ async function licenseRequest(path, body) {
30494
30634
  } catch (err) {
30495
30635
  const latency_ms2 = Date.now() - start;
30496
30636
  if (isAbortTimeoutError(err)) {
30497
- const error48 = `Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s`;
30637
+ const error48 = formatTimeoutMessage(err, latency_ms2);
30498
30638
  logEvent({ event: "http_call", method: "POST", path, status: "timeout", latency_ms: latency_ms2, error: error48 });
30499
30639
  return { ok: false, status: 0, error: error48 };
30500
30640
  }
@@ -30610,14 +30750,14 @@ var affiliateTools = [
30610
30750
  openWorldHint: true
30611
30751
  },
30612
30752
  inputSchema: external_exports3.object({
30613
- affiliateId: external_exports3.string().max(1e4).describe("The affiliate ID"),
30753
+ affiliateId: lsIdSchema.describe("The affiliate ID"),
30614
30754
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,user')")
30615
30755
  }),
30616
30756
  handler: getHandler("/affiliates", "affiliateId")
30617
30757
  },
30618
30758
  {
30619
30759
  name: "ls_list_affiliates",
30620
- 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.",
30621
30761
  annotations: {
30622
30762
  title: "List affiliates",
30623
30763
  readOnlyHint: true,
@@ -30648,7 +30788,7 @@ var checkoutTools = [
30648
30788
  openWorldHint: true
30649
30789
  },
30650
30790
  inputSchema: external_exports3.object({
30651
- checkoutId: external_exports3.string().max(1e4).describe("The checkout ID"),
30791
+ checkoutId: lsIdSchema.describe("The checkout ID"),
30652
30792
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variant')")
30653
30793
  }),
30654
30794
  handler: getHandler("/checkouts", "checkoutId")
@@ -30664,8 +30804,8 @@ var checkoutTools = [
30664
30804
  openWorldHint: true
30665
30805
  },
30666
30806
  inputSchema: external_exports3.object({
30667
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
30668
- variantId: external_exports3.string().max(1e4).optional().describe("Filter by variant ID"),
30807
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
30808
+ variantId: lsIdSchema.optional().describe("Filter by variant ID"),
30669
30809
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variant')"),
30670
30810
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
30671
30811
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
@@ -30683,11 +30823,11 @@ var checkoutTools = [
30683
30823
  openWorldHint: true
30684
30824
  },
30685
30825
  inputSchema: external_exports3.object({
30686
- storeId: external_exports3.string().max(1e4).describe("The store ID"),
30687
- variantId: external_exports3.string().max(1e4).describe("The variant ID for the product being purchased"),
30826
+ storeId: lsIdSchema.describe("The store ID"),
30827
+ variantId: lsIdSchema.describe("The variant ID for the product being purchased"),
30688
30828
  customPrice: external_exports3.number().int().min(0).optional().describe("Custom price in cents (overrides the variant price)"),
30689
- enabledVariants: external_exports3.array(external_exports3.string()).optional().describe("Array of variant IDs to show on the checkout (for products with multiple variants)"),
30690
- email: external_exports3.string().max(1e4).optional().describe("Prefill customer email"),
30829
+ enabledVariants: external_exports3.array(lsIdSchema).optional().describe("Array of variant IDs to show on the checkout (for products with multiple variants)"),
30830
+ email: external_exports3.string().email().max(320).optional().describe("Prefill customer email"),
30691
30831
  name: external_exports3.string().max(1e4).optional().describe("Prefill customer name"),
30692
30832
  billingAddressCountry: external_exports3.string().max(1e4).optional().describe("Prefill billing country (ISO 3166-1 alpha-2)"),
30693
30833
  billingAddressZip: external_exports3.string().max(1e4).optional().describe("Prefill billing ZIP/postal code"),
@@ -30743,7 +30883,7 @@ var customerTools = [
30743
30883
  openWorldHint: true
30744
30884
  },
30745
30885
  inputSchema: external_exports3.object({
30746
- customerId: external_exports3.string().max(1e4).describe("The customer ID"),
30886
+ customerId: lsIdSchema.describe("The customer ID"),
30747
30887
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,orders,subscriptions,license-keys')")
30748
30888
  }),
30749
30889
  handler: getHandler("/customers", "customerId")
@@ -30759,7 +30899,7 @@ var customerTools = [
30759
30899
  openWorldHint: true
30760
30900
  },
30761
30901
  inputSchema: external_exports3.object({
30762
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
30902
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
30763
30903
  email: external_exports3.string().email().max(320).optional().describe("Filter by customer email"),
30764
30904
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,orders,subscriptions,license-keys')"),
30765
30905
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
@@ -30778,7 +30918,7 @@ var customerTools = [
30778
30918
  openWorldHint: true
30779
30919
  },
30780
30920
  inputSchema: external_exports3.object({
30781
- storeId: external_exports3.string().max(1e4).describe("The store ID to create the customer in"),
30921
+ storeId: lsIdSchema.describe("The store ID to create the customer in"),
30782
30922
  name: external_exports3.string().max(1e4).describe("Customer's full name"),
30783
30923
  email: external_exports3.string().email().max(320).describe("Customer's email address"),
30784
30924
  city: external_exports3.string().max(1e4).optional().describe("Customer's city"),
@@ -30806,7 +30946,7 @@ var customerTools = [
30806
30946
  },
30807
30947
  {
30808
30948
  name: "ls_update_customer",
30809
- description: "Update an existing customer's name, email, city, region, country, or status.",
30949
+ description: "Update an existing customer's name, email, city, region, country, or status. The only supported status value is 'archived' \u2014 use ls_archive_customer for the dedicated, audit-tagged path.",
30810
30950
  annotations: {
30811
30951
  title: "Update customer",
30812
30952
  readOnlyHint: false,
@@ -30818,16 +30958,19 @@ var customerTools = [
30818
30958
  // ls_archive_customer and must engage the same rate limiter / audit log;
30819
30959
  // otherwise the dedicated archive tool's destructive flag becomes a side
30820
30960
  // channel anyone can route around. Other field edits (name, email,
30821
- // address) stay on the regular path.
30961
+ // address) stay on the regular path. The schema constrains `status` to
30962
+ // the literal "archived" so a typo ("archive", "Archived") fails at
30963
+ // validation rather than slipping past the predicate as a non-destructive
30964
+ // PATCH that the API would 422 anyway.
30822
30965
  isDestructive: (input) => input.status === "archived",
30823
30966
  inputSchema: external_exports3.object({
30824
- customerId: external_exports3.string().max(1e4).describe("The customer ID to update"),
30967
+ customerId: lsIdSchema.describe("The customer ID to update"),
30825
30968
  name: external_exports3.string().max(1e4).optional().describe("New name"),
30826
30969
  email: external_exports3.string().email().max(320).optional().describe("New email"),
30827
30970
  city: external_exports3.string().max(1e4).optional().describe("New city"),
30828
30971
  region: external_exports3.string().max(1e4).optional().describe("New region/state"),
30829
30972
  country: external_exports3.string().max(1e4).optional().describe("New country (ISO 3166-1 alpha-2 code)"),
30830
- status: external_exports3.string().max(1e4).optional().describe("New status ('archived' to archive the customer)")
30973
+ status: external_exports3.literal("archived").optional().describe("Set to 'archived' to archive the customer. Equivalent to calling ls_archive_customer.")
30831
30974
  }),
30832
30975
  handler: async (input) => {
30833
30976
  const attributes = {};
@@ -30857,7 +31000,7 @@ var customerTools = [
30857
31000
  openWorldHint: true
30858
31001
  },
30859
31002
  inputSchema: external_exports3.object({
30860
- customerId: external_exports3.string().max(1e4).describe("The customer ID to archive")
31003
+ customerId: lsIdSchema.describe("The customer ID to archive")
30861
31004
  }),
30862
31005
  handler: async (input) => {
30863
31006
  return apiPatch(`/customers/${encodePath(input.customerId)}`, {
@@ -30884,14 +31027,14 @@ var discountRedemptionTools = [
30884
31027
  openWorldHint: true
30885
31028
  },
30886
31029
  inputSchema: external_exports3.object({
30887
- discountRedemptionId: external_exports3.string().max(1e4).describe("The discount redemption ID"),
31030
+ discountRedemptionId: lsIdSchema.describe("The discount redemption ID"),
30888
31031
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'discount,order')")
30889
31032
  }),
30890
31033
  handler: getHandler("/discount-redemptions", "discountRedemptionId")
30891
31034
  },
30892
31035
  {
30893
31036
  name: "ls_list_discount_redemptions",
30894
- 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.",
30895
31038
  annotations: {
30896
31039
  title: "List discount redemptions",
30897
31040
  readOnlyHint: true,
@@ -30900,12 +31043,13 @@ var discountRedemptionTools = [
30900
31043
  openWorldHint: true
30901
31044
  },
30902
31045
  inputSchema: external_exports3.object({
30903
- discountId: external_exports3.string().max(1e4).optional().describe("Filter by discount ID"),
30904
- orderId: external_exports3.string().max(1e4).optional().describe("Filter by order ID"),
31046
+ discountId: lsIdSchema.optional().describe("Filter by discount ID"),
31047
+ orderId: lsIdSchema.optional().describe("Filter by order ID"),
30905
31048
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'discount,order')"),
30906
31049
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
30907
31050
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
30908
31051
  }),
31052
+ requiredFilters: ["discountId", "orderId"],
30909
31053
  handler: listHandler("/discount-redemptions", { discountId: "discount_id", orderId: "order_id" })
30910
31054
  }
30911
31055
  ];
@@ -30923,7 +31067,7 @@ var discountTools = [
30923
31067
  openWorldHint: true
30924
31068
  },
30925
31069
  inputSchema: external_exports3.object({
30926
- discountId: external_exports3.string().max(1e4).describe("The discount ID"),
31070
+ discountId: lsIdSchema.describe("The discount ID"),
30927
31071
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants,discount-redemptions')")
30928
31072
  }),
30929
31073
  handler: getHandler("/discounts", "discountId")
@@ -30939,7 +31083,7 @@ var discountTools = [
30939
31083
  openWorldHint: true
30940
31084
  },
30941
31085
  inputSchema: external_exports3.object({
30942
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
31086
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
30943
31087
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants,discount-redemptions')"),
30944
31088
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
30945
31089
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
@@ -30957,7 +31101,7 @@ var discountTools = [
30957
31101
  openWorldHint: true
30958
31102
  },
30959
31103
  inputSchema: external_exports3.object({
30960
- storeId: external_exports3.string().max(1e4).describe("The store ID to create the discount in"),
31104
+ storeId: lsIdSchema.describe("The store ID to create the discount in"),
30961
31105
  name: external_exports3.string().max(1e4).describe("Internal name for the discount"),
30962
31106
  code: external_exports3.string().max(1e4).describe("The discount code customers will enter (e.g. 'SAVE20')"),
30963
31107
  amount: external_exports3.number().int().min(1).describe(
@@ -30972,7 +31116,7 @@ var discountTools = [
30972
31116
  startsAt: external_exports3.string().max(1e4).optional().describe("When the discount becomes active (ISO 8601 format)"),
30973
31117
  expiresAt: external_exports3.string().max(1e4).optional().describe("When the discount expires (ISO 8601 format)"),
30974
31118
  isLimitedToProducts: external_exports3.boolean().optional().describe("If true, the discount only applies to specific variants (set via variantIds)"),
30975
- variantIds: external_exports3.array(external_exports3.string()).optional().describe("Array of variant IDs this discount applies to (requires isLimitedToProducts: true)")
31119
+ variantIds: external_exports3.array(lsIdSchema).optional().describe("Array of variant IDs this discount applies to (requires isLimitedToProducts: true)")
30976
31120
  }),
30977
31121
  handler: async (input) => {
30978
31122
  const attributes = {
@@ -31015,7 +31159,7 @@ var discountTools = [
31015
31159
  openWorldHint: true
31016
31160
  },
31017
31161
  inputSchema: external_exports3.object({
31018
- discountId: external_exports3.string().max(1e4).describe("The discount ID to delete")
31162
+ discountId: lsIdSchema.describe("The discount ID to delete")
31019
31163
  }),
31020
31164
  handler: async (input) => {
31021
31165
  return apiDelete(`/discounts/${encodePath(input.discountId)}`);
@@ -31036,14 +31180,14 @@ var fileTools = [
31036
31180
  openWorldHint: true
31037
31181
  },
31038
31182
  inputSchema: external_exports3.object({
31039
- fileId: external_exports3.string().max(1e4).describe("The file ID"),
31183
+ fileId: lsIdSchema.describe("The file ID"),
31040
31184
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')")
31041
31185
  }),
31042
31186
  handler: getHandler("/files", "fileId")
31043
31187
  },
31044
31188
  {
31045
31189
  name: "ls_list_files",
31046
- 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.",
31047
31191
  annotations: {
31048
31192
  title: "List files",
31049
31193
  readOnlyHint: true,
@@ -31052,11 +31196,12 @@ var fileTools = [
31052
31196
  openWorldHint: true
31053
31197
  },
31054
31198
  inputSchema: external_exports3.object({
31055
- variantId: external_exports3.string().max(1e4).optional().describe("Filter by variant ID"),
31199
+ variantId: lsIdSchema.optional().describe("Filter by variant ID"),
31056
31200
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')"),
31057
31201
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31058
31202
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
31059
31203
  }),
31204
+ requiredFilters: ["variantId"],
31060
31205
  handler: listHandler("/files", { variantId: "variant_id" })
31061
31206
  }
31062
31207
  ];
@@ -31074,14 +31219,14 @@ var licenseKeyInstanceTools = [
31074
31219
  openWorldHint: true
31075
31220
  },
31076
31221
  inputSchema: external_exports3.object({
31077
- licenseKeyInstanceId: external_exports3.string().max(1e4).describe("The license key instance ID"),
31222
+ licenseKeyInstanceId: lsIdSchema.describe("The license key instance ID"),
31078
31223
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'license-key')")
31079
31224
  }),
31080
31225
  handler: getHandler("/license-key-instances", "licenseKeyInstanceId")
31081
31226
  },
31082
31227
  {
31083
31228
  name: "ls_list_license_key_instances",
31084
- 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.",
31085
31230
  annotations: {
31086
31231
  title: "List license key instances",
31087
31232
  readOnlyHint: true,
@@ -31090,11 +31235,12 @@ var licenseKeyInstanceTools = [
31090
31235
  openWorldHint: true
31091
31236
  },
31092
31237
  inputSchema: external_exports3.object({
31093
- licenseKeyId: external_exports3.string().max(1e4).optional().describe("Filter by license key ID"),
31238
+ licenseKeyId: lsIdSchema.optional().describe("Filter by license key ID"),
31094
31239
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'license-key')"),
31095
31240
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31096
31241
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
31097
31242
  }),
31243
+ requiredFilters: ["licenseKeyId"],
31098
31244
  handler: listHandler("/license-key-instances", { licenseKeyId: "license_key_id" })
31099
31245
  }
31100
31246
  ];
@@ -31112,7 +31258,7 @@ var licenseKeyTools = [
31112
31258
  openWorldHint: true
31113
31259
  },
31114
31260
  inputSchema: external_exports3.object({
31115
- licenseKeyId: external_exports3.string().max(1e4).describe("The license key ID"),
31261
+ licenseKeyId: lsIdSchema.describe("The license key ID"),
31116
31262
  include: external_exports3.string().max(1e4).optional().describe(
31117
31263
  "Comma-separated related resources to include (e.g. 'store,customer,order,order-item,product,license-key-instances')"
31118
31264
  )
@@ -31130,10 +31276,10 @@ var licenseKeyTools = [
31130
31276
  openWorldHint: true
31131
31277
  },
31132
31278
  inputSchema: external_exports3.object({
31133
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
31134
- orderId: external_exports3.string().max(1e4).optional().describe("Filter by order ID"),
31135
- orderItemId: external_exports3.string().max(1e4).optional().describe("Filter by order item ID"),
31136
- productId: external_exports3.string().max(1e4).optional().describe("Filter by product ID"),
31279
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
31280
+ orderId: lsIdSchema.optional().describe("Filter by order ID"),
31281
+ orderItemId: lsIdSchema.optional().describe("Filter by order item ID"),
31282
+ productId: lsIdSchema.optional().describe("Filter by product ID"),
31137
31283
  include: external_exports3.string().max(1e4).optional().describe(
31138
31284
  "Comma-separated related resources to include (e.g. 'store,customer,order,order-item,product,license-key-instances')"
31139
31285
  ),
@@ -31157,13 +31303,16 @@ var licenseKeyTools = [
31157
31303
  idempotentHint: true,
31158
31304
  openWorldHint: true
31159
31305
  },
31160
- // Disabling a license key revokes a customer's access. Tag the call as
31161
- // destructive only when `disabled: true` so the rate limiter and audit log
31162
- // engage on revocation, while benign edits (expiry, activation limit) stay
31163
- // on the regular path.
31164
- isDestructive: (input) => input.disabled === true,
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,
31165
31314
  inputSchema: external_exports3.object({
31166
- licenseKeyId: external_exports3.string().max(1e4).describe("The license key ID to update"),
31315
+ licenseKeyId: lsIdSchema.describe("The license key ID to update"),
31167
31316
  activationLimit: external_exports3.number().int().min(0).optional().describe("Maximum number of activations allowed (0 = unlimited)"),
31168
31317
  disabled: external_exports3.boolean().optional().describe("Set to true to disable this license key"),
31169
31318
  expiresAt: external_exports3.string().max(1e4).nullable().optional().describe("Expiry date (ISO 8601 format). Set to null to remove expiry.")
@@ -31263,14 +31412,14 @@ var orderItemTools = [
31263
31412
  openWorldHint: true
31264
31413
  },
31265
31414
  inputSchema: external_exports3.object({
31266
- orderItemId: external_exports3.string().max(1e4).describe("The order item ID"),
31415
+ orderItemId: lsIdSchema.describe("The order item ID"),
31267
31416
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'order,product,variant')")
31268
31417
  }),
31269
31418
  handler: getHandler("/order-items", "orderItemId")
31270
31419
  },
31271
31420
  {
31272
31421
  name: "ls_list_order_items",
31273
- 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.",
31274
31423
  annotations: {
31275
31424
  title: "List order items",
31276
31425
  readOnlyHint: true,
@@ -31279,13 +31428,14 @@ var orderItemTools = [
31279
31428
  openWorldHint: true
31280
31429
  },
31281
31430
  inputSchema: external_exports3.object({
31282
- orderId: external_exports3.string().max(1e4).optional().describe("Filter by order ID"),
31283
- productId: external_exports3.string().max(1e4).optional().describe("Filter by product ID"),
31284
- variantId: external_exports3.string().max(1e4).optional().describe("Filter by variant ID"),
31431
+ orderId: lsIdSchema.optional().describe("Filter by order ID"),
31432
+ productId: lsIdSchema.optional().describe("Filter by product ID"),
31433
+ variantId: lsIdSchema.optional().describe("Filter by variant ID"),
31285
31434
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'order,product,variant')"),
31286
31435
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31287
31436
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
31288
31437
  }),
31438
+ requiredFilters: ["orderId", "productId", "variantId"],
31289
31439
  handler: listHandler("/order-items", { orderId: "order_id", productId: "product_id", variantId: "variant_id" })
31290
31440
  }
31291
31441
  ];
@@ -31303,7 +31453,7 @@ var orderTools = [
31303
31453
  openWorldHint: true
31304
31454
  },
31305
31455
  inputSchema: external_exports3.object({
31306
- orderId: external_exports3.string().max(1e4).describe("The order ID"),
31456
+ orderId: lsIdSchema.describe("The order ID"),
31307
31457
  include: external_exports3.string().max(1e4).optional().describe(
31308
31458
  "Comma-separated related resources to include (e.g. 'store,customer,order-items,subscriptions,license-keys,discount-redemptions')"
31309
31459
  )
@@ -31321,7 +31471,7 @@ var orderTools = [
31321
31471
  openWorldHint: true
31322
31472
  },
31323
31473
  inputSchema: external_exports3.object({
31324
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
31474
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
31325
31475
  userEmail: external_exports3.string().email().max(320).optional().describe("Filter by user email"),
31326
31476
  include: external_exports3.string().max(1e4).optional().describe(
31327
31477
  "Comma-separated related resources to include (e.g. 'store,customer,order-items,subscriptions,license-keys,discount-redemptions')"
@@ -31342,7 +31492,7 @@ var orderTools = [
31342
31492
  openWorldHint: true
31343
31493
  },
31344
31494
  inputSchema: external_exports3.object({
31345
- orderId: external_exports3.string().max(1e4).describe("The order ID"),
31495
+ orderId: lsIdSchema.describe("The order ID"),
31346
31496
  name: external_exports3.string().max(1e4).optional().describe("Customer name on the invoice"),
31347
31497
  address: external_exports3.string().max(1e4).optional().describe("Customer address on the invoice"),
31348
31498
  city: external_exports3.string().max(1e4).optional().describe("Customer city"),
@@ -31377,7 +31527,7 @@ var orderTools = [
31377
31527
  openWorldHint: true
31378
31528
  },
31379
31529
  inputSchema: external_exports3.object({
31380
- orderId: external_exports3.string().max(1e4).describe("The order ID to refund"),
31530
+ orderId: lsIdSchema.describe("The order ID to refund"),
31381
31531
  amount: external_exports3.number().int().min(1).describe("Refund amount in cents (e.g. 1000 = $10.00)")
31382
31532
  }),
31383
31533
  handler: async (input) => {
@@ -31402,14 +31552,14 @@ var priceTools = [
31402
31552
  openWorldHint: true
31403
31553
  },
31404
31554
  inputSchema: external_exports3.object({
31405
- priceId: external_exports3.string().max(1e4).describe("The price ID"),
31555
+ priceId: lsIdSchema.describe("The price ID"),
31406
31556
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')")
31407
31557
  }),
31408
31558
  handler: getHandler("/prices", "priceId")
31409
31559
  },
31410
31560
  {
31411
31561
  name: "ls_list_prices",
31412
- 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.",
31413
31563
  annotations: {
31414
31564
  title: "List prices",
31415
31565
  readOnlyHint: true,
@@ -31418,11 +31568,12 @@ var priceTools = [
31418
31568
  openWorldHint: true
31419
31569
  },
31420
31570
  inputSchema: external_exports3.object({
31421
- variantId: external_exports3.string().max(1e4).optional().describe("Filter by variant ID"),
31571
+ variantId: lsIdSchema.optional().describe("Filter by variant ID"),
31422
31572
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'variant')"),
31423
31573
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31424
31574
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
31425
31575
  }),
31576
+ requiredFilters: ["variantId"],
31426
31577
  handler: listHandler("/prices", { variantId: "variant_id" })
31427
31578
  }
31428
31579
  ];
@@ -31440,7 +31591,7 @@ var productTools = [
31440
31591
  openWorldHint: true
31441
31592
  },
31442
31593
  inputSchema: external_exports3.object({
31443
- productId: external_exports3.string().max(1e4).describe("The product ID"),
31594
+ productId: lsIdSchema.describe("The product ID"),
31444
31595
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants')")
31445
31596
  }),
31446
31597
  handler: getHandler("/products", "productId")
@@ -31456,7 +31607,7 @@ var productTools = [
31456
31607
  openWorldHint: true
31457
31608
  },
31458
31609
  inputSchema: external_exports3.object({
31459
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
31610
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
31460
31611
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,variants')"),
31461
31612
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31462
31613
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
@@ -31478,7 +31629,7 @@ var storeTools = [
31478
31629
  openWorldHint: true
31479
31630
  },
31480
31631
  inputSchema: external_exports3.object({
31481
- storeId: external_exports3.string().max(1e4).describe("The store ID"),
31632
+ storeId: lsIdSchema.describe("The store ID"),
31482
31633
  include: external_exports3.string().max(1e4).optional().describe(
31483
31634
  "Comma-separated related resources to include (e.g. 'products,discounts,license-keys,subscriptions,webhooks')"
31484
31635
  )
@@ -31519,7 +31670,7 @@ var subscriptionInvoiceTools = [
31519
31670
  openWorldHint: true
31520
31671
  },
31521
31672
  inputSchema: external_exports3.object({
31522
- subscriptionInvoiceId: external_exports3.string().max(1e4).describe("The subscription invoice ID"),
31673
+ subscriptionInvoiceId: lsIdSchema.describe("The subscription invoice ID"),
31523
31674
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,subscription')")
31524
31675
  }),
31525
31676
  handler: getHandler("/subscription-invoices", "subscriptionInvoiceId")
@@ -31535,8 +31686,8 @@ var subscriptionInvoiceTools = [
31535
31686
  openWorldHint: true
31536
31687
  },
31537
31688
  inputSchema: external_exports3.object({
31538
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
31539
- subscriptionId: external_exports3.string().max(1e4).optional().describe("Filter by subscription ID"),
31689
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
31690
+ subscriptionId: lsIdSchema.optional().describe("Filter by subscription ID"),
31540
31691
  status: external_exports3.enum(["pending", "paid", "void", "refunded"]).optional().describe("Filter by invoice status"),
31541
31692
  refunded: external_exports3.boolean().optional().describe("Filter by refunded status"),
31542
31693
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store,subscription')"),
@@ -31561,7 +31712,7 @@ var subscriptionInvoiceTools = [
31561
31712
  openWorldHint: true
31562
31713
  },
31563
31714
  inputSchema: external_exports3.object({
31564
- subscriptionInvoiceId: external_exports3.string().max(1e4).describe("The subscription invoice ID"),
31715
+ subscriptionInvoiceId: lsIdSchema.describe("The subscription invoice ID"),
31565
31716
  name: external_exports3.string().max(1e4).optional().describe("Customer name on the invoice"),
31566
31717
  address: external_exports3.string().max(1e4).optional().describe("Customer address on the invoice"),
31567
31718
  city: external_exports3.string().max(1e4).optional().describe("Customer city"),
@@ -31598,7 +31749,7 @@ var subscriptionInvoiceTools = [
31598
31749
  openWorldHint: true
31599
31750
  },
31600
31751
  inputSchema: external_exports3.object({
31601
- subscriptionInvoiceId: external_exports3.string().max(1e4).describe("The subscription invoice ID to refund"),
31752
+ subscriptionInvoiceId: lsIdSchema.describe("The subscription invoice ID to refund"),
31602
31753
  amount: external_exports3.number().int().min(1).describe("Refund amount in cents (e.g. 1000 = $10.00)")
31603
31754
  }),
31604
31755
  handler: async (input) => {
@@ -31627,14 +31778,14 @@ var subscriptionItemTools = [
31627
31778
  openWorldHint: true
31628
31779
  },
31629
31780
  inputSchema: external_exports3.object({
31630
- subscriptionItemId: external_exports3.string().max(1e4).describe("The subscription item ID"),
31781
+ subscriptionItemId: lsIdSchema.describe("The subscription item ID"),
31631
31782
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription,price,usage-records')")
31632
31783
  }),
31633
31784
  handler: getHandler("/subscription-items", "subscriptionItemId")
31634
31785
  },
31635
31786
  {
31636
31787
  name: "ls_list_subscription_items",
31637
- 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.",
31638
31789
  annotations: {
31639
31790
  title: "List subscription items",
31640
31791
  readOnlyHint: true,
@@ -31643,12 +31794,13 @@ var subscriptionItemTools = [
31643
31794
  openWorldHint: true
31644
31795
  },
31645
31796
  inputSchema: external_exports3.object({
31646
- subscriptionId: external_exports3.string().max(1e4).optional().describe("Filter by subscription ID"),
31647
- priceId: external_exports3.string().max(1e4).optional().describe("Filter by price ID"),
31797
+ subscriptionId: lsIdSchema.optional().describe("Filter by subscription ID"),
31798
+ priceId: lsIdSchema.optional().describe("Filter by price ID"),
31648
31799
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription,price,usage-records')"),
31649
31800
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31650
31801
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
31651
31802
  }),
31803
+ requiredFilters: ["subscriptionId", "priceId"],
31652
31804
  handler: listHandler("/subscription-items", { subscriptionId: "subscription_id", priceId: "price_id" })
31653
31805
  },
31654
31806
  {
@@ -31662,7 +31814,7 @@ var subscriptionItemTools = [
31662
31814
  openWorldHint: true
31663
31815
  },
31664
31816
  inputSchema: external_exports3.object({
31665
- subscriptionItemId: external_exports3.string().max(1e4).describe("The subscription item ID to update"),
31817
+ subscriptionItemId: lsIdSchema.describe("The subscription item ID to update"),
31666
31818
  quantity: external_exports3.number().int().min(1).describe("New quantity for the subscription item")
31667
31819
  }),
31668
31820
  handler: async (input) => {
@@ -31686,7 +31838,7 @@ var subscriptionItemTools = [
31686
31838
  openWorldHint: true
31687
31839
  },
31688
31840
  inputSchema: external_exports3.object({
31689
- subscriptionItemId: external_exports3.string().max(1e4).describe("The subscription item ID")
31841
+ subscriptionItemId: lsIdSchema.describe("The subscription item ID")
31690
31842
  }),
31691
31843
  handler: async (input) => {
31692
31844
  return apiGet(`/subscription-items/${encodePath(input.subscriptionItemId)}/current-usage`);
@@ -31707,7 +31859,7 @@ var subscriptionTools = [
31707
31859
  openWorldHint: true
31708
31860
  },
31709
31861
  inputSchema: external_exports3.object({
31710
- subscriptionId: external_exports3.string().max(1e4).describe("The subscription ID"),
31862
+ subscriptionId: lsIdSchema.describe("The subscription ID"),
31711
31863
  include: external_exports3.string().max(1e4).optional().describe(
31712
31864
  "Comma-separated related resources to include (e.g. 'store,customer,order,order-item,product,variant,subscription-items,subscription-invoices')"
31713
31865
  )
@@ -31725,11 +31877,11 @@ var subscriptionTools = [
31725
31877
  openWorldHint: true
31726
31878
  },
31727
31879
  inputSchema: external_exports3.object({
31728
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
31729
- orderId: external_exports3.string().max(1e4).optional().describe("Filter by order ID"),
31730
- orderItemId: external_exports3.string().max(1e4).optional().describe("Filter by order item ID"),
31731
- productId: external_exports3.string().max(1e4).optional().describe("Filter by product ID"),
31732
- variantId: external_exports3.string().max(1e4).optional().describe("Filter by variant ID"),
31880
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
31881
+ orderId: lsIdSchema.optional().describe("Filter by order ID"),
31882
+ orderItemId: lsIdSchema.optional().describe("Filter by order item ID"),
31883
+ productId: lsIdSchema.optional().describe("Filter by product ID"),
31884
+ variantId: lsIdSchema.optional().describe("Filter by variant ID"),
31733
31885
  userEmail: external_exports3.string().email().max(320).optional().describe("Filter by user email"),
31734
31886
  status: external_exports3.enum(["on_trial", "active", "paused", "past_due", "unpaid", "cancelled", "expired"]).optional().describe("Filter by subscription status"),
31735
31887
  include: external_exports3.string().max(1e4).optional().describe(
@@ -31770,8 +31922,8 @@ var subscriptionTools = [
31770
31922
  // - disableProrations toggle on plan-change behavior
31771
31923
  isDestructive: (input) => typeof input.pause === "string" && input.pause !== "resume" || typeof input.variantId === "string",
31772
31924
  inputSchema: external_exports3.object({
31773
- subscriptionId: external_exports3.string().max(1e4).describe("The subscription ID to update"),
31774
- variantId: external_exports3.string().max(1e4).regex(/^[1-9]\d*$/, "variantId must be a positive integer string (e.g. '12345')").optional().describe("New variant ID for plan switching"),
31925
+ subscriptionId: lsIdSchema.describe("The subscription ID to update"),
31926
+ variantId: lsIdSchema.optional().describe("New variant ID for plan switching"),
31775
31927
  pause: external_exports3.enum(["void", "free", "resume"]).optional().describe("Pause mode: 'void' (pause, skip billing), 'free' (pause, keep access free), or 'resume' to unpause"),
31776
31928
  cancelled: external_exports3.literal(false).optional().describe(
31777
31929
  "Set to false to un-cancel a subscription before it expires. To cancel, use ls_cancel_subscription instead."
@@ -31810,7 +31962,7 @@ var subscriptionTools = [
31810
31962
  openWorldHint: true
31811
31963
  },
31812
31964
  inputSchema: external_exports3.object({
31813
- subscriptionId: external_exports3.string().max(1e4).describe("The subscription ID to cancel")
31965
+ subscriptionId: lsIdSchema.describe("The subscription ID to cancel")
31814
31966
  }),
31815
31967
  handler: async (input) => {
31816
31968
  return apiDelete(`/subscriptions/${encodePath(input.subscriptionId)}`);
@@ -31831,14 +31983,14 @@ var usageRecordTools = [
31831
31983
  openWorldHint: true
31832
31984
  },
31833
31985
  inputSchema: external_exports3.object({
31834
- usageRecordId: external_exports3.string().max(1e4).describe("The usage record ID"),
31986
+ usageRecordId: lsIdSchema.describe("The usage record ID"),
31835
31987
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription-item')")
31836
31988
  }),
31837
31989
  handler: getHandler("/usage-records", "usageRecordId")
31838
31990
  },
31839
31991
  {
31840
31992
  name: "ls_list_usage_records",
31841
- 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.",
31842
31994
  annotations: {
31843
31995
  title: "List usage records",
31844
31996
  readOnlyHint: true,
@@ -31847,11 +31999,12 @@ var usageRecordTools = [
31847
31999
  openWorldHint: true
31848
32000
  },
31849
32001
  inputSchema: external_exports3.object({
31850
- subscriptionItemId: external_exports3.string().max(1e4).optional().describe("Filter by subscription item ID"),
32002
+ subscriptionItemId: lsIdSchema.optional().describe("Filter by subscription item ID"),
31851
32003
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'subscription-item')"),
31852
32004
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31853
32005
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
31854
32006
  }),
32007
+ requiredFilters: ["subscriptionItemId"],
31855
32008
  handler: listHandler("/usage-records", { subscriptionItemId: "subscription_item_id" })
31856
32009
  },
31857
32010
  {
@@ -31868,7 +32021,7 @@ var usageRecordTools = [
31868
32021
  openWorldHint: true
31869
32022
  },
31870
32023
  inputSchema: external_exports3.object({
31871
- subscriptionItemId: external_exports3.string().max(1e4).describe("The subscription item ID to report usage for"),
32024
+ subscriptionItemId: lsIdSchema.describe("The subscription item ID to report usage for"),
31872
32025
  quantity: external_exports3.number().int().min(0).describe("The usage quantity to report"),
31873
32026
  action: external_exports3.enum(["increment", "set"]).optional().describe("How to apply the quantity: 'increment' (add to current, default) or 'set' (replace current)")
31874
32027
  }),
@@ -31924,14 +32077,14 @@ var variantTools = [
31924
32077
  openWorldHint: true
31925
32078
  },
31926
32079
  inputSchema: external_exports3.object({
31927
- variantId: external_exports3.string().max(1e4).describe("The variant ID"),
32080
+ variantId: lsIdSchema.describe("The variant ID"),
31928
32081
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'product,files')")
31929
32082
  }),
31930
32083
  handler: getHandler("/variants", "variantId")
31931
32084
  },
31932
32085
  {
31933
32086
  name: "ls_list_variants",
31934
- 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.",
31935
32088
  annotations: {
31936
32089
  title: "List variants",
31937
32090
  readOnlyHint: true,
@@ -31940,11 +32093,12 @@ var variantTools = [
31940
32093
  openWorldHint: true
31941
32094
  },
31942
32095
  inputSchema: external_exports3.object({
31943
- productId: external_exports3.string().max(1e4).optional().describe("Filter by product ID"),
32096
+ productId: lsIdSchema.optional().describe("Filter by product ID"),
31944
32097
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'product,files')"),
31945
32098
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31946
32099
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
31947
32100
  }),
32101
+ requiredFilters: ["productId"],
31948
32102
  handler: listHandler("/variants", { productId: "product_id" })
31949
32103
  }
31950
32104
  ];
@@ -31962,7 +32116,7 @@ var webhookTools = [
31962
32116
  openWorldHint: true
31963
32117
  },
31964
32118
  inputSchema: external_exports3.object({
31965
- webhookId: external_exports3.string().max(1e4).describe("The webhook ID"),
32119
+ webhookId: lsIdSchema.describe("The webhook ID"),
31966
32120
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store')")
31967
32121
  }),
31968
32122
  handler: getHandler("/webhooks", "webhookId")
@@ -31978,7 +32132,7 @@ var webhookTools = [
31978
32132
  openWorldHint: true
31979
32133
  },
31980
32134
  inputSchema: external_exports3.object({
31981
- storeId: external_exports3.string().max(1e4).optional().describe("Filter by store ID"),
32135
+ storeId: lsIdSchema.optional().describe("Filter by store ID"),
31982
32136
  include: external_exports3.string().max(1e4).optional().describe("Comma-separated related resources to include (e.g. 'store')"),
31983
32137
  pageNumber: external_exports3.number().int().min(1).optional().describe("Page number (1-indexed)"),
31984
32138
  pageSize: external_exports3.number().int().min(1).max(100).optional().describe("Results per page (1-100)")
@@ -31996,7 +32150,7 @@ var webhookTools = [
31996
32150
  openWorldHint: true
31997
32151
  },
31998
32152
  inputSchema: external_exports3.object({
31999
- storeId: external_exports3.string().max(1e4).describe("The store ID"),
32153
+ storeId: lsIdSchema.describe("The store ID"),
32000
32154
  url: external_exports3.string().max(1e4).describe("The URL to send webhook events to"),
32001
32155
  events: external_exports3.array(external_exports3.string()).describe(
32002
32156
  "Event types to subscribe to (e.g. ['order_created', 'subscription_created', 'subscription_updated', 'subscription_cancelled', 'subscription_payment_success', 'subscription_payment_failed', 'license_key_created'])"
@@ -32030,7 +32184,7 @@ var webhookTools = [
32030
32184
  openWorldHint: true
32031
32185
  },
32032
32186
  inputSchema: external_exports3.object({
32033
- webhookId: external_exports3.string().max(1e4).describe("The webhook ID to update"),
32187
+ webhookId: lsIdSchema.describe("The webhook ID to update"),
32034
32188
  url: external_exports3.string().max(1e4).optional().describe("New URL to send webhook events to"),
32035
32189
  events: external_exports3.array(external_exports3.string()).optional().describe("Updated list of event types to subscribe to"),
32036
32190
  secret: external_exports3.string().min(6).max(40).optional().describe("New signing secret")
@@ -32060,7 +32214,7 @@ var webhookTools = [
32060
32214
  openWorldHint: true
32061
32215
  },
32062
32216
  inputSchema: external_exports3.object({
32063
- webhookId: external_exports3.string().max(1e4).describe("The webhook ID to delete")
32217
+ webhookId: lsIdSchema.describe("The webhook ID to delete")
32064
32218
  }),
32065
32219
  handler: async (input) => {
32066
32220
  return apiDelete(`/webhooks/${encodePath(input.webhookId)}`);
@@ -32069,7 +32223,7 @@ var webhookTools = [
32069
32223
  ];
32070
32224
 
32071
32225
  // src/index.ts
32072
- var version2 = true ? "0.6.2" : (await null).createRequire(import.meta.url)("../package.json").version;
32226
+ var version2 = true ? "0.7.1" : (await null).createRequire(import.meta.url)("../package.json").version;
32073
32227
  var subcommand = process.argv[2];
32074
32228
  if (subcommand === "version" || subcommand === "--version") {
32075
32229
  console.log(version2);
@@ -32103,7 +32257,6 @@ var server = new McpServer({
32103
32257
  version: version2
32104
32258
  });
32105
32259
  for (const tool of allTools) {
32106
- const toolAcceptsStoreId = "storeId" in tool.inputSchema.shape;
32107
32260
  server.tool(
32108
32261
  tool.name,
32109
32262
  tool.description,
@@ -32114,7 +32267,7 @@ for (const tool of allTools) {
32114
32267
  const start = Date.now();
32115
32268
  try {
32116
32269
  if (isDestructive) checkDestructiveRateLimit();
32117
- checkStoreScopedToolInput(toolAcceptsStoreId, input);
32270
+ checkStoreScopedToolInput(tool, input);
32118
32271
  const result = await tool.handler(input);
32119
32272
  const response = result;
32120
32273
  const latency_ms = Date.now() - start;
@@ -32126,7 +32279,7 @@ for (const tool of allTools) {
32126
32279
  request_id: response.requestId,
32127
32280
  error: response.ok ? void 0 : response.error,
32128
32281
  audit: isDestructive ? true : void 0,
32129
- inputs: isDestructive ? input : void 0
32282
+ inputs: isDestructive ? redactSecrets(input) : void 0
32130
32283
  });
32131
32284
  if (!response.ok) {
32132
32285
  return {
@@ -32153,7 +32306,7 @@ for (const tool of allTools) {
32153
32306
  latency_ms,
32154
32307
  error: message,
32155
32308
  audit: isDestructive ? true : void 0,
32156
- inputs: isDestructive ? input : void 0
32309
+ inputs: isDestructive ? redactSecrets(input) : void 0
32157
32310
  });
32158
32311
  return {
32159
32312
  content: [{ type: "text", text: `Error: ${message}` }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/lemonsqueezy-mcp",
3
- "version": "0.6.2",
3
+ "version": "0.7.1",
4
4
  "description": "LemonSqueezy MCP server for managing your store from AI assistants",
5
5
  "license": "MIT",
6
6
  "author": "YawLabs <contact@yaw.sh>",