@kanopi/campaign-monitor-mcp
v1.0.0
Published
Model Context Protocol server exposing the full Campaign Monitor (createsend) v3.3 API
Maintainers
Readme
📣 Campaign Monitor MCP Server
A Model Context Protocol server that exposes the full Campaign Monitor (createsend) v3.3 API — 117 tools across 9 resource categories — to MCP-compatible clients like Claude Desktop, Claude Code, and the MCP Inspector.
Authenticates with a Campaign Monitor API key (simplest, recommended) or via OAuth 2.0 with an auto-refreshing access token. Runs locally over stdio.
Features
- Complete API coverage — account, clients, campaigns, lists, segments, subscribers,
templates, transactional email, and journeys. Includes destructive/sending operations
(send campaign, send transactional email, delete) — these are flagged with ⚠️ in their
descriptions and tagged with the MCP
destructiveHintannotation. - Simple auth — drop in an API key and go. OAuth 2.0 is available as an optional alternative (with automatic refresh-token rotation persisted to a local store).
- Category filtering — expose only the categories you need via
CM_ENABLED_CATEGORIESto keep the tool surface small.
Install from npm
You don't need to clone or build — run it straight from npm with npx, which is also how
you point an MCP client at it (-y auto-confirms the one-time download):
{
"mcpServers": {
"campaign-monitor": {
"command": "npx",
"args": ["-y", "@kanopi/campaign-monitor-mcp"],
"env": { "CM_API_KEY": "your-api-key" }
}
}
}Or install the CLI globally: npm install -g @kanopi/campaign-monitor-mcp, then the
campaign-monitor-mcp command is available on your PATH.
See Registering the MCP server for per-client setup. To run from source instead (for development), see Running from source.
Requirements
- Node.js 20+
- A Campaign Monitor account and an API key (Account settings → API keys). OAuth credentials are an optional alternative — see Using OAuth instead.
Install & build
npm install # also builds via the prepare hook
npm run build # or build manuallyConfigure
Copy the example env file and fill it in:
cp .env.example .envAPI key (recommended)
In Campaign Monitor, click your account name (top-right) → Account settings → API keys, and copy the API key.
- The account-level key (top-level account settings) can access every client, so
the
accountandclientstools work. A client-level key (inside a specific client's settings) is scoped to just that client.
- The account-level key (top-level account settings) can access every client, so
the
Set it in
.env— this is the only credential you need:CM_API_KEY=your-api-key-hereLeave the OAuth variables blank. The server uses the API key automatically whenever no OAuth refresh token is present.
Using OAuth instead (optional)
OAuth lets the server use short-lived, scoped, revocable tokens instead of a static key. It takes more setup. Skip this entirely if you're using an API key.
Register an OAuth application. Log in, open Integrations in the top nav (select a client first if prompted), then OAuth Registration in the right sidebar. Fill in an application name, a description, and set the Redirect / Callback URI to
http://127.0.0.1:53682/callback(it must matchCM_REDIRECT_URIexactly). Submit to get a Client ID and Client Secret.Put
CM_CLIENT_IDandCM_CLIENT_SECRETin.env.Run the one-time bootstrap — it opens your browser, you approve the scopes, and a refresh token is stored (and printed so you can paste
CM_REFRESH_TOKENinto.envas a backup):npm run auth
When all three OAuth variables are present they take precedence over CM_API_KEY.
Verify
npm run smoke # auth + GET /clients + GET /billingdetails (no writes)
npm run inspector # build + open the MCP Inspector against the serverRegistering the MCP server
The server is a local stdio process: an MCP client launches it with npx and talks to
it over stdin/stdout. You register it once per client by pointing the client at the package
and supplying credentials as environment variables.
The only prerequisite is Node.js 20+. npx -y @kanopi/campaign-monitor-mcp downloads
and runs the package on first use (and caches it) — no clone, no build, no paths to manage.
The credentials block is the same for every client — just your API key:
"env": {
"CM_API_KEY": "your-api-key"
}Tip: you can omit
enventirely if you keepCM_API_KEYin the project's.envfile — the server loads it on startup. (Using OAuth instead? PutCM_CLIENT_ID,CM_CLIENT_SECRET, andCM_REFRESH_TOKENin theenvblock instead ofCM_API_KEY.)
Claude Desktop
Edit claude_desktop_config.json (create it if missing):
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"campaign-monitor": {
"command": "npx",
"args": ["-y", "@kanopi/campaign-monitor-mcp"],
"env": {
"CM_API_KEY": "your-api-key"
}
}
}
}Save and fully quit and reopen Claude Desktop. The tools appear under the 🔌 (MCP) icon in the chat input.
Claude Code (CLI)
Register with one command (no manual JSON editing):
claude mcp add campaign-monitor \
--env CM_API_KEY=your-api-key \
-- npx -y @kanopi/campaign-monitor-mcpAdd --scope user to make it available in every project (default is the current project
only). Verify with claude mcp list, and inside a session run /mcp to see the tools.
Remove with claude mcp remove campaign-monitor.
Cursor / Windsurf / other MCP clients
Any client that supports local stdio MCP servers uses the same shape. Add to the client's
MCP config (e.g. Cursor's ~/.cursor/mcp.json or a project .cursor/mcp.json):
{
"mcpServers": {
"campaign-monitor": {
"command": "npx",
"args": ["-y", "@kanopi/campaign-monitor-mcp"],
"env": {
"CM_API_KEY": "your-api-key"
}
}
}
}Limiting the exposed tools
117 tools is a lot to load at once. To register only the categories you need, add
CM_ENABLED_CATEGORIES to the env block, e.g.:
"env": { "CM_ENABLED_CATEGORIES": "campaigns,lists,subscribers", "...": "..." }Test the registration first
Before wiring into a client, confirm the server boots and lists tools with the Inspector:
npm run inspector # opens the MCP Inspector against node dist/index.jsRunning from source
For development (or to run a local build instead of the published package), clone the repo,
install, and point the client at the built entry file with node:
git clone https://github.com/kanopi/campaign-monitor-mcp.git
cd campaign-monitor-mcp
npm install # builds via the prepare hookThen use this config shape instead of the npx one above (use the absolute path):
{
"mcpServers": {
"campaign-monitor": {
"command": "node",
"args": ["/absolute/path/to/campaign-monitor-mcp/dist/index.js"],
"env": { "CM_API_KEY": "your-api-key" }
}
}
}Troubleshooting
- "No Campaign Monitor credentials found" — the
envblock is missing/misspelled, or (from source).envisn't being read. Provide credentials in the client config'senv. - Server doesn't appear / "failed to start" — ensure
node(v20+) is on the client's PATH; some GUI clients don't inherit your shell PATH, so use an absolute path tonpx(runwhich npx) or tonode. From source, also confirm you rannpm install/npm run buildand used an absolute path todist/index.js. npxcan't find the package — confirm the scoped name@kanopi/campaign-monitor-mcpis spelled correctly and published; clear a stale cache withnpx clear-npx-cache.- 401 / authentication errors at runtime — using an API key: confirm it's correct and
not revoked (and that an account-level key is used for
account/clientstools). Using OAuth: the refresh token expired or was revoked — re-runnpm run auth.
Environment variables
| Variable | Purpose |
| --- | --- |
| CM_API_KEY | API key (recommended). Used unless OAuth credentials are present. |
| CM_ENABLED_CATEGORIES | Comma-separated list to limit exposed tool categories |
| CM_CLIENT_ID / CM_CLIENT_SECRET | OAuth application credentials (optional) |
| CM_REFRESH_TOKEN | OAuth seed refresh token, from npm run auth (optional) |
| CM_REDIRECT_URI | OAuth redirect URI (default http://127.0.0.1:53682/callback) |
| CM_SCOPES | Scopes requested during npm run auth |
| CM_TOKEN_STORE | Path to the OAuth token store file |
Tool catalog
Tools follow a cm_<verb>_<resource> naming convention. Counts by category:
| Category | Tools | Examples |
| --- | --- | --- |
| account | 13 | cm_list_clients, cm_get_billing_details, cm_add_admin |
| clients | 30 | cm_create_client, cm_get_client_lists, cm_suppress_emails |
| campaigns | 15 | cm_create_campaign, cm_send_campaign ⚠️, cm_get_campaign_summary |
| lists | 22 | cm_create_list, cm_create_custom_field, cm_create_webhook |
| segments | 7 | cm_create_segment, cm_get_segment_subscribers |
| subscribers | 7 | cm_add_subscriber, cm_import_subscribers, cm_unsubscribe_subscriber |
| templates | 5 | cm_create_template, cm_copy_template |
| transactional | 9 | cm_send_smart_email ⚠️, cm_send_classic_email ⚠️, cm_get_transactional_statistics |
| journeys | 9 | cm_get_journey, cm_copy_journey, cm_publish_event |
Notes & limits
- Destructive tools are enabled by default (per the build spec). Your MCP client's
permission prompts are the safety gate. To hard-disable a category, omit it from
CM_ENABLED_CATEGORIES. - Responses are returned as JSON. XML responses are not supported.
- Rate limiting (HTTP 429) is honored with a single bounded retry using
Retry-After. - Custom field keys are passed including their brackets, e.g.
[MyField].
License
MIT
