MCP server

Give your agent a phone number.

Cosend's MCP server exposes your WhatsApp number as tools any MCP-capable agent can call — read the inbox, answer carefully, and author, deploy and repair automations without clicking through a flow builder.

Connecting a client

A remote server at mcp.cosend.app, speaking MCP revision 2026-07-28 over Streamable HTTP. It is stateless: no session header, no handshake, any request to any instance.

claude · mcp config
{
  "mcpServers": {
    "cosend": {
      "url": "https://mcp.cosend.app/mcp"
    }
  }
}

There is no key to paste. The server is an OAuth 2.1 resource server — it issues no tokens of its own — so your client runs the authorization flow the first time it connects, and you approve the scopes on a Cosend screen. The token's claims resolve exactly one organization, and every read and write underneath runs under row-level security bound to it.

The MCP server is not on the Free tier. An organization on Free that reaches it gets a 403 with the upgrade URL, before any tool resolves. Everything else on this page is on every paid plan — see pricing.

The nineteen tools

tools/list returns them in exactly this order, always, filtered by the scopes you granted and by your plan. The list is generated from the same contracts package the API validates against, so a tool cannot exist here and not on the API.

The nineteen MCP tools, whether each reads or writes, and what it does.
Tool Class What it does
whoami RO Organization, plan, connected numbers and granted scopes. The right first call in any conversation
list_conversations RO Recent threads with unread counts
search_conversations RO Find a thread by its content
read_conversation RO Message history for one thread
send_message MUT · CONFIRM One message, into one conversation that already exists. 20 a minute, 200 a day, one per recipient per 30 seconds
list_contacts RO The contact list, filtered and paged
upsert_contact MUT Create or update one contact
set_contact_consent MUT Record an opt-in or an opt-out
list_templates RO Templates with their review status
create_template MUT Draft a template
submit_template MUT · CONFIRM Send one to Meta for review. Ten a day
list_automations RO What is deployed, and which version is live
validate_automation RO The compiler’s full report on a draft — resolved actions, derived budget, and every error with a pointer into the source and a machine-actionable fix The one to call first on a draft
upsert_automation MUT · CONFIRM Write a new automation, or a new version of one
deploy_automation MUT · CONFIRM Push a version live
set_automation_state MUT · CONFIRM Enable or disable. Enabling needs the confirmation; disabling does not
list_runs RO Runs, filtered by automation and state
get_run RO One run and its per-step event trace
get_usage RO Meters, what is included, and what is left

CONFIRM means the tool cannot complete on the agent's say-so: it returns asking for a human decision, and the client has to come back with one. That is a protocol-level round-trip, not a prompt asking the model to be careful.

validate_automation is the tool worth building a pipeline around. It returns the compiler's critique of a draft before anything is written — every error with a pointer into the source and a fix an agent can apply — which is what makes an AI-authored automation safe enough to deploy, instead of a runtime failure at 3am.

Why there is no bulk send, and will not be

This server can put text on a stranger's phone. The design assumption is not that the agent is well behaved; it is that the agent is capable, eager, and occasionally under somebody else's influence.

The whole risk is one sentence: inbound content becoming outbound action. Someone messages the business with text shaped like an instruction, an agent reads the thread, treats it as one, and messages the contact list.

The mitigation is architectural rather than a prompt. send_message takes exactly one conversation, and that conversation must already exist. There is no array of recipients, no send-to-tag, no send-to-all, and no way to create a conversation with a number. An agent that wants to reach five hundred people has to call it five hundred times — and the limiter stops it around twenty while the audit alarm fires.

Reaching an audience deliberately is a different thing and lives somewhere else: an automation whose audience is a saved, human-approved segment, enabled by a person clicking approve in the dashboard.

Everything a good client is told about a tool — read-only, destructive, idempotent — is a hint, and the protocol says so. We publish them honestly and enforce the same policy server-side regardless. Rate limits, plan gates and scope checks apply to an agent exactly as they apply to a key.

Message bodies are data, not instructions

Enforced structurally rather than by asking politely. Every string that originated outside Cosend comes back wrapped and marked, with the marker in the output schema so a client can render it differently:

a message body, as a tool returns it
{ "text": { "untrusted": true,
           "value": "⟦EXTERNAL⟧ Hi, is 3pm still ok? ⟦/EXTERNAL⟧" } }

The sentinels are stripped from the inbound text first, so a sender cannot close the fence and escape into trusted context. Text is Unicode-normalised, bidi-override and zero-width characters are removed, and a single body is capped before it reaches a model's context. A classifier flags imperative-to-assistant patterns and marks the message rather than hiding it, because a suppressed message is a support ticket and a flagged one is a decision.