Skip to main content
Glama
heysash

lemonsqueezy-mcp

by heysash
README.md
# lemonsqueezy-mcp

![Lemon Squeezy MCP — a Model Context Protocol server for Lemon Squeezy](https://raw.githubusercontent.com/heysash/lemonsqueezy-mcp/main/assets/cover.png)

[![CI](https://github.com/heysash/lemonsqueezy-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/heysash/lemonsqueezy-mcp/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/@heysash/lemonsqueezy-mcp)](https://www.npmjs.com/package/@heysash/lemonsqueezy-mcp)
[![license: MIT](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
[![node >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](./package.json)

> A [Model Context Protocol](https://modelcontextprotocol.io) server for
> **Lemon Squeezy** — 44 audited tools over the official SDK, security-first.
> Works with **any** Lemon Squeezy account.

An independent, unofficial integration — not affiliated with or endorsed by
Lemon Squeezy.

## What this is

An MCP server that lets Claude (Claude Code, Cowork, Claude Desktop) — or any
MCP-capable client — talk to your Lemon Squeezy account in plain language. Every
tool is a thin, audited wrapper around the official `@lemonsqueezy/lemonsqueezy.js`
SDK. The server runs locally over stdio; your API key never leaves your machine.

## Features

**44 MCP tools** cover the full Lemon Squeezy API surface:

| Category | Read | Mutating | Total |
|----------|-----:|---------:|------:|
| Meta | 1 | 0 | 1 |
| Stores | 2 | 0 | 2 |
| Products / Variants / Prices | 6 | 0 | 6 |
| Subscriptions | 2 | 4 | 6 |
| Customers | 2 | 3 | 5 |
| Orders | 3 | 1 | 4 |
| Discounts | 3 | 2 | 5 |
| License Keys | 4 | 3 | 7 |
| Checkouts | 2 | 1 | 3 |
| Webhooks | 2 | 3 | 5 |
| **Total** | **27** | **17** | **44** |

Plus a **security model built in** (key never leaked, redacted audit log, store
allowlist, read-only mode, `test_mode` signalling — see [below](#security-model))
and **two workflow skills** (`skills/`) that chain the tools into reproducible
tasks: [`lemonsqueezy-tier-setup`](skills/lemonsqueezy-tier-setup) and
[`lemonsqueezy-webhook-test`](skills/lemonsqueezy-webhook-test).

## Install

**Via `npx` (no install — recommended for MCP clients):** see
[Connect your MCP client](#connect-your-mcp-client) below; `npx` fetches the
package on first run.

**Global:**

```bash
npm install -g @heysash/lemonsqueezy-mcp
lemonsqueezy-mcp   # starts a stdio server (expects LEMONSQUEEZY_API_KEY in env)
```

**From source:**

```bash
git clone https://github.com/heysash/lemonsqueezy-mcp.git
cd lemonsqueezy-mcp
npm install
npm run build
```

Requires Node.js ≥ 18.

## Configure

Set your Lemon Squeezy API key. Get one from
[app.lemonsqueezy.com/settings/api](https://app.lemonsqueezy.com/settings/api).

```bash
LEMONSQUEEZY_API_KEY=<your Lemon Squeezy API key>
```

Optional:

| Variable | Effect |
|----------|--------|
| `LEMONSQUEEZY_ALLOWED_STORE_IDS=12345,67890` | Reject destructive tool calls that target any other store. Strongly recommended when you have a test + production store. |
| `LEMONSQUEEZY_AUDIT_LOG_FILE=./audit-logs/lemonsqueezy-mcp.jsonl` | Append every destructive call to a JSONL file. Stderr logging is always on. |
| `LEMONSQUEEZY_READ_ONLY=true` | Disable all destructive tools (create/update/delete/cancel/pause/resume/refund). Useful for audit sessions. |

## Connect your MCP client

Add the server to your MCP configuration — e.g. `~/.claude.json`, an `.mcp.json`
in your repo, or Claude Desktop's config:

```json
{
  "mcpServers": {
    "lemonsqueezy-mcp": {
      "command": "npx",
      "args": ["-y", "@heysash/lemonsqueezy-mcp"],
      "env": {
        "LEMONSQUEEZY_API_KEY": "your-key-here"
      }
    }
  }
}
```

To run a locally built copy instead of `npx`, use
`"command": "node", "args": ["/absolute/path/to/lemonsqueezy-mcp/dist/index.js"]`
(see [`examples/claude-code-mcp-config.json`](examples/claude-code-mcp-config.json)).

Restart the client and verify with `lemonsqueezy_whoami` from a chat — it reports
the authenticated account and whether the key is a **test** or **live** key.

## Tool catalogue

| Tool | What it does | Destructive |
|------|--------------|:-----------:|
| `lemonsqueezy_whoami` | Verify the API key; surfaces `test_mode` | — |
| `lemonsqueezy_list_stores` / `lemonsqueezy_get_store` | Stores | — |
| `lemonsqueezy_list_products` / `lemonsqueezy_get_product` | Products | — |
| `lemonsqueezy_list_variants` / `lemonsqueezy_get_variant` | Variants (pricing tiers) | — |
| `lemonsqueezy_list_prices` / `lemonsqueezy_get_price` | Prices | — |
| `lemonsqueezy_list_subscriptions` / `lemonsqueezy_get_subscription` | Subscriptions | — |
| `lemonsqueezy_update_subscription` | Change variant, billing anchor, proration | ✓ |
| `lemonsqueezy_cancel_subscription` | Cancel at period end | ✓ |
| `lemonsqueezy_pause_subscription` / `lemonsqueezy_resume_subscription` | Pause / resume | ✓ |
| `lemonsqueezy_list_customers` / `lemonsqueezy_get_customer` | Customers | — |
| `lemonsqueezy_create_customer` / `lemonsqueezy_update_customer` / `lemonsqueezy_archive_customer` | CRUD | ✓ |
| `lemonsqueezy_list_orders` / `lemonsqueezy_get_order` / `lemonsqueezy_list_order_items` | Orders | — |
| `lemonsqueezy_refund_order` | Issue refund | ✓ |
| `lemonsqueezy_list_discounts` / `lemonsqueezy_get_discount` / `lemonsqueezy_list_discount_redemptions` | Discounts | — |
| `lemonsqueezy_create_discount` / `lemonsqueezy_delete_discount` | Create / delete discount codes | ✓ |
| `lemonsqueezy_list_license_keys` / `lemonsqueezy_get_license_key` / `lemonsqueezy_list_license_key_instances` / `lemonsqueezy_validate_license` | License keys | — |
| `lemonsqueezy_update_license_key` / `lemonsqueezy_activate_license` / `lemonsqueezy_deactivate_license` | Mutating | ✓ |
| `lemonsqueezy_list_checkouts` / `lemonsqueezy_get_checkout` | Checkouts | — |
| `lemonsqueezy_create_checkout` | Create a one-off checkout URL | ✓ |
| `lemonsqueezy_list_webhooks` / `lemonsqueezy_get_webhook` | Webhooks | — |
| `lemonsqueezy_create_webhook` / `lemonsqueezy_update_webhook` / `lemonsqueezy_delete_webhook` | Mutating | ✓ |

> **API constraint:** Lemon Squeezy does NOT allow creating products or variants
> via the REST API — they must be created in the dashboard. The
> `lemonsqueezy-tier-setup` skill wires dashboard-created products into your config
> rather than creating them from scratch.

## Skills

Optional Claude skills (plain markdown under [`skills/`](skills/)) that turn the
tools into reproducible workflows. Copy them into your skill registry
(`cp -r skills/lemonsqueezy-* ~/.claude/skills/`):

- **[`lemonsqueezy-tier-setup`](skills/lemonsqueezy-tier-setup)** — discover a
  store's subscription tiers and emit `.env` lines + a summary table.
- **[`lemonsqueezy-webhook-test`](skills/lemonsqueezy-webhook-test)** — send
  signature-valid synthetic webhook payloads to your handler and check the
  responses. (Lemon Squeezy has no official test-webhook API — this fills the gap.)

## Security model

Payment tooling handles a live API key, so security is a first-class design goal,
not an afterthought:

- The API key is read **only** from `LEMONSQUEEZY_API_KEY` and never appears in
  tool responses, error messages or audit logs.
- **Audit log** entries automatically redact any field whose key matches `apiKey`,
  `api_key`, `authorization`, `token`, `secret`, `password`, `lemonsqueezy_api_key`.
- Destructive tools carry the MCP `destructiveHint: true` annotation so the client
  can ask for confirmation before mutating anything.
- **Store allowlist is enforced:** with `LEMONSQUEEZY_ALLOWED_STORE_IDS` set, any
  destructive tool that targets a store outside the list is rejected and audited as
  `denied`.
- `LEMONSQUEEZY_READ_ONLY=true` disables every destructive tool — recommended for
  shared MCP sessions.
- `lemonsqueezy_whoami` surfaces the response-level `test_mode` flag, so a caller
  can confirm a key operates on **test data before any write**.

## Develop

```bash
npm run dev          # tsx-watch the server (stdio)
npm run test         # vitest unit + protocol-level integration
npm run coverage     # vitest run --coverage (v8), enforced ≥ 90% lines/statements
npm run lint         # eslint (flat config)
npm run smoke        # API-free end-to-end smoke test against the compiled binary
npm run typecheck    # tsc --noEmit
```

For a real-API check against **your own Test-Mode account**,
[`scripts/live-verify.mjs`](scripts/live-verify.mjs) drives the compiled server
over stdio through a plan of tool calls. Launch it with the key injected by your
secret manager — **never persist or echo the key**, e.g.
`op run --env-file=<template> -- node scripts/live-verify.mjs <plan.json> [out.json]`.

See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full workflow.

## Works with

Any Lemon Squeezy account, and any framework or language — the server speaks the
MCP protocol over stdio. It pairs naturally with SaaS apps that bind checkouts to
their own users via Lemon Squeezy `custom_data`.

## Maintainer

Built and maintained by [heysash Studio](https://heysash.com) (Sascha Rahn).

## License

MIT © heysash Studio (Sascha Rahn) — see [LICENSE](./LICENSE) and [NOTICE](./NOTICE).