MCP Server
The Zyphr MCP Server lets any MCP-compatible AI client call Zyphr directly — sending emails, push notifications, SMS, and in-app messages, rendering templates, managing subscribers, and inspecting webhook deliveries — all from inside the model loop. No bespoke wrapper code required.
Model Context Protocol is an open standard for connecting AI assistants to external tools and data. If your AI client speaks MCP, this server plugs Zyphr in.
Install
npx -y @zyphr-dev/mcp-server
The binary is also exposed as zyphr-mcp when installed as a dependency.
Configure
Add the server to your MCP client's configuration:
{
"mcpServers": {
"zyphr": {
"command": "npx",
"args": ["-y", "@zyphr-dev/mcp-server"],
"env": {
"ZYPHR_API_KEY": "zy_test_..."
}
}
}
}
End users always point at production (https://api.zyphr.dev/v1) using either a zy_test_* or zy_live_* key from the Zyphr Dashboard.
Environment variables
| Variable | Required | Default | Notes |
|---|---|---|---|
ZYPHR_API_KEY | Yes | — | zy_live_* or zy_test_* |
ZYPHR_BASE_URL | No | https://api.zyphr.dev/v1 | Override for non-production environments |
ZYPHR_READ_ONLY | No | false | When true, mutating tools are not registered |
ZYPHR_ALLOWED_TOOLS | No | (all) | Comma-separated whitelist of tool names. Overrides ZYPHR_READ_ONLY |
The server fails fast with a clear stderr message if ZYPHR_API_KEY is missing.
Tools
Integration (zero-to-first-send helpers)
| Tool | Description |
|---|---|
get_sdk_install_for_language | Returns install commands, init snippet, env vars, and a docs link for the chosen language (node, python, ruby, go, php, csharp). Pass an optional packageManager (e.g. yarn, poetry) to narrow to a single command. |
get_quickstart_for_channel | Returns drop-in service file(s) for the chosen channel (email, push, sms, inbox, webhook), language, and optional framework (express, nextjs, flask, fastapi, rails, laravel, aspnetcore). Webhook handlers always verify the HMAC signature; unknown framework hints fall back to plain SDK code. |
Send
| Tool | Description |
|---|---|
send_email | Send a transactional email. Supports inline html/text or templateId + templateData. |
send_push | Send a push notification to a user, device, or subscriber. |
send_sms | Send an SMS message (E.164 recipient). |
send_inbox_message | Deliver an in-app inbox message to a subscriber. |
Templates
| Tool | Description |
|---|---|
list_templates | List templates in the account. |
get_template | Fetch a single template by ID. |
render_template | Preview a template with the given variables without sending. Returns the rendered subject/html/text. |
create_template | Create a new template. |
Subscribers
| Tool | Description |
|---|---|
find_subscriber | Look up a subscriber by external ID. |
list_subscribers | List subscribers (filter by status or email). |
create_subscriber | Create a new subscriber. |
update_subscriber | Update a subscriber. Pass null for email/phone/name/avatarUrl to clear them. |
set_subscriber_preferences | Set notification preferences for a subscriber. |
Webhooks
| Tool | Description |
|---|---|
list_webhooks | List configured webhook endpoints. |
create_webhook | Register a new webhook endpoint subscribed to one or more event types. |
get_webhook_deliveries | Inspect delivery history for a webhook (filter by status, event type, or date range). |
Domains
| Tool | Description |
|---|---|
add_domain | Register a sending domain and return the DNS records (TXT + CNAME) to publish. Idempotent — calling with an already-registered domain returns the existing record. |
list_domains | List sending domains with verification status and DNS records. |
get_domain | Get a sending domain by ID, including per-record verified flags and records_verified / records_total counters. |
verify_domain | Queue an asynchronous DNS verification check. Poll get_domain (or subscribe to the domain.verified webhook event) for terminal status. |
delete_domainThis server intentionally does not expose destructive delete_* operations through MCP. A bad model call could detach an SES identity, invalidate scheduled sends, and break templates hardcoded to a sender. If your workflow needs scripted domain teardown, call zyphr.domains.deleteDomain(id) from the Node SDK directly — that's a deliberate developer action, not an AI tool call. The dashboard works for one-off cleanup.
Auth Organizations
| Tool | Description |
|---|---|
list_organizations | List organizations in the current environment. Cursor-paginated; pass the cursor from the prior response to walk pages. |
get_organization | Fetch a single organization by ID. |
create_organization | Create a new organization. Requires Pro / Scale / Enterprise; Free and Starter return 403 plan_upgrade_required. |
update_organization | Update an organization's name, slug, or metadata. Cannot rename the Default org. |
list_organization_members | List end-user memberships in an organization. Cursor-paginated. |
add_organization_member | Add an end-user to an organization. Adding to a non-Default org is plan-gated; gated calls return 403 plan_upgrade_required. |
update_organization_member_role | Update a membership's role label. Role is an opaque customer-defined string. |
remove_organization_member | Remove an end-user from an organization. Cannot remove the last member of the Default org. |
list_organizations_for_user | List every organization an end-user belongs to within the environment. Useful when the JWT orgs[] claim is capped at 50 and you need the full set. |
The same delete_* exclusion applies — there is no delete_organization tool. Call zyphr.auth.organizations.deleteOrganization(id) from the Node SDK if you need scripted teardown.
Safety
Two environment variables let you scope what the AI is allowed to do:
ZYPHR_READ_ONLY=truesuppresses every mutating tool (sends, creates, updates). Only the read-only tools (list_*,get_*,find_*,render_template,get_webhook_deliveries) remain. Use this when you want the AI to investigate or report without touching state.ZYPHR_ALLOWED_TOOLS="tool_a,tool_b"is a comma-separated whitelist. When set, only those tools are registered. The whitelist takes precedence overZYPHR_READ_ONLY, so you can explicitly allow a mutating tool inside an otherwise read-only profile.
No delete_* tools are exposed in this release. Destructive operations remain dashboard-only.
Example prompts
Once connected, your AI client can act on prompts like:
- "I'm starting a new Node project and want to use Zyphr — what do I install?" → calls
get_sdk_install_for_language - "Add Zyphr email to my Express app." → calls
get_quickstart_for_channel - "Show me how to verify a Zyphr webhook in a FastAPI route." → calls
get_quickstart_for_channel, returns a handler with HMAC verification - "Send a welcome email to alice@example.com with subject 'Welcome to Acme' and a short HTML greeting."
- "Preview the welcome email template with
name='Alice'and verify that the verify link is included." - "Look up the subscriber for external ID
user_123and update their email preferences for marketing to false." - "Push a notification titled 'Order shipped' to subscriber
usr_42." - "Send an SMS to +14155551234 confirming their appointment."
- "Drop an inbox message for subscriber
usr_42with title 'New report ready' and an action URL to the report page." - "Show me the last 20 webhook deliveries for webhook
whk_abcthat failed in the past hour and tell me why." - "Add
sprint.example.comas a sending domain and show me the DNS records I need to publish." - "Has
sprint.example.comfinished verifying? If not, tell me which records are still pending."
Errors from the Zyphr API are surfaced verbatim as MCP errors, so the AI can react to validation failures, rate limits, or auth problems without guessing.
Package & versioning
- npm:
@zyphr-dev/mcp-server - Transport: stdio (every desktop MCP client supports stdio out of the box)