FastSpring MCP Server

FastSpring MCP Server

Enables interaction with FastSpring e-commerce platform for managing orders, subscriptions, and accounts through natural language using the Model Context Protocol.

Category
Visit Server

README

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

  1. Stack
  2. Environment Variables Reference
  3. Sensitive Information — How to Handle Credentials
  4. Running Locally
  5. Running in Docker
  6. CI/CD Deployments
  7. Connecting MCP Clients
  8. Testing & Inspection
  9. Tools Reference
  10. Logging
  11. Scripts Reference

Stack

Concern Choice
Runtime Node.js 22 (≥ 20 required)
Language TypeScript — strict mode
MCP SDK @modelcontextprotocol/sdk v1.26+
HTTP transport StreamableHTTPServerTransport (MCP spec)
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
FS_API_USERNAME FastSpring API username
FS_API_PASSWORD FastSpring API password

Credentials are created in the FastSpring dashboard: Developer Tools → APIs → Create.

Optional — FastSpring settings

Variable Default Description
FS_COMPANY_ID Classic (legacy) API company ID. Required only for order-reference lookups via find_orders_by_reference / get_order_by_reference.
FS_BASE_URL https://api.fastspring.com Override if your account uses a company-scoped base URL.
FS_DEBUG false Set to true to log every API request and response body.
FS_LOG_LEVEL debug Log verbosity: debug info warn error fatal.
FS_LOG_DIR logs Directory for daily log files.

Optional — Transport & HTTP server

Variable Default Description
MCP_TRANSPORT stdio Transport mode: stdio or http.
MCP_HTTP_PORT 3000 Port the HTTP server listens on.
MCP_HTTP_HOST 0.0.0.0 Interface to bind to (0.0.0.0 = all interfaces).
MCP_HTTP_PATH /mcp URL path for the MCP endpoint.
MCP_HTTP_STATELESS false true = create a new server per request (no session tracking). Suitable for serverless/ephemeral callers.

Optional — HTTP authentication

Variable Default Description
MCP_AUTH_ENABLED false Set to true to require Bearer token auth on all MCP endpoints. GET /health is always exempt.
MCP_API_KEYS Comma-separated list of valid API keys. Required when MCP_AUTH_ENABLED=true. Any single key grants full access.

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
.env file on your local machine Never committed (.gitignore), never copied into the image (.dockerignore)
Baked into Dockerfile via ENV Would be visible in every layer of the image
Committed to git Permanent, hard to rotate
Docker image layers docker history / docker inspect exposes them
Runtime environment variable (-e, env:) 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 credentials

The .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: username

Render / Railway / Fly.io / Heroku — use the platform's "Environment Variables" or "Secrets" UI dashboard.


Running Locally

Prerequisites

node --version   # must be ≥ 20
npm --version

Install and build:

npm install
npm run build

Configure credentials:

cp .env.example .env
# Edit .env — set FS_API_USERNAME and FS_API_PASSWORD at minimum

STDIO 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:stdio

The 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:http

Default endpoint: http://localhost:3000/mcp

Custom port or path:

MCP_HTTP_PORT=8080 MCP_HTTP_PATH=/api/mcp npm run start:http

Verify 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:http

Test 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 it

Running 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:start

Stop 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 later

Option 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-compose

Then use the hyphenated docker-compose command (v1) or the :v1 npm script variants:

docker-compose --version  # docker-compose version 1.x or 2.x

How to tell which you have: Run docker compose version (with a space). If it says unknown 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) npm run docker:start or docker compose up -d --build
Start (foreground, see logs in terminal) npm run docker:up or docker compose up
Stop npm run docker:stop or npm run docker:down
Logs npm run docker: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/health

Custom port — set MCP_HTTP_PORT in your .env or shell before starting:

MCP_HTTP_PORT=8080 npm run docker:start

What 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:build

Run persistent (loads .env, container survives reboot; stop with docker stop fastspring-mcp):

npm run docker:run:env

Run 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-mcp

CI/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:latest

The --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/mcp

If 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 test

Watch mode:

npm run test:watch

Type-check only (no emit):

npm run typecheck

Smoke 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:smoke

Save output for sharing or debugging:

npm run test:smoke > logs/smoke.txt 2>&1

MCP 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:6274

Pass credentials if you are not using a .env file:

FS_API_USERNAME=xxx FS_API_PASSWORD=yyy npm run test:inspector

MCP 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/mcp

Custom port:

MCP_HTTP_PORT=8080 npm run test:inspector:http

Integration 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:integration

Tools 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
get_order Fetch a single order by internal FastSpring order ID. orderId (string)
find_orders_by_email List all orders for a customer by email. email (string)
find_orders_by_reference Look up orders by reference (e.g. VI8201014-6538-11102S). reference (string)
get_order_by_reference Fetch full order detail by reference via the Classic API. reference (string)

Subscriptions

Tool Description Inputs
get_subscription Fetch a subscription by internal subscription ID. subscriptionId (string)
get_subscription_by_reference Look up a subscription by reference. reference (string)
list_subscriptions List subscriptions with optional filters. status (optional), product (optional), email (optional)
get_subscription_entries Get line items for a subscription. subscriptionId (string)

Accounts

Tool Description Inputs
get_account Fetch a customer account by ID. accountId (string)
find_account_by_email Look up an account by customer email. email (string)
get_account_orders Get all orders for an account. accountId (string)

ID vs reference — avoiding 400 errors

  • get_order and get_subscription use 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_reference or get_subscription_by_reference when 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 both id and reference.
  • 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/yourcompany in .env.

Logging

  • Daily rotation: one file per day under FS_LOG_DIR (default logs/), e.g. logs/fastspring-mcp-2026-02-19.log. Files are retained for 14 days.
  • Levels: fatal error warn info debug — set via FS_LOG_LEVEL.
  • DEBUG level: logs every FastSpring API request (method, URL) and response (status, body). Enable with FS_DEBUG=true or FS_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
npm run build Compile TypeScript → dist/
npm start Start server in STDIO mode (default)
npm run start:stdio Start server explicitly in STDIO mode
npm run start:http Start server in Streamable HTTP mode (port 3000)
npm run typecheck Type-check without emitting
npm run lint ESLint on src/

Testing

Script Description
npm test Vitest unit tests with coverage
npm run test:watch Vitest in watch mode
npm run test:smoke Smoke test over STDIO — no browser required
npm run test:integration Integration test against real FastSpring API
npm run test:inspector MCP Inspector UI — STDIO mode
npm run test:inspector:http MCP Inspector UI — HTTP mode (starts server + opens Inspector)

Docker

Script Description
npm run docker:start Start persistent container (detached; restarts on reboot) — recommended
npm run docker:stop Stop and remove containers (Compose)
npm run docker:build Build the Docker image only
npm run docker:run Same as docker:start (Compose up -d)
npm run docker:up Start in foreground (logs in terminal; Ctrl+C stops container)
npm run docker:down Same as docker:stop
npm run docker:logs Tail container logs (Compose v2)
npm run docker:run:env Plain docker run with .env, persistent (--restart unless-stopped)
npm run docker:up:v1 / docker:down:v1 / docker:logs:v1 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

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured