Skip to main content

MCP overview

POST /api/mcp exposes Mailroom over the Model Context Protocol, so an AI client can design templates, manage contacts, and run campaigns and sequences against your project.

It is the same platform behind the same credentials as /api/v1 — an MCP client and an SDK client with the same key can do the same things, and are subject to the same scopes and rate limits.

Transport​

Streamable HTTP, stateless, with JSON responses (no long-lived SSE stream). Every request builds its own server instance, so there is no session to establish or resume — each call carries its own credentials.

Both GET and POST are accepted at /api/mcp.

Connecting​

For a client that speaks HTTP MCP directly:

{
"mcpServers": {
"mailroom": {
"type": "http",
"url": "https://<your-mailroom-deployment>/api/mcp",
"headers": { "Authorization": "Bearer pk_live_…" }
}
}
}

Mailroom is deployed per installation — there is no shared host. Use whatever domain serves your instance.

For a stdio-only client, bridge it:

npx mcp-remote https://<your-mailroom-deployment>/api/mcp \
--header "Authorization: Bearer pk_live_…"

Authentication​

Authorization: Bearer pk_live_…

The key is the tenancy: one key belongs to exactly one project, and every tool call is scoped to that project. There is no tenant header and no way for a call to reach another project's data.

Authentication happens before the MCP handshake. A missing, malformed, revoked, or unknown key gets a real HTTP 401 with:

WWW-Authenticate: Bearer realm="mailroom"

so a client fails at connect time rather than discovering the problem on its first tool call. A key belonging to a suspended project gets 403 project_suspended.

Create and revoke keys in the console under Settings → API keys.

Scopes​

Tools enforce the same scopes as the REST endpoints they sit on top of. See Authentication for the full list and what each one covers. Roughly:

ScopeCovers
contacts:readreading contacts
contacts:writeupserting and unsubscribing contacts
templates:writesaving, renaming, enabling templates
campaigns:writeeverything under campaigns
sequences:writesequences, enrollments, events
sendsending a test email
*all of the above

Read-only design tools (validating, rendering, listing) require a valid key but no particular scope, mirroring the open GET routes on /api/v1.

A call missing its scope comes back as a tool error with code forbidden — the connection stays up, so the model can adapt rather than fall over.

Result shape​

Successful tool results are flat, matching the REST envelope:

{ "ok": true, "campaigns": [ … ] }

The same object is returned both as JSON text content and as structuredContent.

Failures set isError and carry a reason:

{ "ok": false, "error": "Missing scope: campaigns:write", "code": "forbidden" }

Domain outcomes that are not errors — an unknown template, an empty audience, a campaign that can no longer be edited — come back as ordinary successful results with a reason field, so the model can react to them instead of retrying a failure. For example { "ok": true, "updated": false, "reason": "not_editable" }.

Rate limits​

Calls are rate limited per project, on the same budget as /api/v1. Exceeding it returns a tool error with code rate_limited and the retry delay in the message.

Resources​

Beyond tools, the server exposes read-only resources the model can pull in as ground truth:

URIWhat it is
mailroom://schema/email-documentJSON Schema for the EmailDocument tree
mailroom://templates/registrythe project's template keys, types, and default subjects
mailroom://examples/seedspreset documents to use as references
mailroom://brand/themethe resolved brand render theme

Next​

See Tools for the full catalogue, including the reviewable campaign workflow that keeps an agent from sending before a human has looked.