MCP server
anymail runs a remote Model Context Protocol server. An LLM client can read and update your workspace through tools. After this page your client is connected and you know which tools it can call.
| Endpoint | https://app.anymail.watch/api/mcp |
| Transport | MCP Streamable HTTP, stateless, with JSON responses |
| Methods | POST for JSON-RPC, DELETE (accepted, no effect). GET returns 405. |
| Authentication | Authorization: Bearer sgn_…, the same API token as the REST API |
| Server info | name seegnals, version 1.0.0 |
Every tool calls one endpoint of the REST API on the same origin with the token you connected with. The server can do exactly what the REST API allows. The validation, the workspace isolation and the rate limit are the same.
Connect a client#
Generate a token first. See Authentication.
Claude Code#
claude mcp add --transport http anymail https://app.anymail.watch/api/mcp \
--header "Authorization: Bearer $ANYMAIL_TOKEN"
Then run /mcp in Claude Code. It lists the server as connected and shows the tools.
Claude Desktop#
The Add custom connector dialog of Claude Desktop supports only OAuth-secured servers, and this server uses a static Bearer token. Bridge it with mcp-remote in claude_desktop_config.json.
{
"mcpServers": {
"anymail": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://app.anymail.watch/api/mcp",
"--header", "Authorization: Bearer sgn_…"
]
}
}
}
Cursor#
Add the server to .cursor/mcp.json in a project, or to ~/.cursor/mcp.json for all projects.
{
"mcpServers": {
"anymail": {
"url": "https://app.anymail.watch/api/mcp",
"headers": { "Authorization": "Bearer sgn_…" }
}
}
}
Another client#
A client that supports Streamable HTTP with custom headers uses the same shape.
{
"mcpServers": {
"anymail": {
"type": "http",
"url": "https://app.anymail.watch/api/mcp",
"headers": { "Authorization": "Bearer sgn_…" }
}
}
}
Raw protocol#
To debug, call the server with curl. The transport requires the Accept header.
curl -s "https://app.anymail.watch/api/mcp" \
-H "Authorization: Bearer $ANYMAIL_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Call a tool with tools/call.
curl -s "https://app.anymail.watch/api/mcp" \
-H "Authorization: Bearer $ANYMAIL_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"add_suppression","arguments":{"target":"example.com"}}}'
The server is stateless. A client does not need to call initialize first, the server issues no Mcp-Session-Id and each HTTP request is complete on its own.
Tools#
The server has 23 tools. Each tool returns the JSON of the REST API as formatted text in content[0].text. When the response is a JSON object, the tool also returns it as structuredContent. The server validates the arguments (required fields, enum values, types) before it makes any HTTP call.
Write tools#
| Tool | Calls | Arguments |
|---|---|---|
create_prospect |
POST /prospects |
email (required), first_name, last_name, timezone, company_name, custom_fields, campaign_id |
update_prospect |
PATCH /prospects/{id} |
id and email (required), first_name, last_name, timezone, company_name, custom_fields |
add_suppression |
POST /suppressions |
target (required) |
create_webhook |
POST /hooks |
event and target_url (required) |
delete_webhook |
DELETE /hooks/{id} |
id |
enrol_prospects |
POST /campaigns/{id}/prospects |
id, and one of prospect_ids or emails (1 to 200 items) |
pause_campaign |
POST /campaigns/{id}/pause |
id |
resume_campaign |
POST /campaigns/{id}/resume |
id |
classify_reply |
PATCH /replies/{id} |
id, classification (interested, neutral or not_interested) |
delete_suppression |
DELETE /suppressions/{id} |
id |
create_prospect with campaign_id creates the prospect and enrols it in one call. An unknown or unusable campaign returns an error before anything is created. update_prospect follows the rules of PATCH /prospects/{id}: send the full desired state. delete_webhook returns the text Done (HTTP 204, no content). with structuredContent of {"ok": true, "status": 204}.
Read tools#
These tools carry the readOnlyHint: true annotation. They take the same parameters as the endpoints, including limit and cursor.
| Tool | Calls | Arguments |
|---|---|---|
list_prospects |
GET /prospects |
email, company_id, status, created_since, limit, cursor |
get_prospect |
GET /prospects/{id} |
id |
list_campaigns |
GET /campaigns |
status, folder_id, archived, limit, cursor |
get_campaign |
GET /campaigns/{id} |
id |
list_campaign_prospects |
GET /campaigns/{id}/prospects |
id, status, limit, cursor |
list_companies |
GET /companies |
search, temperature, limit, cursor |
get_company |
GET /companies/{id} |
id |
list_replies |
GET /replies |
classification, since, campaign_id, prospect_id, limit, cursor |
list_offers |
GET /offers |
status, prospect_id, campaign_id, limit, cursor |
get_offer |
GET /offers/{id} |
id |
list_suppressions |
GET /suppressions |
kind, limit, cursor |
list_webhooks |
GET /hooks |
limit, cursor |
list_mailboxes |
GET /mailboxes |
None |
Errors#
| Situation | What the client sees |
|---|---|
| No header, or a malformed or revoked token | HTTP 401 with JSON {"error":"…"} and WWW-Authenticate: Bearer realm="anymail API". |
| Rate limit exceeded | HTTP 429 with Retry-After in seconds. |
| Token check impossible because of a database outage | HTTP 500 with {"error":"Authentication is temporarily unavailable."}. |
GET /api/mcp |
HTTP 405 with Allow: POST, DELETE. |
| Missing or invalid tool arguments | A tool result with isError: true that explains the problem. The server makes no HTTP call. |
The REST API answers 4xx or 5xx |
A tool result with isError: true and the text HTTP <status> from <METHOD> <path>: <API message> (code: <code>). A 429 adds Retry after N seconds. |
| The REST API cannot be reached, or it times out | A tool result with isError: true that says the API could not be reached. |
A tool failure is always a tool result and never a JSON-RPC protocol error, so the model can read the message and correct its input.
Limits#
- Rate limit. The REST API allows 60 requests per minute per token. One tool call uses two requests: the MCP request is authenticated with the same limiter, and the proxied REST call is the second. Plan for about 30 tool calls per minute per token.
tools/listcosts one request. - Request bodies. Prospects up to 64 KiB. Suppressions, hooks and reply classifications up to 4 KiB, as in the REST API.
- Timeout. A proxied REST call stops after 20 seconds and returns a tool error.
- No sessions. The server has no sessions, no resumability and no server-initiated notifications.
- No resources or prompts. The server offers tools only.
- Same reach as the REST API. The server cannot create campaigns, edit steps, start a draft or delete prospects.