Skip to main content
Glama
ZapSMTP

ZapSMTP MCP server

Official
by ZapSMTP

ZapSMTP MCP server

The official Model Context Protocol server for ZapSMTP: let Claude, Cursor, VS Code, Codex and any other MCP client send, receive and track email, and manage templates, domains, webhooks and everything else the API does.

  • The whole API: one tool per API operation (112), generated from the API reference, so a new endpoint becomes a tool with the next release. Clear descriptions and JSON Schemas with every parameter, required field and allowed value.

  • Safe to hand to an agent: tool annotations (read-only, destructive, idempotent, open-world) for clients that ask before acting, --read-only, toolsets, a recipient domain allowlist, and sends that never repeat when retried. The API key never reaches the model.

  • Made for agents: send_test_email tries any delivery outcome on simulator addresses that never leave ZapSMTP; verify_webhook_signature checks webhook requests; lists come back one page at a time with a cursor for the next; errors carry the API's code, message and request id.

  • stdio or Streamable HTTP: run it next to your editor, or serve a team over HTTP where every client brings its own API key.

  • The docs as resources: llms.txt and every guide, bundled in the package (nothing is fetched at runtime).

Node.js 18.3 or newer. Built on the official Node.js SDK.

Quick start

Create an API key in the dashboard (a zap_test_… key runs everything without delivering anything), then add the server to your client.

Claude Code

claude mcp add zapsmtp -e ZAP_API_KEY=zap_... -- npx -y zapsmtp-mcp

With a default sender and only the tools you need:

claude mcp add zapsmtp -e ZAP_API_KEY=zap_... -e ZAP_SENDER="Acme <hello@acme.com>" \
  -- npx -y zapsmtp-mcp --toolsets emails,templates,simulator

Claude Desktop

Settings → Developer → Edit Config (claude_desktop_config.json):

{
  "mcpServers": {
    "zapsmtp": {
      "command": "npx",
      "args": ["-y", "zapsmtp-mcp"],
      "env": { "ZAP_API_KEY": "zap_..." }
    }
  }
}

Cursor

~/.cursor/mcp.json (every project) or .cursor/mcp.json (one project):

{
  "mcpServers": {
    "zapsmtp": {
      "command": "npx",
      "args": ["-y", "zapsmtp-mcp"],
      "env": { "ZAP_API_KEY": "zap_..." }
    }
  }
}

VS Code (GitHub Copilot agent mode)

.vscode/mcp.json; VS Code asks for the key once and stores it securely:

{
  "inputs": [
    { "type": "promptString", "id": "zapsmtp-key", "description": "ZapSMTP API key", "password": true }
  ],
  "servers": {
    "zapsmtp": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "zapsmtp-mcp"],
      "env": { "ZAP_API_KEY": "${input:zapsmtp-key}" }
    }
  }
}

OpenAI Codex

codex mcp add zapsmtp --env ZAP_API_KEY=zap_... -- npx -y zapsmtp-mcp

or in ~/.codex/config.toml:

[mcp_servers.zapsmtp]
command = "npx"
args = ["-y", "zapsmtp-mcp"]
env = { ZAP_API_KEY = "zap_..." }

Windsurf

~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "zapsmtp": {
      "command": "npx",
      "args": ["-y", "zapsmtp-mcp"],
      "env": { "ZAP_API_KEY": "zap_..." }
    }
  }
}

Zed

settings.json:

{
  "context_servers": {
    "zapsmtp": {
      "source": "custom",
      "command": "npx",
      "args": ["-y", "zapsmtp-mcp"],
      "env": { "ZAP_API_KEY": "zap_..." }
    }
  }
}

Gemini CLI

~/.gemini/settings.json (Gemini CLI expands $ZAP_API_KEY from your environment):

{
  "mcpServers": {
    "zapsmtp": {
      "command": "npx",
      "args": ["-y", "zapsmtp-mcp"],
      "env": { "ZAP_API_KEY": "$ZAP_API_KEY" }
    }
  }
}

Any other client

Run npx -y zapsmtp-mcp over stdio with ZAP_API_KEY in its environment, or connect to the HTTP server below.

Related MCP server: packet-pigeon

Streamable HTTP

npx -y zapsmtp-mcp --http                  # http://127.0.0.1:3000/mcp
npx -y zapsmtp-mcp --http --port 8080 --host 0.0.0.0

