Unspam

MCP Server

Unspam exposes a Model Context Protocol (MCP) server so AI assistants (Claude, ChatGPT, Cursor, and other MCP-compatible clients) can run spam checks, inbox placement tests, and automatic tests on your behalf. MCP is an open standard that lets an assistant call external tools in a structured way. Unspam's is a remote MCP server — your client connects to it over HTTPS and authenticates with your Unspam account via OAuth, so there is no API key to copy or paste. MCP access is available exclusively on subscription plans that include API usage.

Endpoint

The MCP server speaks JSON-RPC 2.0 over HTTP. All requests are POST to a single endpoint:

https://api.unspam.email/mcp

Protocol version: 2024-11-05. Most users never call this endpoint directly — you add the URL to an MCP-compatible client and it handles the protocol and authentication for you (see Setup & integrations).

Authentication

The server uses OAuth 2.1 with discovery, Dynamic Client Registration, and the Authorization Code grant with PKCE. The token must carry the mcp scope. Compliant MCP clients perform this flow automatically: when you add the server they discover the OAuth endpoints, register, open a browser for you to sign in to Unspam and approve access, then store the resulting token. You do not need to create or paste an API token manually.

Every request to /mcp must include the bearer token:

Authorization: Bearer ACCESS_TOKEN

Requests without a valid mcp-scoped token receive a JSON-RPC -32001 error with HTTP 401 (missing/invalid token) or 403 (token lacks the mcp scope). A 401 includes a WWW-Authenticate header pointing at the protected-resource metadata so clients can start the OAuth flow.

OAuth discovery endpoints

Clients locate everything they need from these well-known documents:

PurposeURL
Protected resource metadatahttps://api.unspam.email/.well-known/oauth-protected-resource/mcp
Authorization server metadatahttps://api.unspam.email/.well-known/oauth-authorization-server
Dynamic Client RegistrationPOST https://api.unspam.email/oauth/register
AuthorizationGET https://api.unspam.email/oauth/authorize
TokenPOST https://api.unspam.email/oauth/token
RevocationPOST https://api.unspam.email/oauth/revoke

Supported grant types: authorization_code, refresh_token. PKCE method: S256. Scope: mcp. You can review and revoke tokens that clients have created from the Subscription page in your Unspam dashboard.

Setup & integrations

Any MCP client that supports remote (HTTP/streamable) servers with OAuth can connect. The shape is always the same: point the client at https://api.unspam.email/mcp, complete the OAuth sign-in when a browser opens, and the Unspam tools appear in your assistant. Below are step-by-step instructions for the most common clients.

Claude Desktop

Add a custom connector from the app — no config file needed:

  1. Open Settings → Connectors and click Add custom connector.
  2. Name it Unspam and set the URL to https://api.unspam.email/mcp.
  3. Click Connect and complete the OAuth sign-in in the browser window that opens.

If your build does not offer custom connectors, bridge the remote server through mcp-remote in claude_desktop_config.json (Settings → Developer → Edit Config). It requires Node.js:

{
  "mcpServers": {
    "unspam": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.unspam.email/mcp"]
    }
  }
}

Restart Claude Desktop; a browser opens once to authorize, and the token is cached for future launches.

Claude Code

Add the server with the CLI, then authenticate from inside a session:

claude mcp add --transport http unspam https://api.unspam.email/mcp

Start Claude Code and run /mcp; select unspam and follow the OAuth prompt to sign in. Add --scope project to the command above to share the server with your team via a checked-in .mcp.json:

{
  "mcpServers": {
    "unspam": {
      "type": "http",
      "url": "https://api.unspam.email/mcp"
    }
  }
}
Cursor

Add the server to ~/.cursor/mcp.json (global) or .cursor/mcp.json in your project:

{
  "mcpServers": {
    "unspam": {
      "url": "https://api.unspam.email/mcp"
    }
  }
}

Open Settings → MCP, confirm unspam is listed, and click Login / Needs login to complete the OAuth flow. The Unspam tools then become available to the agent.

ChatGPT

Remote MCP connectors are available in ChatGPT's Developer Mode (Plus, Pro, and Business plans):

  1. In Settings → Connectors, enable Developer mode.
  2. Click Create / Add custom connector and set the MCP server URL to https://api.unspam.email/mcp.
  3. Choose OAuth as the authentication method — the Authorization, Token, and Registration URLs are discovered automatically.
  4. Save, then click Connect and sign in to Unspam to approve access.
  5. Enable the connector in the composer to let ChatGPT call the Unspam tools.
