MCP server
45 tools over the same REST API, for any client that speaks MCP.
The MCP server is the REST API with names an agent can reach for. It runs remotely at https://mcp.sendraven.ai/mcp over Streamable HTTP, holds no database or provider credentials of its own, and can reach exactly what the key behind it can reach. Every tool is a call to a /v1 endpoint, so the scopes, daily cap, allowlist and approval hold on that key apply unchanged.
Install
Claude Code takes one line. The first tool call opens a browser to sign in and pick a workspace.
claude mcp add --transport http sendraven https://mcp.sendraven.ai/mcpCursor, Claude Desktop and other clients with a JSON config point at the same URL. A client that supports OAuth prompts you to authorize on first use.
{
"mcpServers": {
"sendraven": {
"url": "https://mcp.sendraven.ai/mcp"
}
}
}Signing in, or pasting a key
initialize and tools/list are answered without credentials, so a client or registry can see what is there before anyone signs in. The first tools/call without a token returns 401 with a WWW-Authenticate header pointing at the OAuth metadata, which is what starts the sign-in flow in a client that supports one.
A client that does not, or an agent running unattended, sends an API key instead — Authorization: Bearer sk_live_… as a header on every request. Create the key in the dashboard under Developers.
{
"mcpServers": {
"sendraven": {
"url": "https://mcp.sendraven.ai/mcp",
"headers": { "Authorization": "Bearer sk_live_…" }
}
}
}Running it locally
The same server is published to npm as @sendraven/mcp for a client that launches it as a subprocess. It speaks stdio when no PORT is set and takes the key from SENDRAVEN_API_KEY; SENDRAVEN_API_URL overrides the API base.
Over stdio the key comes from the environment because there is one user per process. Over HTTP it only ever comes from the request — reading it from the environment there would hand one caller another's workspace.
claude mcp add sendraven -e SENDRAVEN_API_KEY=sk_live_… -- npx -y @sendraven/mcpTools
Descriptions say which tool to reach for and what it costs to get wrong. A failed call returns the API's own message with its HTTP status, so "domain not verified" arrives as those words rather than a bare 403.
| Group | Tools |
|---|---|
| Send and read | send_email, send_template_email, reply_to_message, list_emails, get_email, list_scheduled_emails, cancel_scheduled_email |
| Threads | list_threads, get_thread |
| Approvals | list_pending_approvals, decide_approval |
| Sending domains | list_sending_domains, add_sending_domain, verify_sending_domain |
| Suppressions | list_suppressions, add_suppression, remove_suppression, suppress_many |
| Templates | list_templates, render_template |
| Campaigns | list_broadcasts, preview_broadcast, send_broadcast, list_broadcast_recipients |
| Automations | list_automations, enroll_in_automation, emit_event |
| Topics | list_topics, get_email_preferences, set_email_preferences |
| Contacts and audiences | list_audiences, add_contact, get_contact, find_contact, update_contact, delete_contact, remove_from_audience, tag_contact, list_tags, list_segments, count_segment |
| Operations | get_email_metrics, list_webhook_deliveries, list_api_keys, get_usage |
Three behaviours worth knowing
A held send is not a failure. When the key requires approval, send_email returns status: "pending_approval" with an approval_id. The message is waiting in list_pending_approvals for a person; there is nothing to retry, and retrying queues a second draft. decide_approval exists so a human can say which way to go — the hold is there precisely so that an agent is not the one deciding.
Out of plan is 402, not 429. A send that would cross the plan's included allowance returns 402 plan_limit_reached. It is not a rate limit, and a client that backs off and retries on 429 would retry this forever. get_usage reports the plan, what has been sent this month and what remains, so an agent can say "you are near your limit" before a batch instead of surfacing a payment error after it.
Two calls cannot be undone. send_broadcast mails an entire audience and cannot be recalled once started — run preview_broadcast first, which returns the recipient count and whether the reputation gate will allow it. remove_suppression lets us mail an address that hard bounced or reported spam, which raises exactly the rates that gate enforces. Neither is a way to fix a failed send.
Next: Templates