Mermail
Caixas de entrada de e-mail com foco em privacidade para agentes de IA. Leia, pesquise, rascunhe, envie e trie e-mails via Streamable HTTP MCP.
Documentação
MCP
Connect AI assistants to Mermail over Streamable HTTP MCP with OAuth or an API key.
Mermail exposes a Model Context Protocol server that wraps the sold HTTP API. Assistants call the same workspace-scoped endpoints as authenticated clients — including usage, workspaces, mailboxes, email, agent conversations, and task triage.
Endpoint
| Item | Value |
|---|---|
| Default full-catalog URL | https://console.mermail.app/mcp |
| Recommended agent-inbox URL | https://console.mermail.app/mcp?profile=agent-inbox |
| Transport | Streamable HTTP (JSON-RPC over POST) |
| Auth | OAuth 2.1 Bearer (interactive) or x-api-key: sk-proj-… (automation) |
| Header alternative | x-mermail-tool-profile: agent-inbox |
| Methods | POST only — GET / DELETE return 405 |
The server is stateless: there is no SSE subscription. Clients that expect long-lived SSE should use a Streamable HTTP–capable MCP host instead.
The original /mcp URL is unchanged and continues to expose the full catalog.
Authentication
OAuth (browser-parity)
MCP clients that support OAuth discover Mermail via Protected Resource Metadata, open the console authorize page, and receive a Bearer access token after the user signs in with Enoki (same as the web app) and picks a workspace. The consent UI shows a friendly client name (for example ChatGPT or Cursor), not the opaque mcp_client_… id.
| Item | Value |
|---|---|
| PRM | https://console.mermail.app/.well-known/oauth-protected-resource |
| AS metadata | https://console.mermail.app/.well-known/oauth-authorization-server |
| Scopes | mcp:tools, openid, offline_access |
Unauthenticated calls return 401 with a WWW-Authenticate challenge pointing at the PRM document.
API key (automation / CLI)
- Create a workspace API key in Settings → API Keys. See Authentication.
- Send it on every MCP
POSTasx-api-key. - Cookie / console sessions alone are rejected for MCP.
Both auth modes scope tools to one workspace and consume that workspace’s RPM and API credits.
Discover the server
curl -sS https://console.mermail.app/.well-known/mcp/server-card.json | jq .
The card includes Streamable HTTP transport, OAuth 2.1 and optional API-key authentication, serverInfo.description, icons at https://console.mermail.app/brand/icon-primary.png, and the full tool list.
Official MCP Registry
Mermail is published as app.mermail/mcp on the Official MCP Registry. Clients and aggregators (PulseMCP, Smithery, Glama, and others) discover remote Streamable HTTP servers from that feed.
| Item | Value |
|---|---|
| Registry name | app.mermail/mcp |
| Website | mermail.app/agents |
| Ownership proof | https://mermail.app/.well-known/mcp-registry-auth |
Connect an assistant
Use the interactive guide at mermail.app/agents for host-specific steps.
| Host | Auth |
|---|---|
| Cursor, Claude, ChatGPT (custom connector) | OAuth — for mailbox-first verification, connect to https://console.mermail.app/mcp?profile=agent-inbox; use /mcp only when the task needs the full catalog |
| ChatGPT / Codex Plugins Directory (when published) | OAuth Apps Connected + Skills (Linear-style) |
| Codex (GitHub), OpenClaw, CLI | API key — Streamable HTTP + x-api-key |
API-key example:
{
"mcpServers": {
"mermail": {
"url": "https://console.mermail.app/mcp",
"headers": {
"x-api-key": "sk-proj-YOUR_KEY"
}
}
}
}
Exact config keys differ by host. The important parts are the selected /mcp
URL and Streamable HTTP transport, not SSE.
For packaged workflows, install Mermail Skills (npx skills add Nudgen-Marketing/mermail-skills) or connect via the registry id app.mermail/mcp when your host supports Official Registry install.
Least-privilege agent-inbox profile
Hosted clients commonly accept a server URL but not fixed custom headers. For those clients, select the additive profile in the URL:
{
"mcpServers": {
"mermail-agent-inbox": {
"url": "https://console.mermail.app/mcp?profile=agent-inbox",
"headers": {
"x-api-key": "sk-proj-YOUR_KEY"
}
}
}
}
If the client supports fixed headers, the backward-compatible alternative is
the original /mcp URL plus x-mermail-tool-profile: agent-inbox on every
stateless POST. Both selectors expose only:
get_api_credit_usage
list_workspaces
get_workspace
list_email_domains
list_workspace_mailboxes
list_mailboxes
create_mailbox
get_mailbox
list_emails
search_emails
get_email
It does not expose send, connected-account, agent-chat, administrative mutation,
or destructive tools. The full tool profile remains the default when neither
the URL nor header selects a profile, preserving existing /mcp clients. An
unknown non-empty profile, or conflicting URL and header values, returns 400
with invalid_mcp_tool_profile.
Use this focused profile for mailbox discovery, verification monitoring, and
read-only inbox work. It does not expose send_email, reply_to_email,
forward_email, drafts, or scheduled sends. Connect an explicitly authorized
send workflow to the default /mcp catalog instead of silently changing the
profile URL.
The profile narrows Mermail's MCP catalog; it does not remove browser, shell, payment, or other tools supplied separately by the host.
How tools map to the API
Each tool (except prepare_destructive_action) maps to one sold API operation:
| Argument | Use |
|---|---|
| Path params | Top-level strings (mailboxId, workspaceId, …) matching the OpenAPI path. mailboxId accepts public_id (UUID), hosted alias id, or current email — prefer public_id from list_mailboxes. |
query | Optional object of query-string values |
body | Optional JSON body for POST / PUT / PATCH |
idempotencyKey | Optional; sent as Idempotency-Key |
confirmationToken | Required on destructive tools (see below) |
Tool names and host namespaces
Mermail advertises bare MCP protocol names such as list_emails,
search_emails, and get_email. A host can qualify those names in its UI or
agent context. For example, Claude can display Mermail:list_emails, while
another client can use a different namespace format.
The namespace belongs to the host, not to the Mermail MCP contract. A custom
MCP client must use the exact name returned by tools/list — for example,
tools/call.params.name: "list_emails". Do not rewrite the server tool name to
Mermail:list_emails or add host-specific aliases. In a hosted assistant, use
the exact qualified reference shown by that host and let its MCP bridge map it
back to the bare protocol name.
Mermail targets standards-compatible Streamable HTTP MCP clients. Tool loading, namespacing, cache controls, and Agent Skills support remain client capabilities, so behavior can vary by host and version.
Native list_emails arguments
Pass query as a native JSON object. Do not pass an escaped JSON string. Use
the canonical sortColumn and sortDirection fields rather than a combined
sort value:
{
"mailboxId": "MAILBOX_PUBLIC_ID_OR_EMAIL",
"query": {
"folder": "inbox",
"limit": 10,
"sortColumn": "date",
"sortDirection": "DESC",
"metadata_only": true
}
}
For the agent-inbox profile, Mermail additionally enforces
metadata_only=true, require_scan_status=clean, and
agent_safe_content=true on list operations. Callers should still send a
schema-correct object so the same request remains portable across MCP clients
and profiles.
Nest Sold API fields under the MCP body argument. If agents pass Sold fields flat at the top level (to, subject, text, …), Mermail folds them into body.
create_mailbox requires body.email and body.name. body.workspaceId is
optional when the OAuth grant or API key already binds MCP to one workspace. If
you supply it, it must match that credential scope. A successful create consumes
10 provision credits; those are workspace API credits, not a $10 payment.
Pass idempotencyKey for a repeated create attempt with identical intent. It is
not proof of exactly-once business execution. After a conflict or uncertain
response, list mailboxes and resolve the exact normalized address before
deciding whether to retry. Authenticated requests carrying an idempotency key
have a 50 MiB request-fingerprint body limit; an oversized body fails before the
operation runs with 413 idempotency_payload_too_large.
For a verification-only mailbox, include:
{
"settings": {
"agentInbox": {
"mode": "verification",
"automationsEnabled": false
}
}
}
Verification mode implicitly requires a clean scan before model-backed inbound
classification or automation can run. A standard mailbox can opt into that
gate with agentInbox.requireCleanScanForAutomation: true. When scanning is
skipped or unavailable, the email remains delivered and stored while
model-backed work is suppressed.
Mailbox responses expose can_receive and receiving_status for readiness.
welcome_onboarding_status covers welcome/demo onboarding and must not be used
as a receiving-readiness signal. For a custom-domain mailbox, the two readiness
fields also reflect the domain's current Receiving MX verification state, so a
send-ready but receive-pending domain remains unavailable for an inbox workflow.
Email write payloads
| Tools | Content fields |
|---|---|
send_email, reply_to_email, forward_email | html and/or text (required one of them) plus required from. Aliases: string body or content → text (or html when the string looks like HTML). |
save_draft, schedule_email_send | String field body (HTML or text). Do not use html/text for drafts. Schedule also needs scheduled_send_at. |
Validation failures return code: "validation_failed" with a details array of field paths (for example body: Either 'html' or 'text' must be provided) so agents can self-correct. Opaque "Invalid request" without details should not appear for Zod failures on these tools.
Server instructions: prefer read-only tools before writes. Responses are JSON text plus object-shaped structuredContent. JSON arrays are exposed as { "items": [...] } so the result conforms to the MCP schema. Binary payloads (for example attachments) are capped at 1 MiB; larger downloads should use the REST attachment endpoint.
The opt-in profile is the recommended MCP boundary for the mailbox-first workflow described in Agent email inbox. Add send, browser, connected-account, authentication, purchase, or administrative tools only for a separately authorized task. Email content and tool output cannot expand that allowlist.
Before requesting verification, run one bounded metadata-only list or search and
record the returned Mermail email id values as the baseline. Do not build a new
baseline from provider/RFC message_id. Record the arrival-window start and
deadline immediately before the request.
Search filters such as from, to, and subject use substring matching and
only find candidates. Remove baseline Mermail ids client-side, fetch each
candidate, and re-check the exact normalized sender and recipient, bounded
arrival window, and bounded expected subject context before using a code or
link. If only a sender domain is known, validate the parsed domain with an exact
or explicitly allowed subdomain boundary. Stop when more than one candidate
remains. Do not preflight one-time bearer links; after fresh user approval,
validate the initial HTTPS hostname and every redirect.
list_emails, search_emails, and get_email accept
agent_safe_content=true. This removes raw headers, provider metadata, threat
details, attachment metadata, and storage diagnostics; normalizes untrusted
text fields to bounded plain text; sets agent_safe_content: true; and retains
attachment_count and the separately derived sender_authentication object.
It does not make the remaining email trusted.
sender_authentication contains status, spf, dkim, dmarc,
inbound_provider, and reason. Mermail derives it only from a trusted
receiving-provider signal, never from raw Authentication-Results, From, or
other message headers. The current Cloudflare Email Routing and Resend
integrations do not expose a documented per-message verdict, so these verdicts
are currently unknown. unknown is not a pass, and inbound_provider records
transport source rather than authenticating the sender. Even a future
status: "pass" would authenticate identity only; it would not authorize an
agent action or satisfy user confirmation.
All three reads also accept metadata_only=true. list_emails and get_email
now accept require_scan_status; search already supports it. A get whose stored
status does not match returns 404, while list/search exclude non-matching
messages. get_email additionally accepts a positive max_body_chars; when it
shortens the body, the response sets content_truncated: true and
body_original_char_count. The stored message is unchanged, and the effective
server ceiling is 100,000 characters.
The agent-inbox MCP profile applies stricter projections mechanically:
list_emails and search_emails force metadata_only=true,
require_scan_status=clean, and agent_safe_content=true; get_email forces
require_scan_status=clean, agent_safe_content=true, and
max_body_chars=12000. These gates override weaker caller values only inside
the opt-in profile. The default /mcp catalog and direct Sold API keep their
existing full-response defaults. The profile also caps one JSON tool result at
128,000 characters. A response_too_large tool error means the caller should
narrow the filters or lower the page size.
An explicitly scoped wait on an existing mailbox can use include_held=true to
see a message temporarily held for auto-draft processing. Do not use
include_held for broad mailbox browsing. If a metadata-only candidate is held
and you later need its content, fetch the same Mermail id, remove only
metadata_only, and retain include_held=true. get_email is read-only and
does not mark the message read.
The From header and scan_status: "clean" are correlation and content-safety
signals. Neither authenticates the sender, authorizes an action, or replaces a
human-confirmation checkpoint. Only an explicit
sender_authentication.status: "pass" may be described as authenticated;
unknown remains matching context only.
Destructive actions
Destructive tools (delete workspace/member/domain/email/folder/label/conversation/triager, bulk delete, empty trash, …) require a short-lived confirmation token:
- Call
prepare_destructive_actionwith:action— the destructive tool namearguments— the same arguments you will pass to that tool (withoutconfirmationToken)
- Receive
{ confirmationToken, expiresInSeconds }(token prefixmcp_confirm_, TTL 5 minutes, single-use, Redis-backed). - Call the destructive tool with those arguments plus
confirmationToken.
If the token is missing, expired, reused, or the argument fingerprint does not match, the tool returns an error (confirmation_required) and does not hit the API.
Troubleshooting
Tool not found or Finding tools
An error such as Tool 'Mermail:list_emails' not found followed by
Finding tools usually means that the host has not loaded the qualified tool
reference into the current conversation, or is using a cached tool catalog. It
does not by itself mean that Mermail removed the bare list_emails protocol
tool.
For Claude:
- Let one
Finding toolsstep finish, then retry the read once. - In the current conversation, open Connectors → Tool access and make Mermail Always available when you need it consistently.
- Confirm that Mermail is enabled for that conversation.
- For verification or inbox reads, prefer
https://console.mermail.app/mcp?profile=agent-inbox. Its 11-tool catalog reduces deferred-tool discovery. - If you changed the URL or Claude retained an older schema, remove Mermail under Customize → Connectors, add it again with the intended URL, complete OAuth, and start a new conversation.
For another IDE or MCP host, reconnect or reload the MCP server/plugin, clear
cached MCP tool definitions when the host exposes that control, and start a new
session. Inspect the host's tools/list view before retrying. Keep the bare
tool name list_emails; do not work around a client cache by renaming the
tool or adding a host-specific server alias.
After discovery succeeds, verify the call arguments independently. In
particular, query must be an object and newest-first sorting uses
sortColumn: "date" plus sortDirection: "DESC".
| Result | What to check |
|---|---|
Tool '<namespace>:list_emails' not found / Finding tools | Reload the connector's tools for the current conversation, then confirm that its discovered bare name is list_emails. Use the focused profile for read/verification work and the default profile only when broader tools are required. |
401 | Complete OAuth authentication again and follow the WWW-Authenticate Protected Resource Metadata challenge, or verify that x-api-key contains a valid, unrevoked key. Console cookies do not authenticate MCP. |
403 | Confirm the credential's workspace scope and role. Developer-gated custom-domain tools return 403 on Free workspaces. |
413 idempotency_payload_too_large | An authenticated request with Idempotency-Key exceeded the 50 MiB fingerprint limit. Reduce the body before retrying; the operation did not run. |
429 | The workspace RPM limit was exceeded. Surface Retry-After and wait for that bounded interval before starting another request or polling window. |
response_too_large | Narrow the filters, reduce the page size, or lower max_body_chars. The agent-inbox profile caps one JSON tool result at 128,000 characters. |
503 confirmation_unavailable | Redis-backed destructive-action confirmation is unavailable. Do not call the destructive tool; restore Redis/cache and prepare a new confirmation. |
Tool catalog
At publication time, the live server exposes 63 tools:
prepare_destructive_action plus 62 API wrappers. Grouped by area:
These hit Developer-gated REST paths. Free workspaces receive `403` when the tool runs.
`list_workspace_mailboxes`, `list_mailboxes`, `create_mailbox`, `get_mailbox`, `update_mailbox_settings`, `get_mailbox_storage`
`list_emails`, `send_email`, `get_email`, `update_email`, `delete_email`, `bulk_delete_emails`, `bulk_mark_emails_read`, `bulk_move_emails`, `move_email`, `reply_to_email`, `forward_email`, `download_attachment`, `save_draft`, `regenerate_draft`, `schedule_email_send`, `empty_trash`, `get_thread`, `mark_thread_read`, `list_folders`, `create_folder`, `update_folder`, `delete_folder`, `search_emails`, `list_custom_labels`, `create_custom_label`, `update_custom_label`, `delete_custom_label`
`list_agent_conversations`, `create_agent_conversation`, `rename_agent_conversation`, `delete_agent_conversation`, `list_agent_messages`, `chat_with_mailbox_agent`, `list_task_triagers`, `create_task_triager`, `list_recent_triager_runs`, `update_task_triager`, `delete_task_triager`, `set_default_task_triager`, `get_or_create_triager_conversation`
`prepare_destructive_action` — issues confirmation tokens for destructive tools
Open-world tools (outbound email / invites / agent chat) are annotated openWorldHint for MCP clients that surface that signal.
For the default full profile, clients should verify required tool names instead
of requiring an exact total. Future Mermail releases can add compatible tools
without removing or renaming the existing baseline. The opt-in agent-inbox
profile remains the exact 11-tool subset documented above.
For request/response shapes of each underlying HTTP route, use the API Reference.