ColdSend MCP Server
AI-Native Email Campaign Management via Model Context Protocol
ColdSend MCP Server enables AI assistants like Claude Desktop, Claude Code, Cursor IDE, Windsurf, OpenCode, and other MCP-compatible clients to manage cold email campaigns through natural language.
The server supports dual transport — Streamable HTTP (modern, recommended) and SSE (legacy, deprecated). Always prefer Streamable HTTP unless your client cannot use it.
Installation
pip install coldsend-mcp-server
Quick Start
You only need your ColdSend API key to get started.
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"coldsend": {
"command": "coldsend-mcp",
"env": {
"X-API-Key": "your-coldsend-api-key"
}
}
}
}
Claude Code
claude mcp add coldsend https://mcp.coldsend.pro/mcp -t http -e X-API-Key=your-api-key
Cursor IDE / Windsurf
- Open Settings -> MCP
- Add new MCP server:
- Name:
ColdSend - Type:
http(Streamable HTTP) - URL:
https://mcp.coldsend.pro/mcp - Headers:
X-API-Key: your-api-key
- Name:
OpenCode
Add to your opencode.jsonc:
{
"mcp": {
"coldsend": {
"type": "remote",
"url": "https://mcp.coldsend.pro/mcp",
"enabled": true,
"headers": {
"X-API-Key": "{env:COLDSEND_API_KEY}"
}
}
}
}
Remote Server (No Installation Required)
You can connect directly to the hosted server without installing anything. Two transport endpoints are available:
| Transport | URL | Use With |
|---|---|---|
| Streamable HTTP | https://mcp.coldsend.pro/mcp |
Claude Code, Cursor, VS Code, Smithery, OpenCode — recommended |
| SSE (legacy, deprecated) | https://mcp.coldsend.pro/sse |
Older clients that cannot speak Streamable HTTP |
Header: X-API-Key: your-api-key
⚠️ Troubleshooting: If your client experiences timeouts, stuck sessions, or tools that never return on the SSE endpoint, switch to Streamable HTTP (
/mcp). SSE sessions are long-lived and can drop silently on unstable networks.
Available Tools
Campaign Management
| Tool | Description |
|---|---|
campaigns.create |
Create a new email campaign |
campaigns.list |
List all campaigns with filtering |
campaigns.get |
Get specific campaign details |
campaigns.update |
Update campaign configuration |
campaigns.pause |
Pause an active campaign |
campaigns.resume |
Resume a paused campaign |
campaigns.archive |
Archive a paused or completed campaign (one-way; deletion is the only way out) |
campaigns.delete |
Delete a campaign permanently |
Lead Management
| Tool | Description |
|---|---|
leads.upload |
Upload leads from CSV file |
leads.upload_progress |
Check CSV upload job progress |
leads.add_manual |
Add leads manually with custom data |
leads.list |
List leads in a campaign with filtering |
leads.get |
Get specific lead details |
leads.update |
Update lead data |
leads.delete |
Remove leads from campaign |
leads.export |
Export leads as CSV |
Analytics
| Tool | Description |
|---|---|
analytics.campaign |
Campaign performance analytics |
analytics.timeline |
Timeline-based campaign analytics |
analytics.ctr |
Click-through rate for a campaign |
analytics.ctr.links |
Per-link click breakdown |
Per-branch analytics live with the flow tools: see analytics.subsequences.
Contact Directory
Contacts are the team-wide people of record, independent of any campaign. A lead is one campaign membership of a contact, so the same person can appear as several leads while remaining one contact.
| Tool | Description |
|---|---|
contacts.list |
Search the directory by signal, source, campaign, list and engagement |
contacts.get |
Get one contact with its cross-campaign history and suppression state |
contacts.import |
Import contacts from CSV, upserting team-wide by email |
contacts.update |
Patch profile fields and merge custom fields |
contacts.set_signal |
Pin or clear a contact's engagement signal |
contacts.delete |
Delete contacts from the directory |
contacts.add_tag |
Tag contacts |
contacts.remove_tag |
Untag contacts |
contacts.add_to_list |
Add contacts to a saved segment |
contacts.add_to_campaign |
Enrol contacts in a campaign (creates leads) |
contacts.send_email |
Send a campaign-less 1:1 email to a contact — costs 1 credit |
contact_lists.list |
List saved segments |
contact_lists.create |
Create a static or dynamic saved segment |
contact_lists.preview |
Preview a filter before saving it |
contact_lists.get |
Get one saved segment |
contact_lists.update |
Rename, re-describe or re-filter a saved segment |
contact_lists.delete |
Delete a saved segment (contacts are untouched) |
contacts.send_email takes from_email as an address and resolves it to an inbox itself. If nothing matches it returns a sender_not_found error listing the ACTIVE addresses your key can see, so the call can be corrected rather than retried blindly. Requires the contacts:send_email scope (included in contacts:all).
Flow & Subsequences
A campaign's flow is its step graph: the linear MAIN follow-up chain every lead walks, plus any subsequence branches that pull a lead off it when a trigger fires.
| Tool | Description |
|---|---|
flow.get |
Read the full graph — nodes, edges and subsequences_enabled |
subsequences.create |
Create a branch: an entry trigger plus an ordered chain of steps |
subsequences.update |
Partially update a branch (trigger, label, priority, active, steps) |
subsequences.delete |
Delete a branch and every step in it |
leads.move_to_subsequence |
Move leads into a branch by hand, invalidating their pending MAIN follow-ups |
leads.journey |
Trace one lead's path through the graph, including branch emails |
analytics.subsequences |
Per-branch enrollment, completion and engagement analytics |
Two things worth knowing before you build a branch:
- Branch entry
trigger_typeisINTENT_TAG,KEYWORDorSTATUS. TheNOT_OPENED/NOT_REPLIED/OPENED_BUT_NOT_REPLIEDvalues thatcampaigns.updatetakes are MAIN-chain conditions and are rejected here. - Branch steps use
wait_seconds, not thewait_daysMAIN sequences use, and their between-stepcondition_typeshould stayALWAYS— a branch is entered because something happened, so a negative condition can never be satisfied.
campaigns.update manages the MAIN chain only and never touches branches.
Domain Management
| Tool | Description |
|---|---|
domains.list |
List all domains with status |
domains.get |
Get domain details with DNS records |
domains.add |
Add new domain for verification |
domains.progress |
Check domain activation progress |
domains.activate |
Activate domain after DNS setup |
domains.get_redirect |
Get domain redirect configuration |
domains.set_redirect |
Configure domain redirect rules |
domains.delete_redirect |
Remove domain redirect |
domains.delete |
Delete domain permanently |
Sender Account Management
| Tool | Description |
|---|---|
sender.list |
List all sender inboxes |
sender.get |
Get sender account details |
sender.quotas |
Get inbox sending quotas |
sender.daily_usage |
Get daily usage statistics |
sender.create_coldsend |
Create ColdSend native inbox |
sender.create_smtp |
Create custom SMTP inbox (BYOC) |
sender.test |
Send test email |
sender.delete |
Delete inbox permanently |
sender.bulk_create_coldsend |
Bulk create ColdSend inboxes |
sender.bulk_create_coldsend_progress |
Check bulk ColdSend creation progress |
sender.bulk_create_smtp |
Bulk create SMTP inboxes |
sender.bulk_smtp_progress |
Check bulk SMTP creation progress |
sender.bulk_delete |
Bulk delete sender accounts |
sender.bulk_delete_progress |
Check bulk delete progress |
Reply Management
| Tool | Description |
|---|---|
replies.list |
List reply conversations |
replies.thread |
Get reply thread details |
replies.messages |
Get messages in a thread |
replies.send |
Send reply to a thread |
replies.mark_read |
Mark thread as read |
replies.toggle_star |
Star/unstar a thread |
Example Interactions
Creating a Campaign:
Create a new campaign called "Q1 Outreach" starting January 15th with a daily limit of 100 emails.
Checking Performance:
How is my Q1 Outreach campaign performing?
Uploading Leads:
Upload these leads to my Q1 Outreach campaign: [paste CSV]
Managing Domains:
Add the domain outreach.acme.com and show me the DNS records I need to configure.
Inbox Health:
Check the health of all my sender inboxes and flag any issues.
Managing Replies:
Show me all unread reply threads from my Q1 Outreach campaign.
Sending Replies:
Reply to the thread from john@acme.com saying "Thanks for your interest, let's schedule a call."
Bulk Inbox Creation:
Create 5 ColdSend inboxes on my domain example.com with prefixes sales1 through sales5.
Sending a Direct Email:
Email jane@acme.com from founder@mycompany.com saying "Thanks for the note — here's the deck you asked for."
Building a Branch:
On my Q1 Outreach campaign, anyone who replies with "pricing" or "how much" should get a two-email pricing sequence, two days apart.
Diagnosing a Lead:
Why has the lead from john@acme.com gone quiet in Q1 Outreach? Show me their journey.
Authentication
The MCP server uses API key authentication. Pass your ColdSend API key via the X-API-Key header — the server forwards it securely to the ColdSend API.
Get your API key from your ColdSend dashboard.
Smithery
This server is also available on Smithery if you prefer to use it from there.
Transport Endpoints
The server exposes two transport protocols on different paths:
| Path | Transport | Description |
|---|---|---|
/mcp |
Streamable HTTP | Modern MCP transport (recommended, stateless) |
/sse |
SSE | Legacy transport for older clients (deprecated; kept alive by periodic pings) |
/messages |
SSE POST | Message endpoint for SSE transport |
/health |
HTTP GET | Health check for Kubernetes probes |
/ |
HTTP GET | Service info with transport discovery |
Configuration
The server works out of the box with sensible defaults. All configuration is optional:
| Environment Variable | Default | Description |
|---|---|---|
COLDSEND_API_URL |
https://api.coldsend.pro/api/public/v1 |
ColdSend API endpoint |
MCP_PORT |
8080 |
Server port |
SSE_PING_INTERVAL |
15.0 |
Seconds between keepalive pings on legacy SSE streams |
LOG_LEVEL |
INFO |
Logging level |
Requirements
- Python 3.11+
Links
- Website: coldsend.pro
- API Docs: docs.coldsend.pro
- Support: support@coldsend.pro
License
MIT License - see LICENSE for details.
Built with Model Context Protocol by the ColdSend Team
Metadata
Release files for coldsend-mcp-server 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| coldsend_mcp_server-0.2.2.tar.gz | 75.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| coldsend_mcp_server-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 139.5 kB
Release files / coldsend_mcp_server-0.2.2.tar.gz
| Download URL | coldsend_mcp_server-0.2.2.tar.gz |
|---|---|
| Size | 75.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bacb661d615f4e40f1e7feb01b58886fc56815f1c06b579ce794bf9047c38bcf
|
|
BLAKE2b-256 checksum How to use checksums |
57d765cc92a8eddb6392341819804f18fafeda2a5d8e472361afc10f9c499f51
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.11
|
Release files / coldsend_mcp_server-0.2.2-py3-none-any.whl
| Download URL | coldsend_mcp_server-0.2.2-py3-none-any.whl |
|---|---|
| Size | 64.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c77c2e26909936d1a3862abdacc305d489e72679b9f0603325d88d6de8a9531
|
|
BLAKE2b-256 checksum How to use checksums |
3c0587670ed439df518562188f796a78281ce4f704f5200471d25b18e02461b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.11
|