MCP Server
The Mailtani MCP (Model Context Protocol) server lets AI agents manage your email marketing directly — contacts, lists, segments, campaigns, emails, tags, custom fields, and event tracking — without leaving your AI tool.
It works with Claude Desktop, Claude Code, Cursor, Codex, and any MCP-compatible client that supports HTTP transport.
Quick start
1. Create an MCP key
Go to Settings → API Keys / MCP, choose Create key, and pick MCP server.
The setup panel below the key list then shows a ready-to-paste config for each AI client, with your key and Project ID already filled in — copy the block for your client and skip to step 3.
If you come back later, click the eye icon next to any MCP key to show its config again.
MCP keys can be shown again because a config is no use if you cannot retrieve it — it usually gets pasted into an editor's settings file on another machine, days after the key was made. Plain API keys are different: they are hashed and shown only once, so copy those immediately. Pick the type that matches what you are doing.
2. Find your Project ID
Your Project ID is shown on the Settings → API Keys / MCP page next to the MCP setup panel, and is already included in the generated config.
3. Connect your AI client
The blocks below use mk_YOUR_API_KEY as a placeholder. The copy on your settings page has the
real key substituted, so prefer that over editing these by hand.
Claude Desktop — edit the config file:
- Mac:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Claude Code — run in your terminal, as a single line:
Keep it on one line. PowerShell does not support the
\line continuations used in bash, so a wrapped version runs only the first line — which adds the server with no headers and then reportsalready existson the retry, leaving you with a server that cannot authenticate. If that happened, runclaude mcp remove mailtani -s localfirst and add it again.
Cursor — go to Cursor → Settings → MCP and add:
Codex — add to ~/.codex/config.json:
Restart your client. A hammer icon (🔨) in Claude Desktop confirms the server is connected.
Authentication
Every request requires two headers:
All operations are strictly scoped to the project in the header. A tool cannot read or modify data from a different project, even if the API key belongs to the same account.
Available tools
Contacts
list-contacts
List contacts in your project. Supports search, filtering, and pagination.
create-contact
Create a new contact or upsert if the email already exists. Returns upserted: true if updated rather than created.
update-contact
Update an existing contact's fields, list memberships, or tags.
delete-contact
Permanently delete a contact.
Lists
list-lists
List all contact lists in your project, including contact counts. No inputs required.
create-list
Create a new contact list.
add-contact-to-list
Add one or more contacts to a list. Maximum 500 contacts per call.
remove-contact-from-list
Remove a single contact from a list.
Segments
list-segments
List all segments with their contact counts. No inputs required.
create-segment
Create a segment with filter conditions.
get-segment-contacts
Get paginated contacts that match a segment's conditions.
Campaigns
Campaigns are always created as drafts via MCP, so nothing sends by accident. Review a draft
in the Mailtani app, then activate it there or with activate-campaign /
bulk-update-campaign-status.
list-campaigns
List campaigns with optional filters and pagination.
create-campaign
Create a single-email campaign of any type as a draft. Prefer create-broadcast,
create-sequence or create-flow — they model their shape properly. This is the low-level
option for one email with no steps or targeting.
create-broadcast
Create a one-time email blast as a draft.
create-sequence
Create a multi-step drip sequence as a draft.
Each step object:
create-flow
Create a visual automation flow as a draft. The flow graph is built automatically from your steps.
Each step object:
create-advanced-flow
Create a flow with the full node graph: branches, delays, and campaign start/stop nodes. Use this instead of create-flow whenever the flow needs to branch on a contact property. Returns a draft.
Node types: send_email {subject, body_html, delay_days}, delay {duration, unit} where unit is days or hours, branch {conditions}, audience_filter {conditions}, start_campaign / stop_campaign {campaign_id}, wait_for_reply, wait_for_option.
Edges leaving a branch need handle set to yes or no. A branch missing either arm is rejected: contacts evaluating that way would sit in the flow forever with nothing to tell you.
Stop rules over stop nodes. stop_on_events and stop_when live on the flow that should stop, so a new flow brings its own rule. A stop_campaign node names targets by id and only stops the flows that existed when you wrote it — add another later and nothing stops it, with no error, because the node did stop everything it was told to.
update-flow
Edit an existing flow in place, keeping its id, enrolment history and stats. Refuses to edit an active campaign: contacts are walking its graph, and replacing nodes underneath them strands anyone whose current node disappears. Archive it first.
All settings from create-advanced-flow can also be updated.
inspect-email-body
Check an email body before creating a campaign: markdown that will render literally, unbalanced tags, dead links, variables with no fallback, and what the plain-text part will contain.
simulate-flow
Walk a flow for one contact and see the exact path they would take: which branch arms, which emails, and why. Reads their real stored fields. Sends nothing and writes nothing.
Use this before activating any flow that branches. The API test tool answers "would this contact enrol?"; this answers "which email would they actually get?" — a different question, and the one that catches the failure that matters.
A branch reading a field that resolves unexpectedly takes the same arm for everyone, with no error and nothing in the logs. The symptom is a flow telling people who shared their video that they never shared it. Simulating shows the value behind each decision:
NOT SET means the property never reached the contact as a custom field — usually because no custom field of that name exists, so the value was dropped on arrival. A value in quotes that looks wrong ("1" where you expected "true") means it arrived in the wrong shape.
activate-campaign
Activate a single draft campaign so it can send.
Only drafts can be activated.
Broadcasts and sequences are rejected when they have no enrollments — activating an empty one would look like it worked while sending to nobody.
Flows are exempt. An event-triggered flow has no enrollments until its trigger event fires, so zero at activation is the normal state rather than a mistake.
bulk-update-campaign-status
Archive or activate up to 100 campaigns in one call. Useful when retiring a whole generation of flows, which would otherwise be dozens of calls against the 30/minute rate limit.
Each campaign is checked on its own and one failure never stops the rest. The response reports a
result per id — archived/active, already_*, not_found, or skipped with a reason — so a
partial run is unambiguous. Sent campaigns are never archived: they are the only record that the
send happened.
enroll-contact
Add a contact to a campaign.
Emails
list-emails
List sent emails in your project.
send-email
Send a one-off transactional email. Respects your plan's daily send limit.
Tags
list-tags
List all tags with contact counts. No inputs required.
create-tag
Create a new tag.
delete-tag
Permanently delete a tag.
Custom Fields
list-custom-fields
List all custom fields in your project. No inputs required.
create-custom-field
Create a custom field. Idempotent — returns the existing field if the name already exists.
Events
track-event
Track a custom event for a contact. Properties are persisted as custom field values and can trigger flow automations.
Rate limits
The MCP server allows 30 requests per minute per API key. Add delays between bulk operations in agent workflows.
Plan limits
Example agent workflows
Onboard a new signup:
Create a welcome sequence:
Tag and segment high-value users:
Troubleshooting
"Missing or invalid API key" — Check that your Authorization header starts with Bearer mk_.
"X-Project-Id header is required" — Add the X-Project-Id header with your numeric project ID.
"Contact not found" / "Campaign not found" — The resource either doesn't exist or belongs to a different project than the one in your header.
"Plan limit reached" — You have hit your daily email send limit. It resets at midnight UTC.
Rate limit errors — The server allows 30 requests per minute. Add delays between bulk operations.
