FastSpring MCP Server
Click on "Deploy 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., "@FastSpring MCP Server List recent orders and their status"
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.
FastSpring MCP Server
Production-ready Model Context Protocol (MCP) server for the FastSpring API. Exposes FastSpring orders, subscriptions, and accounts as MCP tools for use with Claude, Cursor, and any other MCP-compatible client.
Supports two transport modes:
STDIO — default; for local MCP clients (Claude Desktop, Cursor, MCP Inspector)
Streamable HTTP — for remote clients, hosted deployments, and Docker
Table of Contents
Related MCP server: Recharge Storefront API MCP Server
Stack
Concern | Choice |
Runtime | Node.js 22 (≥ 20 required) |
Language | TypeScript — strict mode |
MCP SDK |
|
HTTP transport |
|
HTTP client | Axios (Basic auth + interceptors) |
Testing | Vitest — mocked HTTP, 80 %+ coverage |
Logging | Winston — daily rotation, structured JSON |
Container | Docker / Docker Compose |
Environment Variables Reference
Required — FastSpring credentials
Variable | Description |
| FastSpring API username |
| FastSpring API password |
Credentials are created in the FastSpring dashboard: Developer Tools → APIs → Create.
Optional — FastSpring settings
Variable | Default | Description |
| — | Classic (legacy) API company ID. Required only for order-reference lookups via |
|
| Override if your account uses a company-scoped base URL. |
|
| Set to |
|
| Log verbosity: |
|
| Directory for daily log files. |
Optional — Transport & HTTP server
Variable | Default | Description |
|
| Transport mode: |
|
| Port the HTTP server listens on. |
|
| Interface to bind to ( |
|
| URL path for the MCP endpoint. |
|
|
|
Optional — HTTP authentication
Variable | Default | Description |
|
| Set to |
| — | Comma-separated list of valid API keys. Required when |
Note: Authentication only applies to the HTTP transport. The STDIO transport is secured by the OS process model and needs no auth configuration.
Sensitive Information — How to Handle Credentials
Rule: credentials (
FS_API_USERNAME,FS_API_PASSWORD,FS_COMPANY_ID) are never stored inside the container image or committed to source control. They are always injected at runtime as environment variables.
What is safe and what is not
Location | Safe? | Notes |
| ✅ | Never committed ( |
Baked into | ❌ | Would be visible in every layer of the image |
Committed to git | ❌ | Permanent, hard to rotate |
Docker image layers | ❌ |
|
Runtime environment variable ( | ✅ | The correct approach for all environments |
Local development
Use a .env file — it is loaded automatically by the server at startup (via dotenv) and by Docker Compose for variable substitution:
cp .env.example .env
# Edit .env and fill in your credentialsThe .env file is excluded from git and Docker builds:
.gitignore→ never committed.dockerignore→ never copied into the image
CI/CD and production
Do not use a .env file. Inject credentials as environment variables from your platform's secret store:
GitHub Actions
env:
FS_API_USERNAME: ${{ secrets.FS_API_USERNAME }}
FS_API_PASSWORD: ${{ secrets.FS_API_PASSWORD }}
FS_COMPANY_ID: ${{ secrets.FS_COMPANY_ID }}AWS ECS
{
"secrets": [
{ "name": "FS_API_USERNAME", "valueFrom": "arn:aws:secretsmanager:..." },
{ "name": "FS_API_PASSWORD", "valueFrom": "arn:aws:secretsmanager:..." }
]
}Kubernetes
env:
- name: FS_API_USERNAME
valueFrom:
secretKeyRef:
name: fastspring-credentials
key: usernameRender / Railway / Fly.io / Heroku — use the platform's "Environment Variables" or "Secrets" UI dashboard.
Running Locally
Prerequisites
node --version # must be ≥ 20
npm --versionInstall and build:
npm install
npm run buildConfigure credentials:
cp .env.example .env
# Edit .env — set FS_API_USERNAME and FS_API_PASSWORD at minimumSTDIO transport (default)
STDIO is the standard transport for local MCP clients. The client (Cursor, Claude Desktop, MCP Inspector) spawns the server as a child process and communicates over stdin/stdout.
npm start
# or explicitly:
npm run start:stdioThe server produces no console output on startup (MCP protocol runs over stdio — any stdout/stderr would corrupt the stream). All logs go to the logs/ directory.
Streamable HTTP transport
HTTP mode starts a local web server. Use this when you want to call the server from a script, another process, or a remote MCP client.
npm run start:httpDefault endpoint: http://localhost:3000/mcp
Custom port or path:
MCP_HTTP_PORT=8080 MCP_HTTP_PATH=/api/mcp npm run start:httpVerify it is running:
curl http://localhost:3000/health
# → {"status":"ok","transport":"streamable-http","mode":"stateful","sessions":0}Stateless mode (new server instance per request — useful for scripts or one-shot callers):
MCP_HTTP_STATELESS=true npm run start:httpTest with the MCP Inspector UI (HTTP mode):
npm run test:inspector:http
# Starts the server in HTTP mode, then opens the Inspector UI pointing at itRunning in Docker
The Docker image defaults to HTTP transport (MCP_TRANSPORT=http) and binds to 0.0.0.0 so it is reachable from outside the container. Credentials are never baked into the image — they are always passed at runtime.
Persistent container (recommended) — runs in the background and restarts automatically after a machine reboot:
npm run docker:startStop it with npm run docker:stop. Ensure .env exists with FS_API_USERNAME and FS_API_PASSWORD (see Environment variables).
Prerequisites
You need both the Docker daemon and the Compose plugin. The easiest way to get both together is Docker Desktop.
Option A — Docker Desktop (recommended for Mac/Windows)
Download and install from https://www.docker.com/products/docker-desktop/
Docker Desktop bundles the Docker daemon, the docker CLI, and the docker compose plugin (v2). After installing and starting Docker Desktop:
docker --version # Docker version 29.x or later
docker compose version # Docker Compose version v2.x or laterOption B — Docker CLI + Compose plugin via Homebrew (Mac)
If you already have the Docker CLI installed via Homebrew (brew install docker) but without Docker Desktop, install the standalone Compose plugin separately:
brew install docker-composeThen use the hyphenated docker-compose command (v1) or the :v1 npm script variants:
docker-compose --version # docker-compose version 1.x or 2.xHow to tell which you have: Run
docker compose version(with a space). If it saysunknown command, you have the CLI only and need Option A or B above.
Docker Compose (recommended)
Docker Compose reads your .env file automatically for variable substitution and passes each credential as a runtime environment variable into the container. The .env file itself is never copied into the image. The Compose file sets restart: unless-stopped, so the container survives reboots when run in detached mode.
Action | Command |
Start (persistent, restarts on reboot) |
|
Start (foreground, see logs in terminal) |
|
Stop |
|
Logs |
|
Compose v1 (Homebrew docker-compose): use npm run docker:up:v1, npm run docker:down:v1, npm run docker:logs:v1.
Verify:
curl http://localhost:3000/healthCustom port — set MCP_HTTP_PORT in your .env or shell before starting:
MCP_HTTP_PORT=8080 npm run docker:startWhat Docker Compose does with your .env:
Docker Compose reads .env from the project directory and substitutes ${VAR} placeholders in docker-compose.yml. The result is that each variable is passed to the container as a standard environment variable. The .env file stays on your machine — it is not mounted into the container, and .dockerignore prevents it from entering the build context.
Plain Docker run
Build the image once, then run with env from a file. For a persistent container (restarts on reboot), use docker:run:env which uses --restart unless-stopped and a named container (no --rm).
Build:
npm run docker:buildRun persistent (loads .env, container survives reboot; stop with docker stop fastspring-mcp):
npm run docker:run:envRun one-off (container removed when it stops; credentials from shell):
export FS_API_USERNAME=your_username FS_API_PASSWORD=your_password
docker run --rm --env-file .env -p 3000:3000 fastspring-mcpCI/CD Deployments
For CI/CD pipelines, there is no .env file. Inject all variables as secrets provided by your platform.
Generic pattern:
# 1. Build the image (no secrets needed at build time)
docker build -t fastspring-mcp .
# 2. Push to a registry
docker tag fastspring-mcp registry.example.com/fastspring-mcp:latest
docker push registry.example.com/fastspring-mcp:latest
# 3. Deploy — pass secrets as environment variables at runtime
docker run -d --restart unless-stopped --name fastspring-mcp \
-e FS_API_USERNAME="$FS_API_USERNAME" \
-e FS_API_PASSWORD="$FS_API_PASSWORD" \
-e FS_COMPANY_ID="$FS_COMPANY_ID" \
-e MCP_TRANSPORT=http \
-e MCP_HTTP_HOST=0.0.0.0 \
-e MCP_HTTP_PORT=3000 \
-p 3000:3000 \
registry.example.com/fastspring-mcp:latestThe --restart unless-stopped and --name fastspring-mcp flags make the container persistent and restart automatically after a reboot.
The server performs fail-fast validation at startup: if FS_API_USERNAME or FS_API_PASSWORD are missing, the process exits immediately with a clear error. Misconfiguration is caught at boot, not at the first API call.
Connecting MCP Clients
Cursor / Claude Desktop (STDIO)
Add to your MCP config file (e.g. ~/.cursor/mcp.json):
{
"mcpServers": {
"fastspring": {
"command": "node",
"args": ["/absolute/path/to/fs-mcp/dist/index.js"],
"env": {
"FS_API_USERNAME": "your_username",
"FS_API_PASSWORD": "your_password",
"FS_COMPANY_ID": "your_company_id"
}
}
}
}The client spawns the server as a subprocess. The env block passes credentials directly — no .env file required when using this approach.
Cursor / Claude Desktop (HTTP)
Start the server in HTTP mode first (locally or via Docker), then configure your client to connect by URL.
Claude Desktop only supports stdio transport natively. To connect it to an HTTP MCP server, use mcp-remote as a proxy bridge — npx fetches it automatically, no install required.
Without authentication (MCP_AUTH_ENABLED=false, default):
{
"mcpServers": {
"fastspring": {
"command": "npx",
"args": [
"mcp-remote",
"http://localhost:3000/mcp"
]
}
}
}With authentication (MCP_AUTH_ENABLED=true):
{
"mcpServers": {
"fastspring": {
"command": "npx",
"args": [
"mcp-remote",
"http://localhost:3000/mcp",
"--header",
"Authorization:Bearer <your-api-key>"
]
}
}
}Claude.ai (remote HTTP)
Claude.ai connects to remote MCP servers over the Streamable HTTP transport. Deploy this server (via Docker or any Node host), then add the public URL in Claude.ai's MCP server settings:
https://your-server.example.com/mcpIf authentication is enabled, include the Authorization: Bearer <key> header in your client configuration. Ensure the server is behind HTTPS (e.g. a reverse proxy such as nginx or Caddy) for production use.
Generating API keys
Use Node.js to generate a cryptographically secure random key:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Add one or more keys to your .env:
MCP_AUTH_ENABLED=true
MCP_API_KEYS=a3f8c2...,b7d1e9...The server accepts any key in the list, so different clients can use different keys and be revoked independently by removing their key and restarting.
Testing & Inspection
Unit tests
Run the full test suite with coverage (thresholds: 80 % lines/statements/functions, 75 % branches). All HTTP calls are mocked — no real FastSpring API calls are made.
npm testWatch mode:
npm run test:watchType-check only (no emit):
npm run typecheckSmoke test (no browser)
Spawns the server, sends MCP initialize and tools/list over STDIO, and prints the JSON responses. Useful for verifying the server starts correctly without a browser or UI:
npm run test:smokeSave output for sharing or debugging:
npm run test:smoke > logs/smoke.txt 2>&1MCP Inspector — STDIO mode
The MCP Inspector provides a browser UI to list and invoke tools. In STDIO mode it spawns the server as a child process:
npm run test:inspector
# Opens Inspector UI at http://localhost:6274Pass credentials if you are not using a .env file:
FS_API_USERNAME=xxx FS_API_PASSWORD=yyy npm run test:inspectorMCP Inspector — HTTP mode
In HTTP mode the Inspector connects to an already-running server by URL. This command starts the server in HTTP mode in the background, waits for it to be ready, then opens the Inspector:
npm run test:inspector:http
# Opens Inspector UI connected to http://localhost:3000/mcpCustom port:
MCP_HTTP_PORT=8080 npm run test:inspector:httpIntegration test (real API)
Calls the real FastSpring API with your credentials. Requires a valid .env with credentials and optionally TEST_CUSTOMER_EMAIL:
npm run test:integrationTools Reference
All tools return JSON. Errors include an error field, and when available statusCode and responseBody from FastSpring. All string inputs are trimmed before calling the API.
Orders
Tool | Description | Inputs |
| Fetch a single order by internal FastSpring order ID. |
|
| List all orders for a customer by email. |
|
| Look up orders by reference (e.g. |
|
| Fetch full order detail by reference via the Classic API. |
|
Subscriptions
Tool | Description | Inputs |
| Fetch a subscription by internal subscription ID. |
|
| Look up a subscription by reference. |
|
| List subscriptions with optional filters. |
|
| Get line items for a subscription. |
|
Accounts
Tool | Description | Inputs |
| Fetch a customer account by ID. |
|
| Look up an account by customer email. |
|
| Get all orders for an account. |
|
ID vs reference — avoiding 400 errors
get_orderandget_subscriptionuse FastSpring's internal ID in the URL path. Passing a human-readable reference (e.g.VI8201014-6538-11102S) will return 400 Bad Request.Use
find_orders_by_referenceorget_subscription_by_referencewhen you have a reference string.Internal IDs are available in the FastSpring dashboard or from list tools (
find_orders_by_email,list_subscriptions, etc.) which return objects containing bothidandreference.If you get 400 on valid-looking IDs, your account may use a company-scoped base URL. Set
FS_BASE_URL=https://api.fastspring.com/company/yourcompanyin.env.
Logging
Daily rotation: one file per day under
FS_LOG_DIR(defaultlogs/), e.g.logs/fastspring-mcp-2026-02-19.log. Files are retained for 14 days.Levels:
fatalerrorwarninfodebug— set viaFS_LOG_LEVEL.DEBUG level: logs every FastSpring API request (method, URL) and response (status, body). Enable with
FS_DEBUG=trueorFS_LOG_LEVEL=debug.Format: pretty-printed lines with timestamp, level, message, and JSON metadata. Credentials are never logged.
Docker: the
logs/directory is mounted as a volume (./logs:/app/logs) so logs persist across container restarts.
Scripts Reference
Development
Script | Description |
| Compile TypeScript → |
| Start server in STDIO mode (default) |
| Start server explicitly in STDIO mode |
| Start server in Streamable HTTP mode (port 3000) |
| Type-check without emitting |
| ESLint on |
Testing
Script | Description |
| Vitest unit tests with coverage |
| Vitest in watch mode |
| Smoke test over STDIO — no browser required |
| Integration test against real FastSpring API |
| MCP Inspector UI — STDIO mode |
| MCP Inspector UI — HTTP mode (starts server + opens Inspector) |
Docker
Script | Description |
| Start persistent container (detached; restarts on reboot) — recommended |
| Stop and remove containers (Compose) |
| Build the Docker image only |
| Same as |
| Start in foreground (logs in terminal; Ctrl+C stops container) |
| Same as |
| Tail container logs (Compose v2) |
| Plain |
| Compose v1 (docker-compose) |
License
This project is dual-licensed.
AGPL v3 — Default. You may use, modify, and distribute the software under the terms of the GNU Affero General Public License v3. If you run a modified version as a service over a network, you must make the corresponding source available to users of that service.
Commercial — Use in proprietary products or services without AGPL’s source-availability obligations requires a separate commercial license. See COMMERCIAL_LICENSE.md for details.
Commercial licensing enquiries: help@gotmo.co.uk
Available Tools
11 toolscreate_quoteA
Use this tool to create a new quote (formal order document) for one or more FastSpring subscription or product SKUs on behalf of a buyer.
A quote is the correct way to programmatically generate a Custom Order in FastSpring — it is NOT a checkout session and does NOT charge the buyer.
On success the tool returns a quoteUrl — a permanent payment link you can send to the buyer. The buyer opens the link, sees a full B2B quote document with line items, VAT/tax breakdown, and pricing, then pays on the FastSpring storefront at their convenience. The quote appears immediately in the FastSpring dashboard under Quotes and remains open until paid, cancelled, or expired (default 30 days, maximum 90 days).
Required inputs: quote name, at least one product SKU, buyer first name, last name, email, and billing country (2-letter ISO code).
Optional: quantity and price overrides per item, coupon code, currency, expiration days (1–90), fulfilment term, notes, net-terms days, tags (array of {key, value} objects), and buyer VAT/tax ID.
Inputs: name (required), items (required), recipient (required), recipientAddress (required), +8 more.
get_accountA
Fetch a FastSpring customer account by its account ID. Returns the account details including email, name, company, and billing address.
Inputs: accountId (required).
get_account_by_emailA
Look up a FastSpring customer account by email address. Returns the account details if found.
Inputs: email (required).
get_account_ordersA
Get all orders placed by a FastSpring customer account. Pass the account ID to retrieve the full order history for that account.
Inputs: accountId (required).
get_orderA
Fetch a FastSpring order by its ID or reference number (e.g. VI0000000-0000-00000). Accepts any identifier — the system checks both the current and legacy FastSpring platforms automatically. The response includes a 'platform' field ('modern' or 'legacy') telling you which platform holds the record, and a 'data' field with the full order details. Modern platform orders include: id, reference, status, customer, line items, total, and currency. Legacy platform orders include: reference, status, customer, billing address, line items (each with a subscriptionReference if the line item created a subscription), payments, total, tax, shipping, and referrer.
Inputs: reference (required).
get_subscriptionA
Fetch a FastSpring subscription by its ID or reference number (e.g. VI8201014-6538-11102S). Accepts any identifier — the system checks both the current and legacy FastSpring platforms automatically. The response includes a 'platform' field ('modern' or 'legacy') that tells you which platform holds the record, and a 'data' field with the subscription details. Modern platform subscriptions include: id, status, product, customer, start/end dates, next charge date, and line items. Legacy platform subscriptions include: reference, status, customer, product name, quantity, next renewal date, and end date.
Inputs: reference (required).
get_subscription_line_itemsA
Get the products and quantities on a subscription. Requires the subscription's internal FastSpring ID — the 'id' field from get_subscription results. Returns the list of products, quantities, and SKUs currently on the subscription.
Inputs: subscriptionId (required).
list_orders_by_emailA
List all orders for a customer by their email address. Returns an array of order objects from the current FastSpring platform. Use get_order to fetch the full detail of any individual order.
Inputs: email (required).
list_subscriptionsA
Search for FastSpring subscriptions on the current platform. Optionally filter by status (e.g. active, deactivated), product name, or customer email. Returns a list of matching subscriptions. Use get_subscription to fetch the full details of a specific subscription.
Inputs: email (required), status, product.
update_order_tagsA
Add or replace tags and/or per-product attributes on a FastSpring order. Requires the order's internal FastSpring ID (the 'id' field returned by get_order). Provide 'tags' to set order-level key-value metadata — these REPLACE the full existing tag set. Provide 'items' to set attributes on specific product line items within the order — each entry must include the product path and an attributes map, which also REPLACE the existing attributes for that product. Both 'tags' and 'items' are optional; include whichever you need to update. Active subscriptions created from this order automatically inherit the updated attributes. API: POST /orders
Inputs: orderId (required), tags, items.
update_subscription_tagsA
Add or replace tags on a FastSpring subscription. Requires the subscription's internal FastSpring SBL ID (the 'id' field returned by get_subscription). Provide a 'tags' map of string key-value pairs — these REPLACE the full existing tag set on the subscription. To remove all tags pass an empty object. API: POST /subscriptions/{subscriptionId}
Inputs: tags (required), subscriptionId (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Each tool targets a distinct resource and action. While get_account and get_account_by_email both fetch accounts, they are clearly differentiated by identifier type. The descriptions are explicit about what each tool does.
All tool names follow a consistent verb_noun pattern (get_, list_, update_, create_). The naming clearly distinguishes single-item retrieval from list operations, and actions are aligned with resource types.
With 11 tools covering orders, subscriptions, accounts, and quotes, the server is well-scoped for a commerce platform. Each tool has a clear purpose and the set is neither sparse nor bloated.
The tool set covers core read operations for orders, subscriptions, and accounts, plus subscription line items and quote creation. Minor gaps exist (e.g., subscription cancellation, quote management, order updates beyond tags), but agents can work around these for most workflows.
Maintenance
Related MCP Connectors
Monetize and manage your Tip4Serv store directly from your LLM.
Merchant of record: payment links, checkouts, subscriptions and invoices, with VAT handled.
Model Context Protocol server for the Apideck Unified API. Connect any MCP-compatible agent framework to 100+ accounting systems, HRIS platforms, file storage providers, and more through one integration. More information https://www.apideck.com/mcp-server
Spacebring MCP server. Look up members, bookings, invoices, subscriptions, events and more, and take everyday actions such as creating events or replying to support tickets, from MCP-compatible AI assistants that support remote servers with OAuth.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with the Hostinger Ecommerce API to retrieve product information and update product descriptions through the Model Context Protocol.ISC
- AlicenseNot gradedqualityDmaintenanceA comprehensive Model Context Protocol (MCP) server that provides complete access to the Recharge Storefront API endpoints. Enables AI assistants to manage subscriptions, customers, orders, and billing through a standardized interface.2MIT
- AlicenseAqualityCmaintenanceEnables AI agents to manage crypto payments, stores, products, and orders through the Model Context Protocol.2074 npmMIT
- AlicenseBqualityDmaintenanceEnables natural language control of Teamleader Focus CRM, invoicing, and project management through the Model Context Protocol.4217 npmMIT