Get your API key
AI & agents

Connect your agent

Give your agent a real email address it can send from, receive to, and act on. In Claude Code it's two lines — install the MailKite plugin and authenticate in your browser, no key to copy. Any other MCP client points at the hosted remote server; prefer a static key or offline use? Run it locally. Works with Claude Code, Cursor, VS Code, Windsurf, Codex, Gemini, and any MCP client. Prefer code? It's the same REST API as everything else.

Step 1 — Get your API key

Every MailKite account gets one key the moment you sign up — a single mk_live_… token, full scope across all your domains: it can create & register domains, verify DNS, set webhooks, send, and read inbound. The same key works for your agent and your own code, so there's nothing extra to provision.

Open the dashboard → it's shown on your first screen and under Settings → API key. Copy it and hand it to your agent as MAILKITE_API_KEY:

.env
MAILKITE_API_KEY=mk_live_3a9f…
Treat it like a password — keep it in an env var or secrets vault, never commit it to a repo. Rotate it anytime from the dashboard (the old key stops working at once). Tighter, scoped agent keys are on the roadmap.

Step 2 — Connect your agent

MailKite ships an MCP server that exposes email as tools — and unlike most email MCPs, that includes reading inbound. There are three ways to connect, easiest first: the Claude Code plugin, the hosted remote server (browser OAuth, works in any MCP client), or the local stdio server for a static key or offline use.

Claude Code plugin — one install, no key to copy

The fastest path in Claude Code. Add the marketplace and install the plugin:

bash
/plugin marketplace add mailkite/claude-code
/plugin install mailkite@mailkite

Then run /mcp, pick mailkite → Authenticate, and sign in through your browser — you'll see ✓ Connected. No mk_live_… key to paste; OAuth handles it.

Remote MCP server — browser OAuth, any client

Point any MCP client at the hosted endpoint https://mcp.mailkite.dev/mcp — Streamable HTTP, secured with OAuth 2.1 / PKCE. The client walks you through sign-in on first connect; nothing to copy.

Claude Code

Register the remote server, then run /mcpAuthenticate to sign in via the browser:

bash
claude mcp add --transport http mailkite https://mcp.mailkite.dev/mcp

Headless, CI, or no browser? Pass a static key as a Bearer header instead:

bash
claude mcp add --transport http mailkite https://mcp.mailkite.dev/mcp \
  --header "Authorization: Bearer mk_live_3a9f…"

Cursor, Claude Desktop, Windsurf, Cline & Gemini

These take a remote (type: "http") server block — paste it in, then restart the client. With OAuth the client handles auth on first connect:

mcp.json
{
  "mcpServers": {
    "mailkite": {
      "type": "http",
      "url": "https://mcp.mailkite.dev/mcp"
    }
  }
}

The remote-URL field name differs per client — swap the key, keep the URL:

  • Claude Code / Cursor / Zed / Cline / Roourl
  • WindsurfserverUrl
  • Gemini (HTTP)httpUrl
  • VS Code / Copilot — top-level servers with "type": "http"

Prefer a static key over the OAuth flow? Add a headers object with your mk_live_… token:

mcp.json
{
  "mcpServers": {
    "mailkite": {
      "type": "http",
      "url": "https://mcp.mailkite.dev/mcp",
      "headers": { "Authorization": "Bearer mk_live_3a9f…" }
    }
  }
}

VS Code & GitHub Copilot

VS Code uses a top-level servers key — drop this into .vscode/mcp.json (or your user MCP config) and use Copilot's agent mode:

.vscode/mcp.json
{
  "servers": {
    "mailkite": {
      "type": "http",
      "url": "https://mcp.mailkite.dev/mcp"
    }
  }
}

Run the server locally — static key, offline, or a custom base URL

Prefer a static key, offline use, or a custom base URL? Run @mailkite/mcp locally over stdio via npx (no install; needs Node 18+). The key from step 1 goes in as MAILKITE_API_KEY. Unlike the remote server it runs fully offline — mailkite_verify_webhook needs no network at all — and it honors MAILKITE_BASE_URL to target a staging API.

Claude Code

One command registers it (add -s user to enable it across every project):

bash
claude mcp add mailkite \
  -e MAILKITE_API_KEY=mk_live_3a9f… \
  -- npx -y @mailkite/mcp

Cursor, Claude Desktop, Windsurf, Cline & Gemini

These all take the same mcpServers block — paste it in, then restart the client:

mcp.json
{
  "mcpServers": {
    "mailkite": {
      "command": "npx",
      "args": ["-y", "@mailkite/mcp"],
      "env": { "MAILKITE_API_KEY": "mk_live_3a9f…" }
    }
  }
}
  • Cursor.cursor/mcp.json (project) or ~/.cursor/mcp.json (global) — or click Add to Cursor on a deeplink badge
  • Claude Desktopclaude_desktop_config.json (Settings → Developer → Edit Config)
  • Windsurf~/.codeium/windsurf/mcp_config.json
  • Cline / Roo — the MCP Servers panel → Configure (cline_mcp_settings.json / .roo/mcp.json)
  • Gemini CLI~/.gemini/settings.json

VS Code & GitHub Copilot