The HTTP server holds no API key. Every client sends its own as Authorization: Bearer <key>, and each request gets its own SDK client and MCP server (the server is stateless), so one client's key is never used for another's calls. A request without a key gets 401.

claude mcp add --transport http zapsmtp http://127.0.0.1:3000/mcp --header "Authorization: Bearer zap_..."
{
  "mcpServers": {
    "zapsmtp": { "url": "http://127.0.0.1:3000/mcp", "headers": { "Authorization": "Bearer zap_..." } }
  }
}
  • It listens on 127.0.0.1 unless --host says otherwise, and while on loopback it refuses requests whose Host or Origin is not local (DNS rebinding).

  • Beyond your machine, put it behind HTTPS (a reverse proxy): the key travels in a header.

  • GET /health answers {"status": "ok"} for load balancers. Request bodies are limited to 64 MiB.

Options

Flag

Environment

Default

--key <key>

ZAP_API_KEY

API key (stdio). Not used with --http.

--http

off

Serve Streamable HTTP at /mcp instead of stdio

--port <port>

ZAP_MCP_PORT

3000

HTTP port

--host <host>

ZAP_MCP_HOST

127.0.0.1

HTTP address

--toolsets <a,b>

ZAP_TOOLSETS

the defaults below

Toolsets to expose, or all

--read-only

ZAP_READ_ONLY=1

off

Only tools that change nothing

--sender <address>

ZAP_SENDER

From for sends that omit it; without one, sends require from

--reply-to <address>

ZAP_REPLY_TO

Reply-To for sends that omit it

--allowed-recipient-domains <a,b>

ZAP_ALLOWED_RECIPIENT_DOMAINS

Refuse sends to any other domain

--base-url <url>

ZAP_BASE_URL

https://api.zapsmtp.com/v1

API base URL

--list-tools

Print the tools these options expose, and exit

-h, --help / -v, --version

Flags win over the environment.

Toolsets

The default toolsets give 76 tools; --read-only leaves 41 of them. Clients that slow down with many tools do best with just the toolsets they need: --toolsets emails,simulator is 14 tools.

Toolset

Default

Tools

emails

yes

12

emails_send, emails_send_batch, emails_list, emails_get, emails_update, emails_cancel, emails_get_content, emails_spam_check, emails_spam_check_sent, emails_attachments_list, emails_attachments_get, emails_share

receiving

yes

8

emails_receiving_list, emails_receiving_get, emails_receiving_delete, emails_receiving_attachments_list, emails_receiving_attachments_get, emails_receiving_redeliver, emails_receiving_report_spam, emails_receiving_reply

threads

yes

3

threads_list, threads_get, threads_update

templates

yes

12

templates_list, templates_create, templates_get, templates_update, templates_delete, templates_render, templates_render_source, templates_publish, templates_duplicate, templates_versions_list, templates_versions_get, templates_versions_restore

variables

yes

3

variables_list, variables_set_global, variables_delete_global

domains

yes

11

domains_list, domains_create, domains_get, domains_update, domains_verify, domains_delete, domains_get_dmarc, domains_get_reputation, domains_check_reputation, domains_get_brand, domains_update_brand

webhooks

yes

12

webhooks_list, webhooks_create, webhooks_get, webhooks_update, webhooks_delete, webhooks_test, webhooks_list_deliveries, webhooks_rotate_secret, webhooks_events_replay, webhooks_events_list, webhooks_events_get, verify_webhook_signature

suppressions

yes

6

suppressions_list, suppressions_create, suppressions_delete, suppressions_get, suppressions_create_batch, suppressions_delete_batch

logs

yes

2

logs_list, logs_get

stats

yes

4

stats_get, stats_timeseries, stats_breakdown, stats_metrics

usage

yes

1

usage_get

simulator

yes

2

simulator_get, send_test_email

inbound

16

inbound domains, routes and forward destinations

actions

5

click actions

template_modules

5

reusable template modules

template_assets

3

images hosted for templates

template_timers

1

countdown timer images

api_keys

4

create, update and revoke API keys

smtp_credentials

3

SMTP relay credentials

dedicated_ips

1

dedicated sending IPs

zapsmtp-mcp --list-tools --toolsets all prints every tool. Tool names follow the Node.js SDK: zap.templates.versions.get is templates_versions_get.

