loading…
Search for a command to run...
loading…
MCP server for the LemonSqueezy API. Enables managing stores, products, customers, subscriptions, discounts, and license keys from any MCP-compatible AI assista
MCP server for the LemonSqueezy API. Enables managing stores, products, customers, subscriptions, discounts, and license keys from any MCP-compatible AI assistant.
MCP server for the LemonSqueezy API. Manage your store, products, customers, subscriptions, discounts, license keys, and more from any MCP-compatible AI assistant.
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
npx -y @yawlabs/lemonsqueezy-mcp@latest
Or one-click install via Smithery:
npx -y @smithery/cli install @yawlabs/lemonsqueezy-mcp --client claude
Smithery prompts for your env vars (API key, optional guardrails) and writes the config into your client for you.
Once configured, you can ask your AI assistant store-management questions in plain English and it routes them through the MCP tools:
You: How much did we make from the "Pro Annual" plan last month?
Claude: [calls ls_list_subscriptions, ls_get_variant, ls_list_subscription_invoices]
Pro Annual brought in $14,280 across 84 active subscriptions in April.
Three of those were upgrades from monthly; none churned.
You: Refund order #LS-1234 in full.
Claude: [calls ls_get_order to fetch the total, then ls_refund_order with amount = total]
Refunded $99.00 against order LS-1234. The customer's card will see the
credit in 5-10 business days.
You: Disable license key abc-123 for the customer who reported abuse.
Claude: [calls ls_list_license_keys to find the ID, then ls_update_license_key with disabled: true]
License key disabled. Their existing activations will fail validation
on the next check.
Guardrails (refund cap, rate limit, store allowlist) catch the obvious mistakes before they reach LemonSqueezy. See Configuration for the env vars that turn them on.
Set your LemonSqueezy API key as an environment variable:
export LEMONSQUEEZY_API_KEY="your-api-key"
Get your API key from your LemonSqueezy dashboard.
A multi-stage Dockerfile is included at the repo root. The runtime image is a single bundled file on node:20-alpine running as the non-root node user, with no port exposed (stdio transport).
docker build -t yawlabs/lemonsqueezy-mcp .
docker run --rm -i -e LEMONSQUEEZY_API_KEY="your-api-key" yawlabs/lemonsqueezy-mcp
A matching Containerfile is provided for Podman users. It is generated from Dockerfile via npm run gen:containerfile; CI calls npm run check:containerfile so a divergent edit fails review rather than drifting silently.
Add to your MCP config:
{
"mcpServers": {
"lemonsqueezy": {
"command": "npx",
"args": ["-y", "@yawlabs/lemonsqueezy-mcp@latest"],
"env": {
"LEMONSQUEEZY_API_KEY": "your-api-key"
}
}
}
}
Add to claude_desktop_config.json:
{
"mcpServers": {
"lemonsqueezy": {
"command": "npx",
"args": ["-y", "@yawlabs/lemonsqueezy-mcp@latest"],
"env": {
"LEMONSQUEEZY_API_KEY": "your-api-key"
}
}
}
}
ls_get_user — Get the authenticated userls_get_store — Get a store by IDls_list_stores — List all storesls_get_customer — Get a customer by IDls_list_customers — List customers (filter by store, email)ls_create_customer — Create a customerls_update_customer — Update a customerls_archive_customer — Archive a customerls_get_product — Get a product by IDls_list_products — List products (filter by store)ls_get_variant — Get a variant by IDls_list_variants — List variants (filter by product)ls_get_price — Get a price by IDls_list_prices — List prices (filter by variant)ls_get_file — Get a file by IDls_list_files — List files (filter by variant)ls_get_order — Get an order by IDls_list_orders — List orders (filter by store, email)ls_generate_order_invoice — Generate a PDF invoicels_refund_order — Issue a refundls_get_order_item — Get an order item by IDls_list_order_items — List order items (filter by order, product, variant)ls_get_subscription — Get a subscription by IDls_list_subscriptions — List subscriptions (filter by store, status, product, etc.)ls_update_subscription — Update (plan switch, pause, billing anchor, trial)ls_cancel_subscription — Cancel a subscriptionls_get_subscription_invoice — Get a subscription invoice by IDls_list_subscription_invoices — List subscription invoices (filter by store, subscription, status)ls_generate_subscription_invoice — Generate a PDF invoicels_refund_subscription_invoice — Issue a refundls_get_subscription_item — Get a subscription item by IDls_list_subscription_items — List subscription items (filter by subscription, price)ls_update_subscription_item — Update quantityls_get_subscription_item_usage — Get current billing period usagels_get_usage_record — Get a usage record by IDls_list_usage_records — List usage records (filter by subscription item)ls_create_usage_record — Report metered usage (increment or set)ls_get_discount — Get a discount by IDls_list_discounts — List discounts (filter by store)ls_create_discount — Create a discount codels_delete_discount — Delete a discountls_get_discount_redemption — Get a discount redemption by IDls_list_discount_redemptions — List redemptions (filter by discount, order)ls_get_license_key — Get a license key by IDls_list_license_keys — List license keys (filter by store, order, product)ls_update_license_key — Update activation limit, expiry, or disabled statusls_get_license_key_instance — Get a license key activation by IDls_list_license_key_instances — List activations (filter by license key)ls_get_checkout — Get a checkout by IDls_list_checkouts — List checkouts (filter by store, variant)ls_create_checkout — Create a checkout URL (custom pricing, prefill, discounts)ls_get_webhook — Get a webhook by IDls_list_webhooks — List webhooks (filter by store)ls_create_webhook — Create a webhookls_update_webhook — Update a webhookls_delete_webhook — Delete a webhookls_activate_license — Activate a license key (no API key required)ls_validate_license — Validate a license key (no API key required)ls_deactivate_license — Deactivate a license key instance (no API key required)Bridge to a separate @yawlabs/lemonsqueezy-webhook-sink process so the agent can reconcile against webhooks that actually fired. Tools are always registered; if LEMONSQUEEZY_SINK_URL / LEMONSQUEEZY_SINK_ADMIN_TOKEN are unset, calls return a clear "not configured" error.
ls_sink_events_list — List webhook events the sink has received (filter by since / type / limit)ls_sink_event_mark_processed — Mark a sink event as processed by your consumer (idempotent)ls_sink_stats — Get total events, unprocessed count, and last-received timestampnpx startupLEMONSQUEEZY_DISABLE_CLASSES), and per-authority-class rate limits (LEMONSQUEEZY_RATE_LIMIT_PER_CLASS)lemonsqueezy://audit-log exposes the last 1000 destructive-call entries as application/x-ndjson for clients without stderr accesserror, audit, all)All configuration is via environment variables. Only LEMONSQUEEZY_API_KEY (or LEMONSQUEEZY_API_KEY_COMMAND) is required; everything else is opt-in.
| Variable | Purpose |
|---|---|
LEMONSQUEEZY_API_KEY |
LemonSqueezy API token. |
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. |
LEMONSQUEEZY_TEST_API_KEY |
Optional test-mode key. When set and non-empty, it takes precedence over LEMONSQUEEZY_API_KEY (but not over LEMONSQUEEZY_API_KEY_COMMAND). On first activation per process, the server prints a one-line JSON test_mode notice to stderr so you can confirm test mode is engaged. Use this to point the server at a sandbox/test store without unsetting your production key. |
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. LemonSqueezy API keys are issued at the account level and authorize access to every store in that account, so this allowlist is the only in-process store boundary the server can enforce. Pair it with LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS / LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT / LEMONSQUEEZY_RATE_LIMIT_PER_CLASS for defense in depth, and — if your account hosts multiple stores you don't want exposed to the same agent — keep those stores under a separate LemonSqueezy account whose API key isn't reachable from this server. |
LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS |
Rejects ls_refund_order and ls_refund_subscription_invoice calls above this amount. |
LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT |
Positive integer. 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 every refund, cancellation, archive, and delete tool, plus the input-dependent destructive paths: ls_update_license_key calls that set disabled: true or change activationLimit, ls_update_subscription calls that pause or switch plan, and ls_update_customer calls with status: "archived". |
LEMONSQUEEZY_DISABLE_CLASSES |
Comma-separated list of authority classes to refuse outright. Any tool whose class is listed returns a guardrail_block before the API call is attempted. Example: LEMONSQUEEZY_DISABLE_CLASSES=money,recurring,pii lets an agent run reads but blocks refunds, subscription changes, and customer-record access. Unknown class names throw at server startup. |
LEMONSQUEEZY_RATE_LIMIT_PER_CLASS |
Per-class rolling rate limits, comma-separated. Each entry is class:N, class:N/m, or class:N/h (bare numbers default to per-minute). Example: money:2/h,recurring:5/h,key:10/m. Composes with LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT — both must pass. In-process per server instance. |
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. |
LEMONSQUEEZY_SINK_URL |
Base URL of an optional @yawlabs/lemonsqueezy-webhook-sink instance (e.g. https://webhooks.example.com). Trailing slashes are stripped. Enables the ls_sink_* reconciliation tools below. Unset: the tools are still registered but return a "not configured" error when called. |
LEMONSQUEEZY_SINK_ADMIN_TOKEN |
Bearer token for the sink's admin endpoints. Must match the sink's WEBHOOK_SINK_ADMIN_TOKEN. Required when LEMONSQUEEZY_SINK_URL is set; if the sink itself was started without an admin token, its admin endpoints return 404 and ls_sink_* calls surface that diagnostically. |
Each line: {ts, event, tool?, method?, path?, status, latency_ms, request_id?, error?, audit?, inputs?}. Stdout is reserved for the MCP protocol — never log there.
HTTP errors include the upstream X-Request-Id when present, so support tickets to LemonSqueezy can reference the exact call.
The strongest access control LemonSqueezy itself exposes is the API key boundary. A LemonSqueezy API key authorizes its full account — every store, every tool — and the only way to deny a class of authority through LemonSqueezy is to not give the API key to the agent in the first place. LemonSqueezy's team-membership UI scopes which humans can do which actions in the dashboard, but the public API key inherits the full authority of the account it was issued under; there's no "this key can read but not refund" toggle. So the authoritative boundary, as far as the upstream API is concerned, is which API key the agent has.
That means the env vars below are the primary in-process control surface for anything LemonSqueezy can't gate by itself — per-class rate ceilings (RATE_LIMIT_PER_CLASS), deploy-time class disables (DISABLE_CLASSES), refund caps (MAX_REFUND_AMOUNT_CENTS), and the audit log. They are belt-and-braces in the sense that an operator who can change the server's env can remove them; they are load-bearing in the sense that LemonSqueezy has no equivalent. If you need an agent that genuinely cannot reach a store or a class of action, the durable answer is a separate LemonSqueezy account whose key is never handed to that agent.
Every tool is tagged with an authority class — a label for the kind of business authority a caller needs to invoke it. The class is separate from the binary destructive/read-only annotation: a customer-record read and a product list are both reads, but only one returns PII; a checkout creation and a refund are both writes, but only one moves money.
| Class | What it covers | Example tools |
|---|---|---|
read |
Safe reads (list/get) that don't return customer PII as the primary payload. | ls_list_orders, ls_get_product, ls_validate_license |
pii |
Reads or writes whose primary payload is a customer record. | ls_list_customers, ls_create_customer, ls_archive_customer |
mutate |
Safe mutations: checkouts, discounts, invoice generation, usage records. | ls_create_checkout, ls_create_discount, ls_generate_order_invoice |
money |
Money movement. Irreversible at the payment layer. | ls_refund_order, ls_refund_subscription_invoice |
recurring |
Subscription state changes that affect recurring revenue. | ls_update_subscription, ls_cancel_subscription, ls_update_subscription_item |
key |
License-key admin (activate, deactivate, disable, change activation limit). | ls_update_license_key, ls_activate_license, ls_deactivate_license |
webhook |
Webhook configuration — affects the trust surface other systems rely on. | ls_create_webhook, ls_update_webhook, ls_delete_webhook |
Note: ls_get_order returns customer fields incidentally, but its primary payload is the order — it stays in read, not pii. The class is reserved for tools whose primary purpose is the customer record. If you need to deny all access to customer-shaped data, set LEMONSQUEEZY_DISABLE_CLASSES=pii and — if the agent must never under any circumstances touch that data — also issue its API key from a separate LemonSqueezy account that doesn't host customer records you care about.
The two opt-in env vars that consume this taxonomy:
LEMONSQUEEZY_RATE_LIMIT_PER_CLASS — caps the call rate per class. LemonSqueezy permissions cannot express "max 2 refunds per hour"; this is the only place that policy can live. This is the load-bearing one for runaway-agent prevention.LEMONSQUEEZY_DISABLE_CLASSES — blocks a class outright. Useful when fast deploy-time toggles matter — flipping DISABLE_CLASSES=pii,mutate,money,recurring,key,webhook to lock an analytics deployment into pure reads is a one-line config change. An operator who can change the server's env can also remove this gate, so for an authoritative deny use a separate LemonSqueezy account whose API key the agent never sees.Both are opt-in; with neither set, behavior is unchanged from prior versions.
The server exposes one MCP Resource for clients that prefer structural retrieval over parsing stderr:
| URI | MIME type | Contents |
|---|---|---|
lemonsqueezy://audit-log |
application/x-ndjson |
The most recent destructive tool calls and outcomes (rate-limit blocks, refund-cap blocks, exceptions, successes). Bounded ring buffer of the last 1000 entries, most-recent-first, resets on server restart. Redaction runs on the input payload before it reaches the buffer: any object key whose name matches a credential / PII pattern (secret, password, token, api_key, bearer, authorization, signing_secret, private_key, pin, ssn, social_security_number, credit_card, card_number, cvv, cvc — case-insensitive, whole-word) AND any string value matching the JWT bearer-token shape (eyJ…-prefixed, three base64url segments) is replaced with [REDACTED]. Ordinary identifiers (licenseKey, instanceId, storeId, orderId, webhookId) and UUID-shaped values are preserved. |
For unattended/agentic use against a live store, we recommend:
LEMONSQUEEZY_ALLOWED_STORE_IDS to the same set as a belt-and-braces in-process gate on the tools that take a storeId.LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS to a per-call cap well below any single-refund expectation.LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMIT to a small number (e.g. 5/min) as a runaway-agent circuit breaker. For finer control, add LEMONSQUEEZY_RATE_LIMIT_PER_CLASS=money:2/h,recurring:5/h,key:10/m so each authority class has its own ceiling.read), set LEMONSQUEEZY_DISABLE_CLASSES to the classes you want refused. The server rejects them before the API call is built. For an irrevocable deny, also issue the agent's API key from a separate LemonSqueezy account.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.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.What the server does not do and you must own at the caller level:
See SEMVER.md for the versioning policy.
npm install
npm run lint
npm test # full unit + handler suite
npm run test:integration # requires LEMONSQUEEZY_TEST_API_KEY + LEMONSQUEEZY_TEST_STORE_ID
Containerfile is generated from Dockerfile. After editing Dockerfile:
npm run gen:containerfile # regenerate Containerfile
npm run check:containerfile # CI runs this; non-zero exit means the two have drifted
Two paths from a clean checkout of main. Both produce the same artifact (npm publish with provenance + GitHub release).
# 1. Bump version
npm version X.Y.Z --no-git-tag-version
# 2. Commit
git add package.json && git commit -m "vX.Y.Z"
# 3. Annotated tag (lightweight tags are silently skipped by --follow-tags)
git tag -a vX.Y.Z -m "vX.Y.Z"
# 4. Push commit + tag
git push origin main --follow-tags
# 5. Confirm the Release workflow fired (not just CI on the bump commit)
gh run list --limit 2
The tag push triggers .github/workflows/release.yml, which runs release.sh in CI mode: lint, test, build, npm publish (with --provenance) using the org-level NPM_TOKEN secret, then GitHub release creation, then a smoke test against the published tarball, then a publish to the Official MCP Registry via GitHub OIDC (no MCP_* secret needed; the namespace io.github.YawLabs/* is authorized purely from the OIDC repository_owner claim). No local npm login needed.
./release.sh X.Y.Z
Does the same steps 1–7 on the workstation: lint, test, build, bump, commit, annotated tag, push, npm publish, GitHub release, verify. Idempotent — safe to re-run with the same version after a partial failure. Requires one-time setup:
npm login --auth-type=web # publisher of @yawlabs/lemonsqueezy-mcp
gh auth login # GitHub CLI for the release-creation step
The local path does not publish to the Official MCP Registry — that step lives only in CI and depends on a GitHub Actions OIDC token. To push a locally-released version to the registry, install mcp-publisher, run mcp-publisher login github (interactive OAuth), then mcp-publisher publish from the repo root.
MIT
Выполни в терминале:
claude mcp add yawlabs-lemonsqueezy-mcp -- npx Web content fetching and conversion for efficient LLM usage.
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
автор: modelcontextprotocolProvides auto-configuration for setting up an MCP server in Spring Boot applications.
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
автор: xuzexin-hzНе уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории ai