Skip to main content
Glama
ignytehq

plunk-mcp

Official
by ignytehq
README.md
# plunk-mcp

A Model Context Protocol server for [Plunk](https://useplunk.com), the open-source self-hosted email platform. Gives Claude (and any MCP client) 84 tools across the Plunk API: transactional email, contacts, campaigns, segments, templates, workflows, events, analytics.

Unofficial. Not affiliated with Plunk. Built by [Ignyte](https://github.com/ignytehq).

## Why this exists

Plunk's official Node SDK does two things: `track` and `send`. The API behind those two methods has grown into a full email automation platform that includes workflows, segments, templates, analytics, but the SDK never caught up. So Claude couldn't reach any of it.

This MCP closes that gap. Every endpoint Claude can usefully call, it can call.

## Requirements

The active Plunk codebase: [`useplunk/plunk`](https://github.com/useplunk/plunk), distributed as `ghcr.io/useplunk/plunk`. Self-hosted or on [useplunk.com](https://useplunk.com).

Note that this MCP does not support the legacy `driaug/plunk` Docker image. If you're on that image, see [Migrating from legacy](#migrating-from-legacy-driaugplunk).

Node.js ≥ 18 if you're running from source.

## Install

Add to `~/.claude.json` or your Claude Desktop config:

```json
{
  "mcpServers": {
    "plunk": {
      "command": "npx",
      "args": ["-y", "@ignytehq/plunk-mcp"],
      "env": {
        "PLUNK_API_KEY": "sk_your_secret_key_here",
        "PLUNK_PUBLIC_KEY": "pk_your_public_key_here",
        "PLUNK_API_URL": "https://your-plunk-host"
      }
    }
  }
}
```

Restart Claude.

`PLUNK_PUBLIC_KEY` is optional. Plunk's `/v1/track` endpoint is gated by the public key (`pk_*`), not the secret key — if you omit `PLUNK_PUBLIC_KEY`, `plunk_track_event` will 401 against v0.10+ instances.

### Multiple Plunk projects

Plunk API keys are project-scoped. To work with multiple projects in the same session, register one MCP server per project:

```json
{
  "mcpServers": {
    "plunk-acme": {
      "command": "npx",
      "args": ["-y", "@ignytehq/plunk-mcp"],
      "env": {
        "PLUNK_API_KEY": "sk_acme_...",
        "PLUNK_API_URL": "https://plunk.acme.com"
      }
    },
    "plunk-personal": {
      "command": "npx",
      "args": ["-y", "@ignytehq/plunk-mcp"],
      "env": {
        "PLUNK_API_KEY": "sk_personal_...",
        "PLUNK_API_URL": "https://plunk.example.com"
      }
    }
  }
}
```

Claude sees each as its own tool namespace.

## Configuration

| Env var | Required | Default | What it does |
|---|---|---|---|
| `PLUNK_API_KEY` | yes | — | Secret API key (`sk_*`) from your project settings. Used for all admin endpoints and for `/v1/send` / `/v1/verify`. |
| `PLUNK_PUBLIC_KEY` | no | — | Public API key (`pk_*`). Required for `plunk_track_event` — Plunk's `/v1/track` endpoint is gated by the public key, not the secret key. Without this set, `track_event` will 401. |
| `PLUNK_API_URL` | no | `https://api.useplunk.com` | Base URL of your Plunk API. For self-hosted, point at the API host (e.g. `https://api.plunk.example.com`, or `https://plunk.example.com/api` if your reverse proxy maps it that way). |
| `PLUNK_SKIP_CAPABILITY_DETECTION` | no | `false` | Skip the startup probe and expose every tool regardless of what your instance supports. Useful for debugging. |

## What's in the box

84 tools across 11 categories. At startup, the MCP probes one endpoint per category and only registers tools whose category responds — so on older `useplunk/plunk` releases, missing features are hidden rather than failing at call time.

| Category | Tools | Highlights |
|---|---|---|
| Transactional | 3 | `send_transactional`, `track_event`, `verify_email` |
| Contacts | 18 | CRUD, bulk import/subscribe/unsubscribe/delete, custom field management |
| Campaigns | 10 | Full lifecycle: create, update, send, cancel, test, stats |
| Segments | 10 | Dynamic + static segments, member management, recompute |
| Templates | 7 | Reusable email templates referenced from sends/campaigns/workflows |
| Workflows | 16 | Steps, transitions, executions — the whole automation builder |
| Events | 6 | Read API: history, stats, names, usage, delete |
| Domains | 4 | Add, verify, delete sending domains |
| Activity | 5 | Activity feed, stats, upcoming sends |
| Analytics | 4 | Timeseries, top campaigns, top events |
| Uploads | 1 | Image uploads for templates and campaigns |

Tool names follow `plunk_<verb>_<resource>`. Examples:

- `plunk_send_transactional` — send a one-off email
- `plunk_track_event` — fire an event (which then drives workflows and segment filters)
- `plunk_create_workflow` + `plunk_add_workflow_step` + `plunk_start_workflow_execution`
- `plunk_create_segment` (full filter-condition schema)
- `plunk_get_analytics_timeseries`, `plunk_get_top_campaigns`

Every tool has a typed input schema. Claude knows what to pass.

## Capability detection, briefly

On startup the MCP makes one probe request per tool family to see what your instance answers. If `/templates` 404s, the seven template tools are hidden for the rest of the session. If `/workflows` answers, the sixteen workflow tools are registered.

The point is to keep Claude from confidently invoking endpoints that don't exist on your specific Plunk version. The probe takes one round trip per family at startup, then nothing.

## Migrating from legacy `driaug/plunk`

The legacy image exposes a smaller, different API. This MCP won't fully work against it. The migration path:

1. Stand up `ghcr.io/useplunk/plunk:latest` on a separate host or subdomain. Don't disrupt your existing sender. The official guide is at [docs.useplunk.com/self-hosting/introduction](https://docs.useplunk.com/self-hosting/introduction).
2. Re-create your project on the new instance. Grab a fresh `sk_*` API key. The schemas differ; there's no in-place upgrade.
3. Export contacts from legacy (CSV from the dashboard). Import on the new instance via `plunk_import_contacts`.
4. Re-create campaigns and templates. Workflows and segments are entirely new on the modern codebase.
5. Repoint your apps to the new host. Decommission legacy.

This is a real migration project, an easy evening or two of work. 

## Building from source

```bash
git clone https://github.com/ignytehq/plunk-mcp.git
cd plunk-mcp
npm install
npm run build
PLUNK_API_KEY=sk_... PLUNK_API_URL=https://your-plunk node dist/index.js
```

## Contributing

Issues and PRs welcome. If an endpoint responds unexpectedly, please include:

- Which Plunk version you're running (`docker inspect <container> | grep Image` plus the tag)
- The endpoint path that misbehaved
- The full error message

## License

MIT. See [LICENSE](./LICENSE).

## Acknowledgements

[Plunk](https://github.com/useplunk/plunk) and [Driaug Aerts](https://github.com/sponsors/driaug), for being open source. Anthropic, for the [Model Context Protocol](https://modelcontextprotocol.io).

TDQS

A3.9/5.0

Scored across 11 tools

Disambiguation5/5

Each tool targets a distinct resource/action: event tracking, transactional email, email verification, contact CRUD, subscribe/unsubscribe, and image upload. The only potential overlap between update_contact and subscribe/unsubscribe is clarified by different ID types (UUID vs public id).

Naming Consistency5/5

All tools follow a consistent plunk_verb_noun pattern with snake_case (e.g., plunk_list_contacts, plunk_create_contact). The naming is predictable and uniform across the entire set.

Tool Count5/5

11 tools is well-scoped for an email service MCP, covering contacts, events, email sending, verification, and image upload. It is neither too sparse nor bloated.

Completeness3/5

Core CRUD and essential operations are present, but the descriptions reference plunk_bulk_subscribe_contacts and plunk_bulk_unsubscribe_contacts which are not provided as tools. This creates a gap for batch operations and may mislead agents into invoking non-existent tools.

Maintenance

ActivityStale
ResponsivenessUnresponsive