View as markdown ↓

MCP setup

Postfleet ships a Model Context Protocol (MCP) server so an agent can send and read mail as tools. It is thin-over-REST: every tool calls the same /api/v1/ endpoints as your key, so auth, scoping, and quotas are enforced exactly once.

Configure the server

The server speaks streamable HTTP at /api/mcp and authenticates with a bearer pf_ key. Pass the key in the Authorization header:

{
  "mcpServers": {
    "postfleet": {
      "url": "https://your-app.example.com/api/mcp",
      "headers": { "Authorization": "Bearer pf_..." }
    }
  }
}

A request without a Bearer token is rejected 401:

{ "error": "missing bearer token",
  "hint": "Configure this MCP server with an Authorization: Bearer pf_... header." }

The key's scope and can_read/can_send/mailbox binding apply to tool calls exactly as they do to the REST API — see Authentication. Note that wait_for_email can hold a request open up to ~2 minutes, so a deployment must allow a long request duration.

Tools

Tool Arguments Purpose
create_mailbox slug?, display_name?, extraction_schema_id? Create a mailbox this agent owns.
send_email mailbox_id, to, subject, text Send a new email.
reply_email mailbox_id, reply_to_message_id, text Reply to a received message (threads automatically).
list_inbox mailbox_id, limit? List recent messages, newest first.
read_email message_id Read one message in full (cleaned body, sanitization report, classification, extraction).
wait_for_email mailbox_id, from_contains?, subject_contains?, timeout_seconds? Block until a matching email arrives, or time out ({timed_out:true}).
create_draft mailbox_id, to?, subject?, text, reply_to_message_id? Stage a draft without sending. Returns {id, status:"draft"}.
list_drafts mailbox_id List open drafts (status draft, pending_approval, sending).
send_draft id Send a staged draft by id.

read_email never returns the pre-sanitization raw body — only the cleaned, screened content reaches the agent.

The 202 pending-approval outcome

If a mailbox requires human approval, send_email, reply_email, and send_draft do not send immediately. They return the queued-draft shape instead of a message id:

{ "draft_id": "d_123...", "status": "pending_approval" }

This is a success, not an error, and it must not be retried. The email is delivered once a human approves the draft in the dashboard. To follow up, call list_drafts — a pending_approval entry is still waiting on a human; once approved it is sent and tombstoned (drops off the list).

Distinguish the two success shapes:

  • { "id": "...", "thread_id": "..." } → sent.
  • { "draft_id": "...", "status": "pending_approval" } → queued for human approval.

See Drafts & human-in-the-loop for the full approval model.

Errors

Tool errors come back as a short message plus a recovery hint (never a stack trace), for example an invalid key (401), a scope/capability rejection (403), quota exhaustion (402), a not-found id (404), a suppressed recipient (422), or a transient provider issue (502, retry in a few seconds). The underlying status and shapes match the REST API documented throughout these pages.