@yawlabs/lemonsqueezy-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@yawlabs/lemonsqueezy-mcpHow many active subscriptions do I have?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@yawlabs/lemonsqueezy-mcp
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 mcp.hosting account so it syncs to every MCP client you use. Or install manually below.
Quick start
npx -y @yawlabs/lemonsqueezy-mcp@latestOr one-click install via Smithery:
npx -y @smithery/cli install @yawlabs/lemonsqueezy-mcp --client claudeSmithery prompts for your env vars (API key, optional guardrails) and writes the config into your client for you.
What it looks like
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.
Setup
Set your LemonSqueezy API key as an environment variable:
export LEMONSQUEEZY_API_KEY="your-api-key"Get your API key from your LemonSqueezy dashboard.
Docker
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-mcpA 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.
Claude Code
Add to your MCP config:
{
"mcpServers": {
"lemonsqueezy": {
"command": "npx",
"args": ["-y", "@yawlabs/lemonsqueezy-mcp@latest"],
"env": {
"LEMONSQUEEZY_API_KEY": "your-api-key"
}
}
}
}Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"lemonsqueezy": {
"command": "npx",
"args": ["-y", "@yawlabs/lemonsqueezy-mcp@latest"],
"env": {
"LEMONSQUEEZY_API_KEY": "your-api-key"
}
}
}
}Tools (64)
Users
ls_get_user— Get the authenticated user
Stores
ls_get_store— Get a store by IDls_list_stores— List all stores
Customers
ls_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 customer
Products
ls_get_product— Get a product by IDls_list_products— List products (filter by store)
Variants
ls_get_variant— Get a variant by IDls_list_variants— List variants (filter by product)
Prices
ls_get_price— Get a price by IDls_list_prices— List prices (filter by variant)
Files
ls_get_file— Get a file by IDls_list_files— List files (filter by variant)
Orders
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 refund
Order Items
ls_get_order_item— Get an order item by IDls_list_order_items— List order items (filter by order, product, variant)
Subscriptions
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 subscription
Subscription Invoices
ls_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 refund
Subscription Items
ls_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 usage
Usage Records
ls_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)
Discounts
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 discount
Discount Redemptions
ls_get_discount_redemption— Get a discount redemption by IDls_list_discount_redemptions— List redemptions (filter by discount, order)
License Keys
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 status
License Key Instances
ls_get_license_key_instance— Get a license key activation by IDls_list_license_key_instances— List activations (filter by license key)
Checkouts
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)
Webhooks
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 webhook
License API
ls_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)
Webhook sink (optional)
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 bysince/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 timestamp
Features
Full API coverage — All 17 LemonSqueezy API resources with 61 tools, plus 3 bridge tools to an optional @yawlabs/lemonsqueezy-webhook-sink for webhook reconciliation
JSON:API support — Filtering, pagination, and relationship inclusion on all list/get operations
Zero runtime dependencies — Single bundled file for instant
npxstartupLicense API — Activate, validate, and deactivate license keys without an API key
MCP annotations — Every tool declares read-only, destructive, and idempotent hints
Retry with backoff — 429 and 5xx retries (idempotent methods only) with exponential backoff, jitter, and a 90s overall-deadline ceiling
Guardrails — opt-in store allowlist, refund cap, destructive-call rate limit, authority-class disable (
LEMONSQUEEZY_DISABLE_CLASSES), and per-authority-class rate limits (LEMONSQUEEZY_RATE_LIMIT_PER_CLASS)Audit log MCP Resource —
lemonsqueezy://audit-logexposes the last 1000 destructive-call entries asapplication/x-ndjsonfor clients without stderr accessStructured logging — opt-in JSON logs to stderr with selectable levels (
error,audit,all)
Configuration
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 token. |
| Command whose stdout produces the API key. Overrides |
| Optional test-mode key. When set and non-empty, it takes precedence over |
| Comma-separated allowlist of store IDs. When set: (1) any tool whose input includes a |
| Rejects |
| Positive integer. Max destructive tool calls per 60-second rolling window. In-process limit — per MCP server instance, not global; each |
| Comma-separated list of authority classes to refuse outright. Any tool whose class is listed returns a |
| Per-class rolling rate limits, comma-separated. Each entry is |
| Structured-log verbosity to stderr. Set to |
| Base URL of an optional @yawlabs/lemonsqueezy-webhook-sink instance (e.g. |
| Bearer token for the sink's admin endpoints. Must match the sink's |
Logging format
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.
Error decoration
HTTP errors include the upstream X-Request-Id when present, so support tickets to LemonSqueezy can reference the exact call.
Authority classes
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 |
| Safe reads (list/get) that don't return customer PII as the primary payload. |
|
| Reads or writes whose primary payload is a customer record. |
|
| Safe mutations: checkouts, discounts, invoice generation, usage records. |
|
| Money movement. Irreversible at the payment layer. |
|
| Subscription state changes that affect recurring revenue. |
|
| License-key admin (activate, deactivate, disable, change activation limit). |
|
| Webhook configuration — affects the trust surface other systems rely on. |
|
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 — flippingDISABLE_CLASSES=pii,mutate,money,recurring,key,webhookto 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.
Resources
The server exposes one MCP Resource for clients that prefer structural retrieval over parsing stderr:
URI | MIME type | Contents |
|
| 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 ( |
Operating the server unattended
For unattended/agentic use against a live store, we recommend:
Issue an API key under a LemonSqueezy account that hosts only the store(s) the agent is allowed to touch — LemonSqueezy doesn't expose per-store API-key scoping, so account separation is the durable store boundary. Set
LEMONSQUEEZY_ALLOWED_STORE_IDSto the same set as a belt-and-braces in-process gate on the tools that take astoreId.Set
LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTSto a per-call cap well below any single-refund expectation.Set
LEMONSQUEEZY_DESTRUCTIVE_RATE_LIMITto a small number (e.g. 5/min) as a runaway-agent circuit breaker. For finer control, addLEMONSQUEEZY_RATE_LIMIT_PER_CLASS=money:2/h,recurring:5/h,key:10/mso each authority class has its own ceiling.If a class shouldn't be reachable at all (e.g. an analytics agent that needs only
read), setLEMONSQUEEZY_DISABLE_CLASSESto 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.Set
LEMONSQUEEZY_LOG=auditand ship stderr to your log aggregator. Theauditlevel keeps every destructive-call entry plus errors but drops successful reads so log volume stays bounded over weeks of operation. Alert onstatus: "guardrail_block"or elevated error rates per tool. UseLEMONSQUEEZY_LOG=allwhile debugging.Run
LEMONSQUEEZY_API_KEY_COMMANDagainst 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:
Idempotency / dedupe store — MCP servers are stateless subprocesses; cross-invocation dedupe belongs in your agent or orchestrator.
Webhook reconciliation — subscribe to LemonSqueezy webhooks in a separate long-running process to reconcile state when API writes succeed but the response is lost. See @yawlabs/lemonsqueezy-webhook-sink for a ready-made sink.
Metrics / dashboards — the server emits structured logs; derive metrics in your log pipeline.
See SEMVER.md for the versioning policy.
Development
npm install
npm run lint
npm test # full unit + handler suite
npm run test:integration # requires LEMONSQUEEZY_TEST_API_KEY + LEMONSQUEEZY_TEST_STORE_IDContainerfile 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 driftedReleasing
Two paths from a clean checkout of main. Both produce the same artifact (npm publish with provenance + GitHub release).
1. Tag-and-let-CI (preferred)
# 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 2The 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.
2. Local end-to-end
./release.sh X.Y.ZDoes 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 stepThe 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.
License
MIT
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/YawLabs/lemonsqueezy-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server