Production Mailchimp MCP Server Starter Template (TypeScript)
Overview
This template gives you a fully production-ready Model Context Protocol (MCP) server written in TypeScript that connects Claude Desktop, Cursor, Windsurf, and other MCP-compatible clients to the Mailchimp Marketing API. It uses the stdio transport, meaning the server runs as a local child process launched by the MCP client โ no HTTP server, no open ports, no OAuth dance required. Authentication is handled entirely through the MAILCHIMP_API_KEY environment variable that Mailchimp's official Node.js client reads automatically.
The template ships with seven realistic Mailchimp tools covering the most common marketing workflows: listing and inspecting audiences, adding and updating audience members, tagging contacts, listing and creating campaigns, listing templates, and fetching campaign performance reports. Every tool is fully typed with TypeScript, validates its inputs with Zod before touching the network, and returns structured error messages that Claude can reason about rather than raw stack traces.
This is aimed at developers who want to give an AI assistant first-class access to their Mailchimp account for tasks like "add this subscriber to my newsletter audience", "create a draft campaign for our Black Friday sale", or "show me the open rates for our last five sends" โ all without leaving the chat interface. The template is equally useful as a learning reference for anyone building their first production MCP server and as a drop-in starting point for a commercial Mailchimp integration.
What You'll Learn
- How to bootstrap an MCP server with the official
@modelcontextprotocol/sdkpackage usingStdioServerTransport - How stdio transport works and why it is the right choice for local, single-user MCP servers
- How to register MCP tools with JSON Schema-compatible input definitions and implement their handlers
- How to authenticate with the Mailchimp Marketing API using an API key and data-centre routing
- How to validate all tool inputs with Zod before making any external API calls
- How to write structured logs with Pino that go to
stderr(neverstdout) so they never corrupt the stdio MCP frame stream - How to implement retry logic with exponential back-off for transient Mailchimp API failures
- How to validate required environment variables at startup and exit with a meaningful error if they are missing
- How to write Jest integration tests that invoke MCP tools end-to-end against a mocked Mailchimp client
- How to build a minimal, production-hardened Docker image with a multi-stage Dockerfile
- How to wire up GitHub Actions CI/CD with lint, type-check, test, and Docker build steps
- How to configure Claude Desktop and Cursor to launch and connect to the server
Architecture
Claude Desktop / Cursor / Windsurf
โ stdin / stdout (JSON-RPC 2.0)
โผ
MCP Server Process (Node.js)
โ
StdioServerTransport
โ
Tool Router (MCP SDK)
โ
Zod Input Validation
โ
Mailchimp API Client (@mailchimp/mailchimp_marketing)
โ HTTPS
โผ
Mailchimp Marketing API (usX.api.mailchimp.com)
The MCP client (Claude Desktop, Cursor, etc.) spawns the server as a child process and communicates over stdin/stdout using JSON-RPC 2.0 framing. The server never binds a TCP port. Pino logs are written exclusively to stderr so they are visible in the MCP client's log viewer without interfering with the protocol stream.
Project Structure
mailchimp-mcp-server/
โโโ src/
โ โโโ __tests__/
โ โ โโโ tools/
โ โ โ โโโ audiences.test.ts
โ โ โ โโโ members.test.ts
โ โ โโโ config.test.ts
โ โ โโโ retry.test.ts
โ โ โโโ setup-env.ts
โ โโโ tools/
โ โ โโโ audiences.ts
โ โ โโโ campaigns.ts
โ โ โโโ members.ts
โ โ โโโ reports.ts
โ โ โโโ templates.ts
โ โโโ types/
โ โ โโโ mailchimp-marketing.d.ts
โ โโโ config.ts
โ โโโ logger.ts
โ โโโ retry.ts
โ โโโ server.ts
โโโ .env.example
โโโ .gitignore
โโโ eslint.config.mjs
โโโ jest.config.ts
โโโ package-lock.json
โโโ package.json
โโโ tsconfig.json
Prerequisites
- Node.js 20 or later
- npm 10 or later
- A Mailchimp account with a Marketing API key (generate one here)
- Docker Desktop (optional, for container deployment)
- Claude Desktop or Cursor (to connect the server as an MCP tool provider)
Quick Start
# 1. Clone or copy the template
git clone https://github.com/your-org/mailchimp-mcp-server.git
cd mailchimp-mcp-server
# 2. Install dependencies
npm install
# 3. Configure environment
cp .env.example .env
# Edit .env and set MAILCHIMP_API_KEY and MAILCHIMP_SERVER_PREFIX
# 4. Build TypeScript
npm run build
# 5. Run the server (stdio โ for manual testing with a pipe)
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | node dist/server.js
# 6. Run tests
npm test
# 7. (Optional) Start with Docker Compose
docker-compose up --build
Features
- stdio MCP transport โ runs as a child process, zero open ports
- Seven Mailchimp tools โ audiences, members, tags, campaigns, templates, reports
- Zod input validation โ every tool validates inputs before hitting the API
- Environment validation โ server exits with a clear error on missing config
- Pino structured logging โ JSON logs on stderr, log level controlled by
LOG_LEVEL - Retry with back-off โ transient 5xx and rate-limit errors are automatically retried
- Full TypeScript โ strict mode, no
any, generated declaration files - Multi-stage Dockerfile โ builder + minimal runtime image (~120 MB)
- docker-compose.yml โ local development with env file support
- Jest tests โ tool execution and error-handling scenarios with mocked Mailchimp client
- GitHub Actions CI โ lint, type-check, test, and Docker build on every push
- Claude Desktop config โ ready-to-paste
mcpServersblock - Cursor config โ ready-to-paste
.cursor/mcp.jsonblock
Works With
| Client | Config method |
|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Code | claude mcp add CLI command |
| Cursor | .cursor/mcp.json in project root or ~/.cursor/mcp.json globally |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Continue | .continue/config.json mcpServers array |
Claude Desktop
Add this block to your claude_desktop_config.json:
{
"mcpServers": {
"mailchimp": {
"command": "node",
"args": ["/absolute/path/to/mailchimp-mcp-server/dist/server.js"],
"env": {
"MAILCHIMP_API_KEY": "your-api-key-here",
"MAILCHIMP_SERVER_PREFIX": "us1",
"LOG_LEVEL": "info"
}
}
}
}
Cursor
Create .cursor/mcp.json in your project root:
{
"mcpServers": {
"mailchimp": {
"command": "node",
"args": ["/absolute/path/to/mailchimp-mcp-server/dist/server.js"],
"env": {
"MAILCHIMP_API_KEY": "your-api-key-here",
"MAILCHIMP_SERVER_PREFIX": "us1"
}
}
}
}
Configuration
| Variable | Description | Required |
|---|---|---|
MAILCHIMP_API_KEY | Mailchimp Marketing API key (format: <key>-<dc>) | Required |
MAILCHIMP_SERVER_PREFIX | Data-centre prefix extracted from your API key (e.g. us1, us21) | Required |
LOG_LEVEL | Pino log level: trace, debug, info, warn, error, fatal | Optional (default: info) |
RETRY_MAX_ATTEMPTS | Maximum number of retry attempts for transient API errors | Optional (default: 3) |
RETRY_BASE_DELAY_MS | Base delay in milliseconds for exponential back-off | Optional (default: 500) |
REQUEST_TIMEOUT_MS | Milliseconds before an API request is aborted | Optional (default: 15000) |
Finding your server prefix: Your Mailchimp API key ends with a data-centre suffix, e.g.
abc123def456-us21. The part after the hyphen (us21) is yourMAILCHIMP_SERVER_PREFIX.
Deployment
Docker (recommended for production)
# Build the image
docker build -t mailchimp-mcp-server:latest .
# Run interactively (stdio โ pipe JSON-RPC frames in)
docker run --rm -i \
-e MAILCHIMP_API_KEY=your-key-us1 \
-e MAILCHIMP_SERVER_PREFIX=us1 \
mailchimp-mcp-server:latest
For Claude Desktop to launch the containerised server, update your mcpServers entry:
{
"mcpServers": {
"mailchimp": {
"command": "docker",
"args": ["run", "--rm", "-i",
"-e", "MAILCHIMP_API_KEY=your-key",
"-e", "MAILCHIMP_SERVER_PREFIX=us1",
"mailchimp-mcp-server:latest"
]
}
}
}
docker-compose (local development)
# Copy and fill in .env
cp .env.example .env
# Start
docker-compose up --build
# The container will start and wait on stdin.
# Attach another terminal and pipe frames in, or connect via Claude Desktop.
Running directly with npx / pm2 (server machines)
For headless servers where Claude connects remotely via a wrapper:
# Install globally
npm install -g .
# Run as a long-lived process with pm2
pm2 start dist/server.js --name mailchimp-mcp --no-autorestart
Production Checklist
-
MAILCHIMP_API_KEYis stored in a secrets manager (1Password, AWS Secrets Manager, etc.) โ never committed to git -
MAILCHIMP_SERVER_PREFIXmatches the suffix of your API key -
LOG_LEVELis set toinfoorwarnin production (notdebugortrace) - API key has the minimum required Mailchimp permissions (see Security Notes below)
- Docker image is built from the
productionstage (notbuilder) -
.envis listed in.gitignoreand never committed -
npm auditreports zero high/critical vulnerabilities - All tests pass:
npm test - TypeScript compiles without errors:
npm run type-check - ESLint reports zero errors:
npm run lint - Docker image size is reasonable (
docker image ls mailchimp-mcp-server) -
RETRY_MAX_ATTEMPTSandRETRY_BASE_DELAY_MSare tuned for your API usage pattern -
REQUEST_TIMEOUT_MSis set low enough to avoid hanging Claude responses - GitHub Actions CI passes on the
mainbranch before deploying - Claude Desktop or Cursor config uses the absolute path to
dist/server.js
Security Notes
Least-privilege API key: Create a dedicated Mailchimp API key for this server with the narrowest permissions your use case needs. Mailchimp does not offer scoped API keys for the Marketing API (all Marketing API keys have full account access), so treat the key as a high-value secret:
- Store it in your OS keychain or a secrets manager โ never in
.envfiles that are committed - Rotate the key immediately if it is ever exposed
- Consider creating a separate Mailchimp account/sub-account if you need stronger isolation
- Audit the tools you enable and comment out any tools you do not need to reduce the blast radius of a compromised key
Testing
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run in watch mode during development
npm run test:watch
The test suite in src/__tests__/server.test.ts mocks the Mailchimp client at the module level and exercises:
- Tool list โ verifies all seven tools are registered
mailchimp_list_audiencesโ happy path returns formatted audience listmailchimp_get_audienceโ happy path returns audience detailmailchimp_list_campaignsโ happy path returns campaign listmailchimp_create_campaignโ happy path creates a campaign and returns its IDmailchimp_list_templatesโ happy path returns template listmailchimp_get_campaign_reportโ happy path returns report metricsmailchimp_add_memberโ happy path subscribes a new member- Error handling โ Mailchimp API errors are caught and returned as structured error text
- Zod validation โ missing required fields return a validation error, not a 500 typescript utilities mailchimp mailchimp api mailchimp mcp server mcp typescript