MailParrot

Integrations

MCP server

Connect Cursor (or any MCP client) to MailParrot over a hosted Streamable HTTP endpoint. No local package, Node install, or compile — just a URL and an API key.

New to MCP? See what AI agents can do with MailParrot and copyable connection config.

Install with your agent

Copy and paste the following prompt into your agent. The agent will complete the installation automatically.

Prompt
Please help me set up a new custom MCP server via the following endpoint, and complete the authorization process, https://api.mailparrot.app/mcp. Authorization is an API key in the x-api-key header (create one under Dashboard → Settings → API Keys).

Point and go

Manual setup. Add this to your Cursor mcp.json. Create an API key in Dashboard → Settings.

{
  "mcpServers": {
    "mailparrot": {
      "url": "https://api.mailparrot.app/mcp",
      "headers": {
        "x-api-key": "mp_your_key_here"
      }
    }
  }
}

Staging: https://api.test.mailparrot.app/mcp. Alias domains: to.mailparrot.app (prod) / to.test.mailparrot.app (staging). Authorization: Bearer mp_… also works.

Malformed JSON

The hosted endpoint is a Cloud Function. The Functions runtime parses Content-Type: application/json before MailParrot runs, and it does not hand a parse failure to the function. A body that is not valid JSON (for example {not json) is HTTP 400 with Express's HTML Bad Request page, even when no API key is sent. There is no supported setting to turn that parser off.

An empty JSON body does reach the server. After the API key is accepted, the MCP SDK responds with HTTP 400 and JSON-RPC error -32700. The same JSON-RPC parse error is what a direct Express process (local HTTP) returns for invalid JSON, because that process is the first parser.

Agent flow

  1. Call get_usage to confirm credits remain.
  2. Create a project and alias (create_project, create_alias).
  3. Send the app under test to the returned inbox address.
  4. Call wait_for_auth_code (or list_messages) to retrieve the OTP. The wait ignores codes already stored on the alias and returns one ingested after the call starts. Pass includeExisting: true to accept a code that is already there.

Credits and payment gating

When remaining credits hit zero, inbound mail is not stored, and the messages and latestAuthCode GraphQL operations fail with PAYMENT_REQUIRED. Project, alias, webhook, and usage tools still work. Buy packs in Settings → Credits.

See also the messages and latestAuthCode API reference.

Tools

Argument names, types, and whether each one is required come from the MCP tool schemas.

get_usage

Get MailParrot credit usage (used, remaining, total, unlock fields). Available even at 0 credits. Call this before wait_for_auth_code when unsure about balance.

No arguments.

list_credit_packs

List available Stripe credit pack sizes (priceId + credits). Purchases happen in the dashboard Settings → Credits page (not via MCP).

No arguments.

list_projects

List all MailParrot projects for the authenticated account.

No arguments.

create_project

Create a new MailParrot project to group disposable inboxes (aliases).

  • name (string, required): Project display name

update_project

Rename an existing MailParrot project.

  • projectId (string, required): Project id
  • name (string, required): New project display name

delete_project

Permanently delete a project and its aliases, messages, and webhooks.

  • projectId (string, required): Project id

list_aliases

List disposable inbox aliases for a project.

  • projectId (string, required): Project id

create_alias

Create a disposable inbox. Domains: to.mailparrot.app (prod) or to.test.mailparrot.app (staging). Returns the full emailAddress to use in tests.

  • projectId (string, required): Project id
  • localPart (string, required): Local part before @, e.g. qa-user-42
  • domain (string, required): to.mailparrot.app or to.test.mailparrot.app

set_alias_active

Enable or disable an alias inbox.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • active (boolean, required): True to receive mail, false to drop it

delete_alias

Delete an alias inbox.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id

list_messages

List messages for an alias (paginated). Fails with PAYMENT_REQUIRED when the account has no remaining credits.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • page (integer, optional): Page number (default 1)
  • limit (integer, optional): Page size, 1-100 (default 20)
  • sortOrder ("asc" | "desc", optional): Sort by receivedAt: "asc" or "desc" (default desc)

get_latest_auth_code

Return the most recently extracted OTP/auth code for an alias, or null if none. With no since or afterMessageId, this is the latest code even when it arrived earlier. Pass since and/or afterMessageId to ignore codes that are not strictly newer. since is compared to storedAt (server insert time). Fails with PAYMENT_REQUIRED when out of credits.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • since (string | integer, optional): Only return a code stored strictly after this time. ISO-8601 timestamp or epoch milliseconds (a whole number below 1e11 is read as epoch seconds). Compared to storedAt (server clock at insert, millisecond precision), not the email Date header and not Mailgun's whole-second receivedAt.
  • afterMessageId (string, optional): Only return a code whose message id sorts after this id (MongoDB ObjectId order). The given id is excluded. Use this to ignore a code you already consumed, including when two emails share a second.

wait_for_auth_code

Poll until an auth code is stored after this call starts, or the wait elapses (default 50000ms). Codes already on the alias are ignored, so a reused inbox cannot hand back a stale OTP. Pass includeExisting: true to accept a code that is already stored. since (ISO-8601 or epoch ms) overrides that cutoff and is compared to storedAt, the server insert time, not the email Date or Mailgun's whole-second receivedAt. afterMessageId skips that message id and anything older, which separates two codes that share a second. The time cutoff still applies; pass includeExisting or an earlier since to accept an older stored code with a newer id. timeoutMs above 50000ms is accepted and capped to 50000ms on this server instead of being rejected. Hosted MCP (https://api.mailparrot.app/mcp) caps near 50s because Firebase Hosting closes the connection at 60s; local stdio caps at 300000ms. Always returns a tool result (OTP, PAYMENT_REQUIRED, or timeout). Call again to keep polling. Pre-checks usage and aborts immediately on PAYMENT_REQUIRED / 0 credits (inbound mail is not stored when empty).

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • timeoutMs (integer, optional): Max wait in ms (default 50000). Larger values are accepted and capped to 50000ms on this server.
  • intervalMs (integer, optional): Poll interval in ms (default 2000)
  • since (string | integer, optional): Only return a code stored strictly after this time. ISO-8601 timestamp or epoch milliseconds (a whole number below 1e11 is read as epoch seconds). Compared to storedAt (server clock at insert, millisecond precision), not the email Date header and not Mailgun's whole-second receivedAt.
  • afterMessageId (string, optional): Only return a code whose message id sorts after this id (MongoDB ObjectId order). The given id is excluded. Use this to ignore a code you already consumed, including when two emails share a second.
  • includeExisting (boolean, optional): When true, a code already stored before this call may be returned (the previous behaviour). Default false: only a code ingested after the call starts is returned. An explicit since or afterMessageId still applies.

list_webhooks

List outgoing webhooks configured for an alias.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id

create_webhook

Register a webhook URL for an alias. Use event types transactional_email_arrived and/or auth_code_extracted.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • url (string, required): HTTPS endpoint that receives events
  • eventTypes (string[], required): Event names, e.g. transactional_email_arrived and auth_code_extracted

update_webhook

Update a webhook URL, event types, or active flag. Use event types transactional_email_arrived and/or auth_code_extracted.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • webhookId (string, required): Webhook id
  • url (string, optional): Replacement endpoint URL
  • eventTypes (string[], optional): Replacement event names
  • active (boolean, optional): Enable or disable delivery

delete_webhook

Delete a webhook from an alias.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • webhookId (string, required): Webhook id

list_webhook_logs

List recent delivery attempts for a webhook.

  • projectId (string, required): Project id
  • aliasId (string, required): Alias id
  • webhookId (string, required): Webhook id