Use Cold Leads from Cursor, Claude Desktop and Windsurf over MCP
- Who it is for
- Developers who use AI assistants in Cursor, Claude Desktop or Windsurf
- The problem
- Copying addresses between an assistant, a CRM and a verification tool is slow and error-prone, and an assistant asked for contacts will happily make some up.
- The solution
- Connect the Cold Leads MCP server once. An assistant can work with contacts already in your workspace, import structured rows from a user-provided file, read synced conversations, maintain templates and campaign drafts, and set up website lead forms. Sending remains behind explicit user confirmation and Cold Leads' consent, unsubscribe, DNC, content and account safeguards.
- What you get
- An assistant that works with your own contact data, inbox and outreach drafts through MCP or the Node SDK, while keeping each website enquiry and outreach consent status distinct.
Addresses, IDs and results in the examples are illustrative. example.com is reserved for documentation, so a real check of these addresses returns invalid.
What the server offers
| Tool | What it does | Cost |
|---|---|---|
| search_leads | Contacts already in your Cold Leads CRM at a company domain (subdomains included), with an optional role keyword matched against name, e-mail local part, tags, notes and contact type. Returns e-mail, name, company, phone, stage, tags, verification and do_not_contact. | Free |
| verify_email | Syntax, disposable-domain, role-account and MX checks, plus the SMTP mailbox and accept-all probe when Cold Leads can open an SMTP connection to the recipient's mail server. Returns validity, score, reasons, catch_all, disposable and role_account. | 1 credit |
| CRM, inbox, templates, campaigns, workspace and website tools | list_contacts/import_contacts/update_contact manage your workspace (imports accept up to 100 structured rows, deduplicate and skip global DNC; uploaded CSV/XLSX is parsed by the assistant). get_conversation reads synced messages; send_contact_message sends one only after approval. list_templates/save_template manage templates. list_campaigns/create_campaign_draft/launch_campaign support reviewed, confirmed campaigns. get_workspace_info and setup_website_lead_capture expose non-secret settings and public-only lead-form setup. Website signups are inquiry, not automatic cold-outreach consent. | Free; sending follows account limits |
| provision_account_and_get_payment_link, check_provisioning_status | Onboarding without a key: a Stripe payment link for the human owner, then the API key once. Only in the local server. | No credits |
Cold Leads has no third-party database of people or companies. MCP operations access only the authenticated workspace. Uploaded files must be parsed into structured contact rows before import; the server does not receive or store the original file. Website submissions use inquiry status. Verification does not establish permission to contact. Bulk campaigns remain drafts until the human approves launch.
- Local server (stdio): npx -y --allow-git=root github:anttka4cz/mcp-server-coldleads with COLDLEADS_API_KEY in its environment. It is not published on npm; npx installs it from GitHub. It needs Node.js 20 or newer. npm 12 blocks installs from git unless you allow them, which --allow-git=root does for this command; npm 10 accepts the flag too.
- Hosted endpoint: https://coldleads.app/api/mcp, MCP Streamable HTTP (JSON-RPC 2.0 over POST, protocol versions 2024-11-05 to 2025-11-25). Use a secret API key or connect ChatGPT with OAuth. It offers contact import and management, conversation reading and confirmed single-message sending, template and campaign draft management, confirmed campaign launch, workspace info, website lead-form setup, lead search and e-mail verification.
- The key is a secret key (sk_…) from Settings → API keys. The API, and with it MCP, is part of the Business plan.
Cursor
Put the server in ~/.cursor/mcp.json to use it in every project, or in .cursor/mcp.json inside one project. The local server:
{
"mcpServers": {
"coldleads": {
"command": "npx",
"args": ["-y", "--allow-git=root", "github:anttka4cz/mcp-server-coldleads"],
"env": { "COLDLEADS_API_KEY": "sk_your_secret_key" }
}
}
}Cursor also connects to remote servers with custom headers, so the hosted endpoint works without Node.js. Cursor resolves ${env:NAME} in url and headers, which keeps the key out of the file:
{
"mcpServers": {
"coldleads": {
"url": "https://coldleads.app/api/mcp",
"headers": { "Authorization": "Bearer ${env:COLDLEADS_API_KEY}" }
}
}
}Claude Desktop
- Open the Claude menu in the system menu bar (not the settings inside the chat window), choose Settings…, open the Developer tab and click Edit Config.
- The file is ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows. Add the block below and save.
- Quit Claude Desktop completely and start it again; it loads MCP servers only at start-up.
{
"mcpServers": {
"coldleads": {
"command": "npx",
"args": ["-y", "--allow-git=root", "github:anttka4cz/mcp-server-coldleads"],
"env": { "COLDLEADS_API_KEY": "sk_your_secret_key" }
}
}
}Claude Desktop starts local servers from this file. Remote servers are added as connectors in the app settings instead, and sending an API key header from a connector is a beta that only some organizations have, so the local server is the route that works for everyone.
Windsurf (Devin Desktop) and Claude Code
Windsurf became Devin Desktop on June 2, 2026. In the Cascade panel, open the … (Actions) menu at the top right and click Open MCP config file in the MCPs section, then add the same mcpServers block as for Cursor (the local server) and save. Devin's documentation names ~/.config/devin/mcp_config.json (%APPDATA%\devin\mcp_config.json on Windows) for this file; Windsurf releases before the rename read ~/.codeium/windsurf/mcp_config.json. Remote servers take a url (or serverUrl) with headers:
{
"mcpServers": {
"coldleads": {
"url": "https://coldleads.app/api/mcp",
"headers": { "Authorization": "Bearer sk_your_secret_key" }
}
}
}In Claude Code, add either variant from the terminal:
# local stdio server (Node.js 20 or newer)
claude mcp add --env COLDLEADS_API_KEY=sk_your_secret_key --transport stdio coldleads -- npx -y --allow-git=root github:anttka4cz/mcp-server-coldleads
# or the hosted endpoint
claude mcp add --transport http coldleads https://coldleads.app/api/mcp --header "Authorization: Bearer sk_your_secret_key"Prompts that match the real tools
- Search my Cold Leads CRM for contacts at example.com tagged cto and verify their addresses. (search_leads with domain example.com and role cto, then verify_email for each lead without do_not_contact: 1 credit per address.)
- Which of my Cold Leads contacts at example.com are marked do_not_contact? (search_leads only, free.)
- Verify anna@example.com and tell me whether the mailbox itself was checked. (verify_email; the answer is in reasons: ok means a mail server accepted the mailbox, smtp_unreachable means it was not checked.)
- Check these five addresses and sort them into send, review and drop by their reason codes. (verify_email five times, 5 credits.)
- Import these rows as website enquiries, deduplicate them and report skipped rows. (import_contacts with consent inquiry; no messages are sent.)
- Show me the conversation with this contact and draft a reply. Wait for me to approve the recipient and final text before sending. (get_conversation, then send_contact_message only after explicit approval.)
- Create a campaign draft from template tpl_123 for inquiry contacts tagged webinar, show its audience estimate and wait for my approval before launch. (create_campaign_draft, then launch_campaign only after review and confirmation.)
- Set up a website contact form for example.com and give me the snippet. (setup_website_lead_capture returns a publishable form key; submissions are inquiry leads.)
- With the local server and no key yet: set up Cold Leads for owner@example.com. (provision_account_and_get_payment_link returns a payment link that you, the human, decide on.)
The role keyword is matched against name, e-mail local part, tags, notes and contact type; Cold Leads has no job-title field. Tag contacts with their role (cto, ceo, sales) if you want role searches to work. Tool results come back as compact JSON:
{
"status": "success",
"domain": "example.com",
"count": 1,
"source": "crm",
"leads": [
{
"email": "jan.novak@example.com",
"name": "Jan Novák",
"company": "Acme",
"stage": "lead",
"tags": ["cto"],
"verification": { "status": "valid", "score": 75 },
"do_not_contact": false
}
]
}{
"status": "success",
"email": "jan.novak@example.com",
"validity": "valid",
"catch_all": null,
"score": 75,
"reasons": ["smtp_unreachable"],
"disposable": false,
"role_account": false
}Check the hosted endpoint from a terminal
The endpoint is stateless, so a single POST works without an initialize handshake. This is also a quick way to confirm that a key is valid and belongs to a Business account.
# list the tools of the hosted endpoint (free; counts toward 120 requests per minute)
curl -s https://coldleads.app/api/mcp \
-H "Authorization: Bearer $COLDLEADS_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# call verify_email once (1 credit)
curl -s https://coldleads.app/api/mcp \
-H "Authorization: Bearer $COLDLEADS_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"verify_email","arguments":{"email":"anna@example.com"}}}'Limits and costs
- search_leads is free and returns up to 50 contacts per call (10 by default).
- verify_email costs 1 credit per call, including results served from the 30-day cache. It answers in about 5 seconds: the hosted endpoint gives each check a 4.5-second budget and the local server asks for 4 seconds. When the budget runs out, the result is risky with the reason timeout and is not cached; POST /api/v1/verify accepts a timeout_ms of up to 30,000 for a longer check.
- Every request to the hosted endpoint, including initialize and tools/list, counts toward the key's 120 requests per minute. The local server calls the API only for tool calls.
- The Business plan costs $99 a month and includes 10,000 credits a month; extra packs of 1,000 credits cost $5.
FAQ
Can the assistant find new people at a company?
No. Cold Leads has no people or company database. search_leads covers only the contacts in your own Cold Leads workspace. For a name you already know, POST /api/v1/find returns the most likely address, labelled pattern unless a mail server confirmed the mailbox.
Local server or hosted endpoint?
The local server works in every client that can start a command and also handles onboarding without a key. The hosted endpoint needs no Node.js but only works in clients that can send a custom Authorization header. Both run the same checks.
Why is catch_all null?
catch_all is only known when a mail server answered the probe, which shows as a last reason of ok, catch_all or mailbox_missing. Otherwise both the hosted endpoint and the local server return null: accept-all was not tested, so read reasons for what was checked.
Where does my key go?
Into the env block or header of your local MCP configuration. The server sends it to coldleads.app as Authorization: Bearer. Do not paste it into a chat, and rotate it in Settings → API keys if it leaks.