Windsurf & other clients

For Windsurf, add the server under mcpServers in ~/.codeium/windsurf/mcp_config.json using the serverUrl field, then press the refresh button in the Cascade MCP panel to trigger the OAuth login:

{
  "mcpServers": {
    "unspam": {
      "serverUrl": "https://api.unspam.email/mcp"
    }
  }
}

Any other MCP-compatible client works the same way — register a remote/streamable HTTP server pointed at https://api.unspam.email/mcp and complete the OAuth sign-in. Clients that only support stdio servers can bridge through npx -y mcp-remote https://api.unspam.email/mcp, as shown for Claude Desktop above.

Usage examples

Once connected, drive Unspam in plain language — the assistant picks the right tools and chains them for you. A few prompts to try:

Because every tool mirrors the REST API, you can mix conversational requests with precise follow-ups like "re-run that test against only Gmail and Outlook mailboxes."

Protocol basics

If you are integrating directly rather than through a client, the server implements three JSON-RPC methods.

initialize

Handshake. Returns the protocol version and server info.

curl -X POST https://api.unspam.email/mcp \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize" }'
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": { "tools": {} },
    "serverInfo": { "name": "unspam", "version": "1.0.0" }
  }
}
tools/list

Returns the catalog of available tools, each with a JSON Schema inputSchema. This is the authoritative, machine-readable description of every tool and its parameters.

curl -X POST https://api.unspam.email/mcp \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'
tools/call

Invokes a tool by name with arguments. The result payload is a JSON document returned as text content.

curl -X POST https://api.unspam.email/mcp \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "get_spam_check_result",
      "arguments": { "id": "abc123" }
    }
  }'
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [ { "type": "text", "text": "{ \"id\": \"abc123\", \"status\": \"completed\", ... }" } ]
  }
}

Notifications (requests without an id) receive an empty 202 response.

Tools

Tool inputs and outputs mirror the REST API. A * marks a required argument. IDs returned by these tools are the same opaque IDs used throughout the platform.

Account

ToolArgumentsDescription
get_account_statusAccount email and active subscription, including remaining monthly limits.

Spam Check

ToolArgumentsDescription
start_spam_checkCreate a spam check; returns an id and an inbox_address to send your test email to.
list_spam_checkspage, per_pageList spam checks created via MCP, newest first.
get_spam_check_resultid*Full result of a spam check, including per-signal breakdown and report URL.
get_spam_check_screenshotsid*Desktop, tablet, and mobile screenshots for a completed check.
get_spam_check_heatmapid*Attention and focus heatmap URLs for a completed check.
Example — run a spam check

Start a check, send your email to the returned address, then fetch the result.

# 1. Start
{ "name": "start_spam_check", "arguments": {} }
# -> { "id": "abc123", "inbox_address": "abc123@inbox.unspam.email" }

# 2. Send your email to abc123@inbox.unspam.email, wait a moment.

# 3. Fetch the result
{ "name": "get_spam_check_result", "arguments": { "id": "abc123" } }

Inbox Placement

ToolArgumentsDescription
list_mailboxesAvailable seed mailboxes for inbox placement tests.
start_inbox_placement_testmailboxes (int[])Start a test. Omit mailboxes to use all enabled mailboxes. Returns an id and the mailboxes to send to.
list_inbox_placement_testspage, per_pageList inbox placement tests created via MCP, newest first.
get_inbox_placement_resultid*Full per-mailbox result of an inbox placement test.

Automatic Testing — Senders

An automatic test delivers your email through your own SMTP sender on a schedule. Create a sender first, then attach it to a test.

ToolArgumentsDescription
create_scheduled_test_sendername*, service*, settingsRegister an SMTP sender. Returns its id.
list_scheduled_test_senderspage, per_pageList your senders, newest first.
get_scheduled_test_senderid*A single sender, including its SMTP settings.
update_scheduled_test_senderid*, name*, service*, settingsUpdate a sender. Clears any previous connection error.
delete_scheduled_test_senderid*Delete a sender.
test_scheduled_test_sender_connectionid*Verify the stored SMTP credentials. Returns { "status": "ok" } or { "status": "error", "message": "..." }.
Example — create an SMTP sender

