MCP server
Point an assistant at Rasket and it can set your account up and run it — add and verify a domain, wire a webhook, write a template, send, and follow what happened — on your behalf, without anyone pasting an API key into a desktop app. That is a trust decision before it is an integration, so this page starts there.
The boundary
A connected app never gets a key. It gets an OAuth access token, issued for one team, carrying only the scopes you approved on the consent screen, and you can revoke it from Connected apps at any moment.
The scopes you approve decide which tools exist. A grant without domains:write is not a server that refuses create_domain — it is a server that does not have one.
Two scopes reach further than their names suggest, so read them before approving. emails:read can cancel a scheduled send, because cancelling only ever prevents mail. team:write can turn AI assist on, which decides whether content you ask about is sent to the AI provider.
What it may never do
These are not tools that refuse. They are tools that do not exist.
- Mint, change or revoke an API key, or manage the grants it is itself using.
- Change your plan, your billing, or who is on your team.
- Delete anything — a domain, a webhook, a template, a segment, a broadcast, an automation — or erase a contact.
- Remove a suppression — an unsubscribe stays an unsubscribe, whoever is asking.
- Regenerate a domain's DKIM keys, rotate a webhook's signing secret, or take a registrar credential.
No scope reaches them either, so there is no consent screen anywhere that could hand them over. See Authentication for how the scopes and the API-key permissions relate.
Seven toolsets
74 tools, grouped so a client can load only the ones it needs. Every call goes through the same service the dashboard and the API use, so every rule applies unchanged. A refusal comes back as a tool result marked isError, carrying the error name the API would have answered with — so the assistant can read it and tell you which address unsubscribed, rather than reporting that something broke.
Every list takes limit (at most 25) and after. An html body over 4 KB is left out of what a tool returns, and a sent or received message's HTML is never returned at all.
Setup · setup · 23
Add and verify a domain, name the sender, wire webhooks, write templates.
| Tool | Scope | What it does |
|---|---|---|
get_team | team:read | The team's plan, sender identity, AI assist and single sign-on status. |
update_team | team:write | Set the sender name and postal address a broadcast needs, or turn AI assist on or off. |
list_domains | domains:read | Your domains, their region and whether they may send. |
get_domain_status | domains:read | One domain: every DNS record, its status, and why a failing one failed. |
get_domain_records | domains:read | The records to publish at the DNS host, exactly as it needs them. |
create_domain | domains:write | Add a domain; the answer carries the records to publish. |
verify_domain | domains:write | Look the records up now rather than at the next scheduled check. |
update_domain | domains:write | Change tracking, TLS or a domain's capabilities. |
claim_domain | domains:write | Start a claim on a name another team verified. It completes by itself once the TXT record resolves. |
list_webhooks | webhooks:read | Your endpoints and the events each receives. |
get_webhook | webhooks:read | One endpoint, with its status and delivery health. |
list_webhook_events | webhooks:read | The events created for one endpoint, with their delivery state. |
list_parked_events | webhooks:read | The events held while an endpoint was disabled. |
create_webhook | webhooks:write | Add an endpoint. The answer carries its signing secret, once. |
update_webhook | webhooks:write | Change an endpoint's URL or events, or enable or disable it. |
replay_webhook_event | webhooks:write | Deliver one past event to its endpoint again. |
deliver_parked_events | webhooks:write | Deliver the events parked on an endpoint, oldest first. |
list_templates | templates:read | Templates with their alias and status, to send by name. |
get_template | templates:read | One template, its variables and whether it is published. |
preview_template | templates:read | Render a template with values filled in. Nothing is sent. |
create_template | templates:write | Write a new template draft. |
update_template | templates:write | Change a template's draft. |
publish_template | templates:write | Publish the draft, so a send can name it. |
Send · send · 11
Send one message, follow what happened to it, and read what came in.
| Tool | Scope | What it does |
|---|---|---|
send_email | emails:send | Send one message from a verified domain. Every sending rule applies unchanged. |
get_email | emails:read | One message: its recipients, what happened to each, and the event timeline. |
list_emails | emails:read | A page of sent mail, newest first, with an optional search. |
list_email_events | emails:read | Every event of one message, with what each one recorded. |
cancel_email | emails:read | Cancel a scheduled message before it leaves. |
get_email_metrics | emails:read | Delivery, bounce, complaint, open and click rates over a window. |
list_received_emails | emails:read | Inbound mail, newest first. |
get_received_email | emails:read | One inbound message, its text capped at 4 KB and never its HTML. |
list_suppressions | suppressions:read | The addresses you will not send to, and why. |
add_suppression | suppressions:write | Suppress up to 100 addresses at once. |
list_logs | logs:read | Your API request logs, tool calls included. |
Audience · audience · 19
Contacts and their properties, imports, segments, and the topics people chose.
| Tool | Scope | What it does |
|---|---|---|
list_contacts | contacts:read | A page of contacts. |
get_contact | contacts:read | One contact, by id or by address. |
list_contact_properties | contacts:read | The properties a contact may carry. |
get_import | contacts:read | How a contact import is getting on. |
create_contact | contacts:write | Add a contact. An address you already hold is updated, not duplicated. |
update_contact | contacts:write | Change a contact's name, address, properties or consent. |
create_contact_property | contacts:write | Declare a property before a contact can carry it. |
import_contacts | contacts:write | Import a CSV of up to 512 KiB, given inline. |
list_segments | segments:read | Your segments. |
get_segment | segments:read | One segment and the filter that defines it. |
preview_segment | segments:read | Count who a filter matches, before a segment is saved with it. |
create_segment | segments:write | Define an audience by filter, by hand, or both. |
update_segment | segments:write | Rename a segment. |
add_contact_to_segment | segments:write | Put one contact in a segment. |
remove_contact_from_segment | segments:write | Take one contact out of a segment. The contact is untouched. |
list_topics | topics:read | The subscription topics you offer. |
create_topic | topics:write | Offer a new topic. |
update_topic | topics:write | Rename a topic, or change its description or visibility. |
set_contact_topics | topics:write | Record which topics one contact opted into or out of. |
Marketing · marketing · 16
Broadcasts, automations, and the custom events that start them.
| Tool | Scope | What it does |
|---|---|---|
list_broadcasts | broadcasts:read | Your broadcasts and their status. |
get_broadcast | broadcasts:read | One broadcast, with HTML over 4 KB left out. |
get_broadcast_report | broadcasts:read | How a sent broadcast performed, and its most-clicked links. |
create_broadcast | broadcasts:write | Draft a broadcast to a segment. It stays a draft. |
update_broadcast | broadcasts:write | Change a draft. |
send_broadcast | broadcasts:write | Send a draft now, or schedule it. |
cancel_broadcast | broadcasts:write | Cancel a scheduled broadcast. |
list_automations | automations:read | Your automations and whether each is enabled. |
get_automation | automations:read | One automation and the graph of its current version. |
list_automation_runs | automations:read | The contacts an automation has run for. |
create_automation | automations:write | Create a workflow. It is disabled until you enable it. |
update_automation | automations:write | Rename, enable or disable an automation, or publish a new version of its graph. |
stop_automation | automations:write | Disable an automation and cancel its runs in flight. |
list_events | events:read | The custom events you have defined. |
create_event | events:write | Define a custom event an automation can start from. |
send_event | events:send | Record that an event happened for one contact. |
Insight · insight · 0
Reserved. It holds no tool of its own yet: email metrics are in send, a broadcast's report is in marketing.
Billing · billing · 1
Read-only. Nothing here buys, changes or cancels anything.
| Tool | Scope | What it does |
|---|---|---|
get_billing | billing:read | Your plan, usage, add-ons and payment state. |
AI · ai · 3
AI assist, once the team has turned it on. Each call uses AI credits.
| Tool | Scope | What it does |
|---|---|---|
suggest_subject_lines | ai:use | Subject lines for a draft. |
draft_email | ai:use | A first draft of an email body from a brief. |
diagnose_email | ai:use | What happened to one message, and what to do about it. |
create_webhook is the one tool that returns a secret: the endpoint's signing secret, once, because your endpoint cannot verify a delivery without it. It is your outbound secret, not a credential into Rasket. A claim started with claim_domain transfers the name by itself once its TXT record resolves, unless the current owner sent or verified recently.
Start with describe_setup
describe_setup needs no scope and is registered whatever the toolset filter says, so it is always the first call an agent can make. It returns the setup recipe — the same steps as the Agents guide — with each step's tool, and a plan marking which steps this connection's scopes allow and which scopes are missing. With format: "json" it returns only the plan:
{
"steps": [
{ "id": "create_key", "tool": null, "scope": null, "allowed": false, "reason": "No tool creates an API key: …" },
{ "id": "add_domain", "tool": "create_domain", "scope": "domains:write", "allowed": true, "reason": null },
{ "id": "send_broadcast", "tool": "send_broadcast", "scope": "broadcasts:write", "allowed": false, "reason": "Needs the broadcasts:write scope." }
],
"missing_scopes": ["broadcasts:write", "automations:write"]
}An agent that finds a scope missing should ask you to reconnect with it before starting, rather than stopping halfway through.
Budgets, because an assistant is chatty
Four limits, counted per connected app, on top of your team's ten requests a second. They are deliberately low: an assistant is a person's hands, not a pipeline.
| Budget | Window | What counts |
|---|---|---|
| 60 tool calls | per minute | Every call that reaches a tool, including one that comes back as an error — the cost is the call. |
| 100 sends | per rolling hour | send_email calls we accepted. Your plan's own quota still applies. |
| 3 broadcasts | per rolling hour | send_broadcast calls that queued or scheduled a broadcast. |
| 5 imports | per rolling hour | import_contacts calls that started an import. |
Over any of them, the call answers JSON-RPC error -32000 with a retryAfter in seconds. A refused call is not itself a tool call, so it does not hold the window open; a malformed batch is refused with -32600 before any tool runs and costs nothing. Each accepted broadcast and import is also written to your audit log as mcp.broadcast_sent or mcp.contacts_imported, naming the connected app.
Connect
One command. The client does the rest.
claude mcp add --transport http rasket https://api.rasket.com/mcpClients that take JSON take the same endpoint:
{
"mcpServers": {
"rasket": {
"type": "http",
"url": "https://api.rasket.com/mcp"
}
}
}To load only some toolsets, name them in toolset, separated by commas. Leave it out for all seven. A tool outside the named toolsets is not registered: it is missing from tools/list, a call to it is answered as not found, and that call counts against no budget. An unknown toolset name is JSON-RPC error -32602 before any tool runs.
claude mcp add --transport http rasket "https://api.rasket.com/mcp?toolset=setup,send"There is nothing else to configure. The first unauthenticated call is answered with a 401 whose WWW-Authenticate header names our protected-resource document, so the client discovers the authorization server, registers itself, and opens a browser for your approval. You pick the team; it exchanges its code for a token.
Every request to /api/v1 needs a User-Agent, and this one needs an Accept listing both application/json and text/event-stream. Every MCP client sends both already.
Nothing is remembered
The server is stateless. Each request builds a server, answers, and forgets: no session id, no stream, nothing kept between calls. GET on the endpoint is 405 — there is no stream to open — and DELETE is a 204 that does nothing, because there is no session to end.
Every tool call is logged like any other API request. It appears in your Logs with source of mcp, the tool it ran, and the connected app that ran it, so a send an assistant made is as traceable as one your own code made.