What the tools do

  • Arguments are the API's parameters by their API names (reply_to, scheduled_at), path parameters included (templates_versions_get takes id and vid). Unknown or missing arguments are refused before anything is sent.

  • Results are the API's JSON. A list returns one page: {data, has_more, next_cursor}; pass next_cursor back as cursor for the next page with the same filters. An operation without a body returns {"ok": true}.

  • Errors are tool errors (isError) with {"error": {status, code, type, message, request_id}}, so the model can correct itself; quote the request_id to support.

  • Sends (emails_send, emails_send_batch, emails_receiving_reply) take an idempotency_key; the server makes one when it is omitted, so the SDK's automatic retries never send twice.

  • send_test_email sends to the simulator address of a scenario (delivered, bounced, full, blocked, delayed, complained, suppressed, or any SMTP reply as bounce+<code>…) and returns the email id with the event to expect.

  • verify_webhook_signature checks a webhook request's Zap-Signature against its raw body and the endpoint's secret, locally, and returns its events (several for a batch webhook).

Annotations: tools for GET requests, renders and spam checks are readOnlyHint. Deletes, cancelling a scheduled email, rotating a webhook secret, removing suppressions and restoring a template version are destructiveHint. Sends, test webhooks and replays are openWorldHint. Updates, deletes and verifications are idempotentHint.

Resources

When the package was built with the docs site, resources/list offers https://zapsmtp.com/llms.txt (an index of the docs) and every guide as Markdown, for example https://zapsmtp.com/docs/sending.md. They are read from the package; nothing is fetched.

Safety

  • The key stays out of the conversation. It is read from the environment or a flag and sent only to the API. Tool results and errors are scrubbed of it, and the server writes nothing about it to its logs. Prefer the environment (or VS Code's promptString input) over --key, which shows in process lists.

  • Scope the key. Give the agent a zap_test_… key while you try things, and a key restricted to sending, one domain or one stream (api_keys_create) for production use.

  • Limit what the agent can do: --read-only, --toolsets, and --allowed-recipient-domains acme.com,example.org, which refuses sends to any other domain (and its subdomains) before any request is made. Under the allowlist, emails_receiving_reply must name its recipients in to and cannot use reply_all, since the original sender's domain is unknown until the API answers. send_test_email always sends to the simulator.

  • Review before approving: destructive tools are annotated, so clients that ask before running a tool (Claude Code, Claude Desktop, VS Code, Cursor) show which calls change or delete things.

  • HTTP: loopback by default with Host/Origin checks; use HTTPS beyond your machine.

Embedding

import { API, buildTools, createServer, makeClient } from 'zapsmtp-mcp';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const tools = buildTools(API, { toolsets: ['emails', 'simulator'], sender: 'hello@acme.com' });
const server = createServer({ client: makeClient({ apiKey: process.env.ZAP_API_KEY! }), tools });
await server.connect(new StdioServerTransport());

Development

cd sdks/node && npm ci && npm run build   # the SDK this package uses
cd ../mcp && npm ci
npm run generate    # src/generated/ by sdks/codegen (emit/mcp.mjs); the build fails when it is stale
npm test            # every tool against the conformance server, HTTP auth, safety options
npm run coverage    # 100% of the hand-written code
npm run build       # the codegen check, dist/, and docs/ from landing/zapsmtp-site/dist when it is built
../live/run.sh mcp  # against the dev API

src/generated/ is generated by sdks/codegen (emit/mcp.mjs; the code calling the SDK comes from codegen/templates/tools-model.ts, shared with the CLI); src/catalog.ts holds the hand-written choices (toolsets, annotations, descriptions).

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI models to send emails, manage contacts, and interact with SendGrid's email platform via MCP.
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to read, search, send, manage, schedule, and analyze email across multiple IMAP/SMTP accounts through MCP, including drafts and templates, provider-aware labels, bulk operations, real-time IMAP IDLE watching with AI triage, verification-code capture, calendar extraction, and analytics.
    21 npm
    ISC
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to search, read, send, reply to, forward, organize, and bulk-delete email across multiple IMAP/SMTP mailboxes, with AES-256-encrypted credential storage, connection pooling, and folder management. Supports 15+ pre-configured providers and simultaneous multi-account access from any MCP client.
    929 npm
    MIT