@yawlabs/lemonsqueezy-mcp is an MCP server for the LemonSqueezy API. Manage your store, products, customers, subscriptions, discounts, license keys and more from any MCP-compatible AI assistant. It ships as a single bundled file with zero runtime dependencies for instant npx startup. From Yaw Labs, MIT licensed, published on npm.

npx -y @yawlabs/lemonsqueezy-mcp@latest

GitHub · npm · Add to Yaw MCP

Who it is for

Anyone running a store on LemonSqueezy who would rather ask a question than click through the dashboard or hand-roll a script against the API. Once it is configured, store questions get answered in plain English and routed through the tools:

Install

1. Set your API key. Create one in your LemonSqueezy dashboard under Settings > API:

export LEMONSQUEEZY_API_KEY="your-api-key"

If you would rather the key never sit in a config file or an environment variable at all, set LEMONSQUEEZY_API_KEY_COMMAND instead - the server runs that command and uses its stdout, so you can pull a short-lived credential from a vault. See Safety and control for how the cache and rotation behave.

2. Add the server to your client. In Claude Code, your MCP config:

{ "mcpServers": { "lemonsqueezy": { "command": "npx", "args": ["-y", "@yawlabs/lemonsqueezy-mcp@latest"], "env": { "LEMONSQUEEZY_API_KEY": "your-api-key" } } } }

Claude Desktop takes the same block in claude_desktop_config.json. If your shell profile already exports the key, you can drop the env object entirely rather than duplicating the credential into a file your editor may sync.

3. Restart and approve. Restart Claude Code (or your MCP client) and approve the LemonSqueezy server when prompted. Then ask it something: "List the subscriptions that churned on this store last month."

Running Yaw MCP? One click adds it to your local config, and it is then available in every Yaw Terminal session.

What it covers

Full coverage of the LemonSqueezy API resources, with JSON:API filtering, pagination and relationship inclusion on the list and get operations:

AreaWhat it covers
Stores and usersThe authenticated user, get a store, list stores
CustomersGet, list by store or email, create, update, archive
CatalogProducts, variants, prices and files - get and list, filtered by their parent
OrdersGet, list by store or email, order items, generate a PDF invoice, issue a refund
SubscriptionsGet, list by store, status or product, update (plan switch, pause, billing anchor, trial), cancel
Subscription invoices and itemsGet and list invoices, generate a PDF, refund an invoice; update item quantity and read current billing-period usage
Usage recordsGet, list by subscription item, and report metered usage as an increment or an absolute set
DiscountsGet, list, create and delete discount codes, plus redemptions by discount or order
License keysGet and list keys, update the activation limit, expiry or disabled status, and list activations for a key
CheckoutsGet, list, and create a checkout URL with custom pricing, prefill and discounts
WebhooksGet, list, create, update and delete
License APIActivate, validate and deactivate a license key - these need no API key at all
Webhook sink (optional)Bridge to a separate webhook-sink process so the agent can reconcile against webhooks that actually fired: list received events, mark one processed, read totals and the last-received timestamp

The sink tools are always registered. If the sink URL and admin token are not set they return a clear "not configured" error rather than vanishing from the tool list, so a model can tell the difference between a capability that does not exist and one that is not wired up yet.

One MCP resource is exposed for clients that prefer structural retrieval over parsing stderr: lemonsqueezy://audit-log serves the most recent destructive tool calls and their outcomes as application/x-ndjson, most-recent-first. It is a bounded ring buffer that resets on server restart - a live tail, not a durable audit store.

Safety and control

Start with the caveat the README leads with, because it decides how much the rest is worth: the strongest access control LemonSqueezy itself exposes is the API key boundary. A LemonSqueezy API key is issued at the account level and authorizes that whole account - every store, every action. There is no "this key can read but not refund" toggle. So the durable boundary is which key the agent holds; everything below is an in-process control surface for what LemonSqueezy cannot gate itself, and an operator who can change the server's environment can also remove it.

