Campaign Monitor MCP Server
# π£ Campaign Monitor MCP Server
A [Model Context Protocol](https://modelcontextprotocol.io) 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 `destructiveHint` annotation.
- **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_CATEGORIES`
to 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):
```json
{
"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](#registering-the-mcp-server) for per-client setup. To run
from source instead (for development), see [Running from source](#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](#using-oauth-instead-optional).
## Install & build
```bash
npm install # also builds via the prepare hook
npm run build # or build manually
```
## Configure
Copy the example env file and fill it in:
```bash
cp .env.example .env
```
### API key (recommended)
1. 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 `account` and `clients` tools work. A **client-level** key (inside a specific
client's settings) is scoped to just that client.
2. Set it in `.env` β this is the only credential you need:
```
CM_API_KEY=your-api-key-here
```
Leave 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.
1. **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 match `CM_REDIRECT_URI` exactly). Submit
to get a **Client ID** and **Client Secret**.
2. Put `CM_CLIENT_ID` and `CM_CLIENT_SECRET` in `.env`.
3. 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_TOKEN` into `.env` as a backup):
```bash
npm run auth
```
When all three OAuth variables are present they take precedence over `CM_API_KEY`.
## Verify
```bash
npm run smoke # auth + GET /clients + GET /billingdetails (no writes)
npm run inspector # build + open the MCP Inspector against the server
```
## Registering 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:
```jsonc
"env": {
"CM_API_KEY": "your-api-key"
}
```
> Tip: you can omit `env` entirely if you keep `CM_API_KEY` in the project's `.env` file β
> the server loads it on startup. (Using OAuth instead? Put `CM_CLIENT_ID`,
> `CM_CLIENT_SECRET`, and `CM_REFRESH_TOKEN` in the `env` block instead of `CM_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`
```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):
```bash
claude mcp add campaign-monitor \
--env CM_API_KEY=your-api-key \
-- npx -y @kanopi/campaign-monitor-mcp
```
Add `--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`):
```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.:
```json
"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:
```bash
npm run inspector # opens the MCP Inspector against node dist/index.js
```
### Running 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`:
```bash
git clone https://github.com/kanopi/campaign-monitor-mcp.git
cd campaign-monitor-mcp
npm install # builds via the prepare hook
```
Then use this config shape instead of the `npx` one above (use the **absolute** path):
```json
{
"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 `env` block is missing/misspelled, or
(from source) `.env` isn't being read. Provide credentials in the client config's `env`.
- **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 to `npx`
(run `which npx`) or to `node`. From source, also confirm you ran `npm install`/`npm run
build` and used an **absolute** path to `dist/index.js`.
- **`npx` can't find the package** β confirm the scoped name `@kanopi/campaign-monitor-mcp`
is spelled correctly and published; clear a stale cache with `npx 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`/`clients` tools). Using
OAuth: the refresh token expired or was revoked β re-run `npm 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
TDQS
Scored across 117 tools
Across 117 tools, most target a distinct resource and action, and the descriptions clearly separate account-level vs client-level vs list-level operations. A few closely related reporting endpoints (e.g., transactional message vs smart email, campaign opens vs journey email opens) could cause minor misselection, but the boundaries are generally well-defined.
The cm_ prefix and snake_case verb_noun style are applied consistently, which helps a lot at this scale. There are minor deviations in verb choiceβlist_clients vs get_client_lists, get_person vs list_people, get_active_subscribers vs list_transactional_messagesβbut the overall pattern is predictable.
117 tools is an extreme count for a single MCP server. Even though the underlying API is broad, this surface overwhelms an agent's tool-selection space and would benefit from splitting into domain-specific servers (e.g., campaigns, lists, transactional, journeys).
The surface covers the major Campaign Monitor domains thoroughly: clients, people, lists, subscribers, segments, campaigns, templates, webhooks, transactional email, journeys, and billing. Notable gaps include no way to update a campaign after creation and no tool to retrieve a segment's current rule definitions, but most workflows can still be completed with available tools.