@cyanheads/mailchimp-mcp-server
Allows drafting, testing, and sending Mailchimp campaigns, managing audiences, subscribers, segments, templates, files, and reports, with safe-by-default send gates.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@cyanheads/mailchimp-mcp-serverDraft a campaign for the upcoming webinar"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Overview
Mailchimp campaign management over the Mailchimp Marketing API v3. Draft, test, and send email campaigns, manage audiences and subscribers, and review post-send analytics from any MCP client. Runs as a stdio process or a local Streamable HTTP server.
Tools
Tool | Description |
| Account profile, plan, data center, and the Chimp Chatter activity feed. |
| Manage audiences (lists) — read, create/update, per-audience analytics, signup-form config. No delete. |
| One-call audience health digest: info, stats, growth history, top email clients, merge-field schema. |
| Subscriber CRUD + tags/notes/activity. |
| Add or update a subscriber idempotently with status, merge fields, tags, and an optional note. |
| Locate a subscriber by email in one audience or across the account. |
| Batch add/update subscribers (capped at 500/call). Status defaults to |
| CRUD for audience segments (saved, static, fuzzy) plus member listing and batch add/remove. |
| Read + create/update custom subscriber attributes. No delete. |
| Campaign record management: list/get/create/update, replicate, content, checklist, RSS/resend controls. |
| Compose and send (or schedule/test) a campaign in one call. |
| Duplicate a campaign with optional overrides, then draft/test/send/schedule. |
| Campaign reports — generic slicer across ten dimensions. |
| Post-send analytics digest — headline metrics plus top-N slices in one response. |
| Mailchimp-hosted templates: reads work on free; writes require a paid plan. |
| File Manager (Content Studio) — upload, list, fetch, rename, delete files on Mailchimp's CDN. |
| Global search across members or campaigns. |
| Local-assets surface — inspect and pre-warm uploads for |
| Author and render local |
| Structured procedural playbook merged with live account state. Advice-only. |
Resources
Resource | Description |
| Account info snapshot — profile, plan, data center, total subscribers. |
| Audience snapshot — name, contact, stats, double opt-in status. |
| Campaign snapshot — status, settings, recipients summary. |
| Post-send campaign report headline metrics. |
All resource data is also reachable via tools. Large collections (audiences, campaigns) are not exposed as resources — use the list operation on the corresponding tool instead.
Prompts
Prompt | Description |
| Compose a monthly editorial newsletter from a URL or brief, chaining into |
Design reference: docs/email-design-playbook.md.
Related MCP server: Mailchimp MCP Server
Capability reference
mailchimp_account tool
operation: inforeturns profile, plan, data center, and total subscribers;operation: activity-feedreturns the Chimp Chatter event streamactivity-feedpages viacount(max 100, default 20) andoffset; each item carries type, timestamp, and a human-readable descriptionAn empty activity feed returns a plain-language
noteexplaining likely causes instead of a bare empty array
mailchimp_audiences tool
list/get/create/updatemanage audience records;createrequiresname,contact(company/address1/city/state/zip/country),permissionReminder, andcampaignDefaults(fromName/fromEmail/language)Analytics reads:
list-activity,list-growth,list-clients,list-abuse-reports,list-locationsget-signup-forms/customize-signup-formsmanage hosted/embedded signup-form header, content sections, and CSSNo delete — on the free plan's 1-audience cap this is destructive; delete via the Mailchimp UI
countcaps at 1000 per page
mailchimp_audience_overview tool
One call merges audience info,
growthMonthsof growth history (1–36, default 12), top email clients, and the full merge-field schemanotes[]distinguishes "no data yet" (new audience, no sends) from a genuine empty-engagement signal
mailchimp_subscribers tool
CRUD except permanent delete:
list/get/update, plusarchive(removes from the active audience, preserves the record so the email can resubscribe)set-tagsis declarative — the provided set becomes the full active tag list; anything not included is removed unless named inpreserveTagsMailchimp stores static-segment membership as a tag, so an unguarded
set-tagscan silently drop segment membershiplist-notes/add-note/update-note/delete-notemanage CRM-style notes;list-activity/list-events/list-goalsare engagement readsNo GDPR permanent-delete — do that in the Mailchimp UI
mailchimp_upsert_subscriber tool
Idempotent add-or-update by email — creates via PUT, updates via PATCH, skipping merge-field revalidation on updates that don't touch merge fields
Declarative tag sync computes the add/remove delta from a desired set;
preserveTagsprotects named tags (including static-segment names) from removalstatus: 'pending'triggers Mailchimp's double opt-in email;'subscribed'requires documented consentupdateExistingStatus: falseappliesstatusonly to newly-created subscribers, leaving existing ones untouched
mailchimp_find_subscriber tool
Searches one audience (
audienceId) or every audience on the account by email, returning separateexactMatches/fuzzyMatchesarraysEach match is enriched with merge fields and engagement stats;
includeTags: true(default) adds the full active tag list at one extra call per match
mailchimp_import_subscribers tool
Batch add/update, capped at 500 rows per call — chunk larger imports client-side
statusdefaults topending(double opt-in) to prevent accidental mass-sends; a per-rowstatusoverrides the top-level defaultupdateExisting: false(default) skips rows that already exist instead of overwriting themReturns per-row succeeded/failed with Mailchimp error codes and messages
mailchimp_segments tool
CRUD for saved, static, and fuzzy segments; free tier supports static and basic saved segments — advanced dynamic conditions require Premium
list-memberspages current segment membershipbatch-update-membersadds/removes many subscribers from a static segment in one call — not reversible in one shotdeleteis exposed here (unlike audiences/merge-fields), since removing a segment doesn't destroy subscriber data
mailchimp_merge_fields tool
list/get/create/updatefor custom subscriber attributes (merge tags such asFNAME, limited to 10 characters)No delete — removing a merge field drops that data column across every subscriber; do it in the Mailchimp UI
optionscarries type-specific config:choicesfor dropdown/radio,date_formatfor date/birthday,phone_formatfor phone
mailchimp_campaigns tool
list/get/create/update/replicatefor campaign records;get-content/set-contentmanage the HTML/plaintext payloadget-checklistruns Mailchimp's send-readiness checklist without sending;cancel-sendaborts an in-flight sendcreate-resendbuilds a resend-to-non-openers draft;pause-rss/resume-rsscontrol RSS-driven campaignsNo
send/send-test/schedule/delete— usemailchimp_send_campaignormailchimp_replicate_campaignfor dispatch (checklist-validated, gated onconfirmSend: true); delete would destroy report history on a sent campaignset-contentacceptshtml,plainText,templateId+templateSections, an archive payload, a fetchurl, orlocalTemplate(mutually exclusive withhtml/templateId)
mailchimp_send_campaign tool
Chains create → set-content → checklist → optional test → send/schedule in one call
modedefaults todraft;send/schedulerequireconfirmSend: trueplus a re-entrant confirmation round before any campaign mutationBlocking checklist errors throw
pre_send_checklist_failedbefore dispatch;cleanupOnError: true(default) deletes the orphaned draft on any mid-flow failurescheduleTimemust be at least 15 minutes in the future;testEmailscaps at 50 recipients
mailchimp_replicate_campaign tool
Duplicates an existing campaign, then optionally overrides subject/previewText/fromName/replyTo/title/audience/segment/content before draft/test/send/schedule
Same
confirmSend: trueplus re-entrant confirmation andcleanupOnErrorsemantics asmailchimp_send_campaignoverridesApplied[]in the output lists which overrides actually took effect
mailchimp_reports tool
list/getare report-index reads;slicepulls one dimension viadimension(abuse-reports, advice, click-details, open-details, domain-performance, eepurl, email-activity, locations, sent-to, unsubscribed)click-detailsdrills into one URL withlinkId;open-detailsdrills into one member withsubscriberHashget/slicethrowcampaign_not_sentwhen the campaign has no send yetFor a full digest in one call, prefer
mailchimp_campaign_report
mailchimp_campaign_report tool
One call parallelizes headline delivery/engagement metrics with top-N clicked links, top locations, and recent unsubscribes (
includeTopN, 1–100, default 10)Throws
campaign_not_sentif the campaign hasn't been dispatched yetIncludes industry benchmarks when Mailchimp reports them for the account's declared vertical
mailchimp_templates tool
list/get/get-default-contentare reads that work on free forbase/usertemplate types;create/update/deleteare paid-tier writes regardless of typegallery(drag-and-drop) is read-gated to paid plans tooPer-section edits aren't supported here — Mailchimp's PATCH only accepts
name/html/folderId; per-section overrides at send time go throughmailchimp_campaigns(set-content) ormailchimp_send_campaign'stemplateSectionsPrefer
mailchimp_local_templatesfor authoring — it works on every plan tier
mailchimp_files tool
upload/list/get/update/deletemanage Mailchimp File Manager (Content Studio); works on every plan tier including freeSize caps: 1 MB per image, 10 MB per other file;
fileDatais base64 with nodata:prefixUpload response's
fullSizeUrlis the public CDN URL to embed in campaign HTMLupdatewithfolderId: 0moves a file to root; folder CRUD isn't exposed — use the Mailchimp UI or upload to rootWebP/AVIF aren't in Mailchimp's allowed-extension list — convert to PNG/JPG first
mailchimp_search tool
scope: membersmatches across all audiences (or one viaaudienceId);scope: campaignsmatches subject/title/preview/archive textMember results split into
exactandfuzzyarrays with separate upstream totalsCapped at
includeTopNresults (1–100, default 10); usemailchimp_find_subscriberfor full subscriber detail and tags
mailchimp_assets tool
Conditional — registered only when
MAILCHIMP_ASSETS_DIRis setlist/info/sync/clear-cacheinspect and pre-warm the local-assets pipeline; most workflows never call this directly@assets/<path>references in campaign HTML auto-upload viamailchimp_send_campaign,mailchimp_replicate_campaign, ormailchimp_campaigns set-content— hash → upload cache misses → cachesha256 → fileId/URLat<assetsDir>/.mailchimp-cache.json→ rewrite to the CDN URLPath traversal (
.., absolute paths) is rejected; deleting the cache file forces re-upload on next referenceNode-only
mailchimp_local_templates tool
Conditional — registered only when
MAILCHIMP_TEMPLATES_DIRis setlist/get/render-preview/seed-from-mailchimpmanage.etatemplate files (Eta v4 — partials, conditionals, loops) with optional YAML frontmatter (subject,previewText,vars) or a legacy<name>.meta.yamlsidecarCanonical write path for templates on free-tier Mailchimp accounts, where the upstream
/templatesAPI is read-onlyWhen a template declares
vars, every declared name must be present inrender-preview'svarsinput or the render fails — undeclared lookups fall back to an empty stringseed-from-mailchimpbootstraps a local template from an existing Mailchimpbase/usertemplate by IDReference from any campaign tool via
content.localTemplate+content.localTemplateVars; mutually exclusive withhtml/templateId
mailchimp_playbook tool
topicselects a procedural playbook:send,post-send-review,deliverability,list-hygiene,onboarding,subscriber-triage,design-campaignReturns markdown
instructionstailored to live account/audience state, aliveStatesnapshot, andnextToolSuggestionswith pre-filled argumentsAdvice-only — makes no writes; the agent executes the suggested follow-up tool calls
design-campaignincludes the editorial-design reference (palette, typography, layout, graphics via CDN) tailored by audience size and engagement
mailchimp://account resource
Account snapshot as
application/json— profile, plan, data center, total subscribers,fetchedAttimestampNo parameters; equivalent to
mailchimp_accountoperation: info
mailchimp://audiences/{audienceId} resource
Audience snapshot — name, contact, stats, campaign defaults, double opt-in status
audienceIdcomes frommailchimp_audiencesoperation: list
mailchimp://campaigns/{campaignId} resource
Campaign snapshot — status, settings, recipients summary, tracking, report summary
campaignIdcomes frommailchimp_campaignsoperation: list
mailchimp://campaigns/{campaignId}/report resource
Post-send headline metrics — bounces, opens, clicks, industry stats
Throws a validation error if the campaign hasn't been sent yet
newsletter_from_source prompt
Arguments:
source(URL or free-form brief, required),audienceId(optional — feeds live engagement state intodesign-campaign),seasonalContext(optional)Chains into
mailchimp_playbook(topic: design-campaign) for audience-aware design guidance, then walks draft → test → send viamailchimp_send_campaignReturns a single user-role message carrying the full workflow instructions
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Mailchimp-specific:
Auto-derives the API base URL and data center from the
-dcsuffix on the API keySafe-by-default send workflows — re-entrant confirmation before dispatch, pending-status imports, no permanent deletes from the agent surface
Upstream requests share a configurable concurrency limit and 429 cooldown (
MAILCHIMP_CONCURRENCY_LIMIT)Local-first authoring for assets and templates — bypasses the free tier's read-only Templates API and File Manager UI friction
Declarative tag sync computes add/remove deltas instead of requiring callers to track state
Agent-friendly output:
Provenance and freshness — plain-language
notes/notefields explain empty results (e.g. "no growth history yet" vs. zero engagement)Graceful partial failure —
mailchimp_import_subscribersandmailchimp_segmentsbatch operations return per-row succeeded/failed with Mailchimp error codes instead of failing the whole requestDiscriminated output contracts —
operation/dimensionfields on multi-operation tools tell the caller which optional fields are populatedTyped error contracts with required recovery hints — every declared error reason carries a
recoverystring describing the caller's next move
Getting started
Add the following to your MCP client configuration file. See docs/api-key.md for how to generate a Mailchimp API key.
{
"mcpServers": {
"mailchimp-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/mailchimp-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"MAILCHIMP_API_KEY": "your-key-with-dc-suffix-e.g.-us22"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"mailchimp-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/mailchimp-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"MAILCHIMP_API_KEY": "your-key-with-dc-suffix-e.g.-us22"
}
}
}
}Or with Docker:
{
"mcpServers": {
"mailchimp-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "MAILCHIMP_API_KEY=your-key-with-dc-suffix-e.g.-us22",
"ghcr.io/cyanheads/mailchimp-mcp-server:latest"
]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 MAILCHIMP_API_KEY=... bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
A Mailchimp Marketing API key — the key's
-dcsuffix (e.g.-us22) identifies your data center and is parsed at startup.
Installation
Clone the repository:
git clone https://github.com/cyanheads/mailchimp-mcp-server.gitNavigate into the directory:
cd mailchimp-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env and set MAILCHIMP_API_KEYConfiguration
Variable | Description | Default |
| Required. Mailchimp Marketing API key including | — |
| Override API base URL (for mock servers or tests). |
|
| Per-request timeout in milliseconds. |
|
| Max retry attempts for transient upstream failures (0-10). |
|
| Max in-flight upstream requests across all tools in this process (1-10). |
|
| Absolute path to a local assets directory. Enables | unset |
| Absolute path to a local templates directory. Enables | unset |
| Transport: |
|
|
|
|
| HTTP server hostname. |
|
| HTTP server port. |
|
| MCP endpoint path. |
|
| Auth mode: |
|
| Log level (RFC 5424). |
|
| Directory for log files (Node.js only). |
|
| Enable OpenTelemetry. |
|
See .env.example for the full list of optional overrides.
Local assets (optional)
Set MAILCHIMP_ASSETS_DIR to enable a local-image workflow on top of Mailchimp's File Manager. Drop image files into the directory, reference them in HTML as @assets/<relative-path>, and the server uploads + rewrites at send time.
export MAILCHIMP_ASSETS_DIR=/Users/me/Pictures/email-assetsThen in a campaign:
<img src="@assets/hero.png" alt="Hero">
<a href="@assets/whitepaper.pdf">Download</a>When mailchimp_send_campaign (or mailchimp_campaigns set-content / mailchimp_replicate_campaign contentOverride) sees these references, it:
Hashes each referenced file (SHA-256).
Uploads cache misses to Mailchimp File Manager via the
mailchimp_filestool surface.Caches
sha256 → file_id + URLat<assetsDir>/.mailchimp-cache.json(atomic writes; safe to delete to force re-upload).Rewrites every
@assets/<path>to the public CDN URL before passing content upstream.
The mailchimp_assets tool exposes list, info, sync (pre-warm), and clear-cache for direct inspection — most workflows don't need it.
Caveats:
Mailchimp caps images at 1 MB and other files at 10 MB. Oversize files fail before upload with an actionable error.
Allowed extensions: see the
mailchimp_filestool description. WebP and AVIF are NOT in the allowlist — convert to PNG/JPG.Path traversal is rejected (
../and absolute paths throwForbidden).The
mailchimp_assetstool is Node-only.
Local templates (optional)
Set MAILCHIMP_TEMPLATES_DIR to enable a local-template authoring workflow on top of Eta (v4 — fast, ESM-native, supports partials/conditionals/loops). This is the canonical write path for templates on free-tier Mailchimp accounts, where the upstream /templates API is read-only.
export MAILCHIMP_TEMPLATES_DIR=/Users/me/email-templatesemail-templates/
welcome.eta # body + optional YAML frontmatter
newsletter.eta
partials/
header.eta
footer.etaTemplate (welcome.eta) — YAML frontmatter on top, Eta body below:
---
subject: "Welcome to {{brand}}"
previewText: "Onboarding starts here"
vars:
- firstName
- brand
---
<%~ include('partials/header', it) %>
<h1>Hello <%= it.firstName %></h1>
<p>Welcome to <%= it.brand %>.</p>
<img src="@assets/hero.png" alt="Hero">Frontmatter and its fields are optional. When vars: is present, every listed variable must be supplied; undeclared variable lookups render as an empty string.
Sidecar fallback (legacy): prior to v0.3.1, meta lived in a separate
<name>.meta.yamlfile next to the body. That form still works for backward compatibility — if a.etahas no frontmatter, the loader falls back to reading the sidecar. Frontmatter takes precedence when both exist.
Reference from any campaign tool:
{
"audienceId": "abc123",
"subject": "Welcome to Acme",
"fromName": "Casey",
"replyTo": "casey@acme.com",
"content": {
"localTemplate": "welcome",
"localTemplateVars": { "firstName": "Sam", "brand": "Acme" }
},
"mode": "draft"
}The render pipeline:
Eta renders
welcome.etawithit = { firstName: 'Sam', brand: 'Acme' }.If L1 is configured,
@assets/hero.pngis uploaded to Mailchimp File Manager and rewritten to a CDN URL.Final HTML is set on the campaign via Mailchimp's
set-content.
The mailchimp_local_templates tool exposes list, get, render-preview (returns HTML without sending), and seed-from-mailchimp (reads a Mailchimp base/user template by ID and writes it to disk as a starting point — useful on free where you can read but not write upstream).
Example templates in this repo
The templates/ directory holds working examples — point MAILCHIMP_TEMPLATES_DIR at it directly to try them, or copy them into your own dir as a starting point:
Template | What it shows |
Minimal body — frontmatter declaring | |
Full inline-styled HTML newsletter. Demonstrates the recommended split: Mailchimp merge tags ( |
Caveats:
localTemplateis mutually exclusive withhtmlandtemplateIdon the same content block.Missing declared variables fail before rendering; extra variables are allowed.
Path traversal is rejected.
Running the server
Local development
Watch mode (transport via
MCP_TRANSPORT_TYPE):bun run dev # stdio (default) MCP_TRANSPORT_TYPE=http bun run dev # httpBuild and run:
bun run rebuild bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t mailchimp-mcp-server .
docker run --rm -e MAILCHIMP_API_KEY=your-key-us22 -p 3010:3010 mailchimp-mcp-serverThe Dockerfile defaults to HTTP transport, stateful session mode, and logs to /var/log/mailchimp-mcp-server. Stateful HTTP preserves campaign confirmation for 2025-era clients. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Resource definitions ( |
| Prompt definitions ( |
| Mailchimp client wrapper — HTTP plumbing, retries, normalization, typed surface. |
| Example |
| Vitest coverage for configuration, services, tool workflows, output formatting, framework contracts, and regressions. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped loggingRegister new tools and resources via the barrels in
src/mcp-server/*/definitions/index.tsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Mailchimp MCP Pack — manage audiences, campaigns, and members via Mailchimp Marketing API.
Send transactional email and manage domains, audiences, and broadcasts from any MCP client.
Read audiences, members, campaigns and reports; add, update, tag and archive subscribers.
Read subscribers, groups, campaigns, fields, segments, automations, webhooks; safe additive writes.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that interfaces with the Mailchimp Marketing API to manage audiences, email campaigns, and subscribers. It enables users to create and schedule campaigns, handle member lists, and send test or live emails through natural language commands.1324 npmMIT
- AlicenseBqualityCmaintenanceA production-grade MCP server that integrates with the Mailchimp Marketing API to manage campaigns, audiences, members, and reports. It provides 28 specialized tools for automating marketing tasks such as sending emails, managing subscriber tags, and analyzing performance data.711MIT
- FlicenseNot gradedqualityDmaintenanceEnables interaction with the Mailchimp API for managing campaigns, lists, templates, reports, and automations through natural language.3-
- AlicenseNot gradedqualityBmaintenanceManage Mailchimp audiences, campaigns, and members via the Mailchimp Marketing API through natural language queries.5 npmMIT