With that understood, the guardrails are all opt-in and compose:

What the server deliberately does not do, and you own at the caller level: cross-invocation idempotency and dedupe (MCP servers are stateless subprocesses, so that belongs in your agent or orchestrator), webhook reconciliation (run a long-running sink and bridge to it), and metrics (derive them from the structured logs in your pipeline).

Other ways to run it

Docker or Podman. A multi-stage Dockerfile lives at the repo root. The runtime image is a single bundled file on Alpine running as a non-root user, with no port exposed - it speaks stdio:

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 the Dockerfile rather than maintained by hand, and CI fails review if the two have drifted.

Smithery. npx -y @smithery/cli install @yawlabs/lemonsqueezy-mcp --client claude prompts for your environment variables - the API key and any guardrails - and writes the config into your client for you.

oam.js. The server runs unmodified on oam, and LEMONSQUEEZY_MCP_SANDBOX=1 runs it under oam's permission model: network restricted to the LemonSqueezy API host, filesystem denied outright, child processes denied unless the API-key command is configured. Node stays the default deliberately - a client cold-starts this server once per session, and Node won that startup measurement on the hardware it was tested on. The sandbox is opt-in for a reason worth carrying: a wrong grant does not fail loudly, because oam denies a non-granted environment variable by making it absent rather than throwing, so an under-granted API key reads as "unauthenticated" rather than "denied".

Frequently asked questions

What does the LemonSqueezy MCP server do?

It puts the LemonSqueezy API behind MCP tools, so you can ask store-management questions in plain English and have the agent act on the answer in the same turn. Stores, products, variants, prices, files, customers, orders, subscriptions and their invoices and items, usage records, discounts, license keys and activations, checkouts and webhooks are all covered, with JSON:API filtering, pagination and relationship inclusion on the list and get operations.

How do I authenticate it, and can I keep the key out of my config file?

Set LEMONSQUEEZY_API_KEY from your LemonSqueezy dashboard. To avoid writing the key anywhere, set LEMONSQUEEZY_API_KEY_COMMAND instead: the server runs that command and uses its stdout, so you can pull a short-lived credential from a vault. The result is cached for an hour, keyed by the command string, and invalidated automatically on a 401 or 403 from the API, so a key rotated upstream takes effect on the next call rather than waiting out the cache.

Can I stop an agent issuing refunds or cancelling subscriptions?

Yes, with opt-in guardrails. Every tool carries an authority class - read, pii, mutate, money, recurring, key, webhook - and LEMONSQUEEZY_DISABLE_CLASSES refuses a whole class before the API call is built. LEMONSQUEEZY_RATE_LIMIT_PER_CLASS caps how often each class can be called, LEMONSQUEEZY_MAX_REFUND_AMOUNT_CENTS rejects refunds above a ceiling, and a value of zero on either the refund cap or the destructive rate limit blocks those calls entirely as a kill switch.

Does the store allowlist fully isolate one store from the agent?

No, and the README is direct about it. LemonSqueezy issues API keys at the account level, and a key authorizes every store in that account, so LEMONSQUEEZY_ALLOWED_STORE_IDS is an in-process gate rather than a real boundary. It blocks calls to a non-allowed store on tools that take a store ID, but tools with no store ID field are not gated, and list stores and list affiliates return rows from every store the key can see. An operator who can change the server environment can also remove the gate. For a durable boundary, issue the agent's key from a separate LemonSqueezy account.

What should I turn on before running it unattended?

Issue the key under an account hosting only the stores the agent may touch, then set the store allowlist to match. Add a per-call refund cap well below any plausible single refund, a small destructive rate limit as a runaway circuit breaker, and per-class limits for money, recurring and key. Set LEMONSQUEEZY_LOG to audit and ship stderr to your log aggregator, alerting on guardrail blocks. Note the rate limits are per server instance, so each cold start resets the window.

Related MCP servers

Further reading

Published by Yaw Labs.