For the smtp service, settings is required with from_name, from_email, and an smtp object. headers is optional.

{
  "name": "create_scheduled_test_sender",
  "arguments": {
    "name": "My Sender",
    "service": "smtp",
    "settings": {
      "from_name": "Admin",
      "from_email": "admin@no-reply.com",
      "smtp": {
        "host": "smtp.example.com",
        "port": 465,
        "protocol": "SSL",
        "username": "user@example.com",
        "password": "password"
      },
      "headers": {}
    }
  }
}
# -> { "id": "2ded86a5-...", "name": "My Sender", "service": "smtp", "settings": { ... }, "error_code": null }

Automatic Testing — Tests & Runs

ToolArgumentsDescription
create_scheduled_testCreate a draft test. Returns an id and an inbox_address to send your email template to.
set_scheduled_test_emailid*, subject*, html*, text, from, headersSet the email template directly from content instead of sending one to the inbox address. from defaults to the sender's address, then the existing one. headers lets you add e.g. List-Unsubscribe.
get_scheduled_testid*A single test: schedule, sender, mailboxes, and the last completed run. While in draft, poll until email_subject/email_from are populated.
list_scheduled_testspage, per_pageList your automatic tests, newest first.
configure_scheduled_testid*, name*, status*, sender_uuid*, providers*, schedule*, alert_settings*Configure a test. status is active (run on schedule) or disabled (manual dispatch only). The sender must have no connection error.
set_scheduled_test_statusid*, status*Enable (active) or disable (disabled) a configured test.
dispatch_scheduled_testid*Trigger a run immediately. Works for active and disabled tests with a schedule and sender. Returns a run_id with status in_queue.
delete_scheduled_testid*Delete a test.
list_scheduled_test_runsid*, from, to, page, per_pageList a test's runs. Defaults to the last month; the date range must not exceed 6 months.
get_scheduled_test_runid*, run_id*Detailed inbox-placement result of a single run.
Example — set up and run an automatic test

Step 1. Create a draft test.

{ "name": "create_scheduled_test", "arguments": {} }
# -> { "id": "9b1c7e84-...", "status": "draft", "inbox_address": "test-9b1c7e84@inbox.unspam.email" }

Step 2. Send the email you want to test to the returned inbox_address, then poll until the template is captured.

{ "name": "get_scheduled_test", "arguments": { "id": "9b1c7e84-..." } }
# Wait until email_subject / email_from are no longer null.

Or skip steps 2 entirely and set the template directly from content with set_scheduled_test_email:

{
  "name": "set_scheduled_test_email",
  "arguments": {
    "id": "9b1c7e84-...",
    "subject": "Welcome to our newsletter",
    "html": "<h1>Hello!</h1><p>Thanks for subscribing.</p>",
    "from": "news@yourdomain.com",
    "headers": {
      "Reply-To": "support@yourdomain.com",
      "List-Unsubscribe": "<https://yourdomain.com/unsubscribe?id=123>",
      "List-Unsubscribe-Post": "List-Unsubscribe=One-Click"
    }
  }
}

Step 3. Configure the test. Use a sender id as sender_uuid and mailbox IDs from list_mailboxes as providers.

{
  "name": "configure_scheduled_test",
  "arguments": {
    "id": "9b1c7e84-...",
    "name": "My automatic test",
    "status": "active",
    "sender_uuid": "2ded86a5-...",
    "providers": [3, 7, 23],
    "schedule": { "start_at": "2026-06-18T10:21:00Z", "type": "week", "days": [] },
    "alert_settings": { "mode": "all", "spam_level": null }
  }
}

Schedule type is one of month, week, days, or specific_days; days (0–6) is required only for specific_days. Alert mode is all or spam_level; spam_level (0–100) is required only for spam_level.

Step 4. Trigger a run now (optional), then fetch its result.

{ "name": "dispatch_scheduled_test", "arguments": { "id": "9b1c7e84-..." } }
# -> { "status": "in_queue", "run_id": "f47ac10b-..." }

{ "name": "get_scheduled_test_run", "arguments": { "id": "9b1c7e84-...", "run_id": "f47ac10b-..." } }

Errors

The server uses two error channels:

Rate Limits

MCP requests are rate-limited per user account. Exceeding the limit results in a 429 Too Many Requests response.