VS Code uses a top-level servers key with "type": "stdio":

.vscode/mcp.json
{
  "servers": {
    "mailkite": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@mailkite/mcp"],
      "env": { "MAILKITE_API_KEY": "mk_live_3a9f…" }
    }
  }
}

Codex CLI

Codex keeps MCP servers in TOML:

~/.codex/config.toml
[mcp_servers.mailkite]
command = "npx"
args = ["-y", "@mailkite/mcp"]
env = { MAILKITE_API_KEY = "mk_live_3a9f…" }

Already use the CLI? mailkite mcp launches the same local server with your saved token.

Whichever path you pick, the 20 mailkite_* tools below appear — the five inbox-agent tools are rolling out in preview. The server is a thin layer over the MailKite SDK and the same contract it uses: one tool per endpoint, with inputs validated against the shared JSON Schemas before any request is made — so a tool can't put a malformed call on the wire. A couple of tools (like mailkite_verify_webhook) run locally, with no API call at all.

What your agent can do

ToolWhat it does
Sending
mailkite_sendSend a message over a verified domain — HTML, text, cc/bcc, attachments, and in-thread replies via inReplyTo.
Inbound messages
mailkite_list_messagesList stored messages, newest first.
mailkite_get_messageFetch one message in full — body, headers, deliveries, and attachment links.
mailkite_retry_deliveryRe-deliver a stored message to its webhook.
Domains
mailkite_list_domainsList your domains, each with its webhook URL.
mailkite_create_domainAdd a domain; returns the DNS records to set.
mailkite_get_domainGet one domain with DNS records + webhook.
mailkite_verify_domainRe-check DNS and update verification status.
mailkite_delete_domainRemove a domain.
mailkite_check_domain_availabilityCheck whether a domain is available to register, with pricing.
mailkite_register_domainRegister a domain through MailKite and auto-provision its DNS.
Webhooks
mailkite_set_webhookSet or replace the domain's catch-all webhook.
mailkite_delete_webhookRemove the domain's webhook.
mailkite_test_webhookSend a signed test event to the webhook.
mailkite_verify_webhookVerify an x-mailkite-signature header on an inbound delivery — runs locally, no API call.
Routes
mailkite_list_routesList inbound routing rules.
mailkite_create_routeCreate a route (match, action, destination) — action is webhook, forward, store, drop, or agent (hand inbound to an inbox agent).
Templates
mailkite_list_templatesList your saved email templates.
mailkite_list_base_templatesList the built-in base templates you can start from.
mailkite_get_templateFetch one template (subject + rendered HTML/text).
mailkite_create_templateSave a new email template, then send it with templateId + templateData.
Inbox agents (preview)
mailkite_create_agentCreate a built-in inbox agent — instructions, reply mode, spam, tags, escalation. Preview.
mailkite_list_agentsList your inbox agents. Preview.
mailkite_get_agentFetch one inbox agent's config. Preview.
mailkite_update_agentUpdate an inbox agent's config. Preview.
mailkite_delete_agentRemove an inbox agent. Preview.

Drop-in AI skill

Prefer a coding agent? The MailKite agent skill wires email into your agent in one step — download the zip, drop it into Claude Code or claude.ai, and it drives the whole lifecycle (domains, DNS, webhooks, sending, inbound) over MCP, the CLI, any SDK, or REST.

Download the skill Install guide →

Why give an agent an inbox

  • Email is your agent's identity. Sign-ups, verification, and 2FA codes land in an inbox the agent owns and reads — no OAuth, no human in the loop.
  • Inbound it can act on. Received mail is parsed to clean JSON and kept in a queryable store, so the agent reasons over the full message and replies in-thread.
  • One inbox per agent. Unlimited domains and addresses — a fleet of agents means a fleet of inboxes, with no per-domain tax.

Run your own agent loop

If you run your own agent loop, route the inbound webhook straight into it, then take the agent's response and hand it to the SDK's send with inReplyTo (the Send API under the hood) to respond in-thread:

Don't want to host a loop at all? A built-in inbox agent can triage, reply, filter spam, tag, and escalate in MailKite's pipeline — no server to run.

agent hook
import { MailKite } from "mailkite";

const mk = new MailKite(process.env.MAILKITE_API_KEY);

// Hand inbound mail to your agent loop, then send its reply.
app.post("/hooks/mailkite", async (req, res) => {
  res.sendStatus(200); // ack fast
  const event = req.body;
  if (event.type !== "email.received") return;

  // 1. Let the agent reason over the message and produce a reply.
  const reply = await agent.run({
    role: "user",
    content: `New email from ${event.from.address}: ${event.subject}\n\n${event.text}`,
  });

  // 2. Feed the agent's response straight to the Send API, in-thread.
  await mk.send({
    from: event.to[0].address,   // the agent's own address
    to: event.from.address,
    subject: `Re: ${event.subject}`,
    text: reply.content,
    inReplyTo: event.threadId,   // keeps it in the same conversation
  });
});
Give each agent its own address — a per-address route (mailkite_create_route) or its own domain (mailkite_create_domain) — so its mail, context, and replies stay cleanly separated.

Ready to wire one up? Create an agent inbox or read the API reference.