SpacePost

dev.spacepostPublished by spacepost.devOfficial publisherv0.2.2Updated Nov 4, 2026

Send email and manage domains, contacts and webhooks on SpacePost, the Resend-compatible email API.

VerifiedStreamable HTTPWeb executableCommunication & CollaborationBusiness & Commerce

Overview

AI-generated overview

SpacePost MCP exposes the SpacePost (Resend-compatible) email API so an assistant can send email and manage domains, contacts, broadcasts and webhooks.

What you can do
  • Send single or batch emails, schedule them, and list, reschedule or cancel queued emails
  • Register, verify, update and delete sending domains, including DNS record details
  • Manage audiences and their contacts, plus suppressions and tenants
  • Create, update, delete and send or schedule broadcasts, with a pre-send deliverability readiness check
  • Manage API keys and webhooks
  • Filter the exposed tools by API area, read-only mode or sending-only permission
When to use it
Useful when you want an assistant to draft and send transactional or broadcast email through SpacePost, or to inspect and configure the account's domains, audiences, contacts and webhooks from a chat session.
Requirements
A SpacePost account and API key (sp_live_...) created in the dashboard, passed as SPACEPOST_API_KEY or an Authorization bearer header. Runs either as a hosted Streamable HTTP endpoint or locally via npx @spacepost/mcp over stdio; the local package bundles the spec and starts offline. Optional settings cover default sender, base URL, read-only mode, toolsets and permission.
Before you install
The assistant acts with exactly the key's permissions, so a full_access key can create and delete domains, API keys, webhooks, audiences and contacts, and send mail. Sending consumes quota per recipient, and broadcasts go to every subscribed contact of an audience. Creating an API key returns its token once. Deleting an audience also deletes its contacts. Prefer a sending_access or read-only configuration when write access is not needed.

Installation

In SourceWeft

  1. Open SpacePost in the dashboard and add it to a workspace.
  2. Connect Authorization token credentials. They are stored privately and never shown on public pages.
  3. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/dev.spacepost%2Fmcp/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config.

{
  "mcpServers": {
    "spacepost": {
      "type": "http",
      "url": "https://api.spacepost.dev/mcp",
      "headers": {
        "Authorization": "Bearer <YOUR_TOKEN>"
      }
    }
  }
}

README

[SpacePost]

@spacepost/mcp

[SpacePost MCP server on Glama]

An MCP server that gives AI assistants the whole SpacePost API: one tool per endpoint of the API reference, generated from the OpenAPI document. New API features become MCP tools automatically. Docs: https://docs.spacepost.dev/tools/mcp/

SpacePost is a Resend-compatible transactional email API on Amazon SES (EU company), with an SMTP relay and this MCP server.

Two ways to use it:

  • Hosted: https://api.spacepost.dev/mcp (Streamable HTTP) with Authorization: Bearer sp_live_.... Nothing to install.
  • Local (this package): npx -y @spacepost/mcp, stdio. The spec is bundled, so it starts offline.

Create an API key in the SpacePost dashboard. In the official MCP Registry the server is dev.spacepost/mcp; on npm it is @spacepost/mcp.

Configuration

Env
SPACEPOST_API_KEYRequired. The assistant has exactly this key's permissions (sending_access keys can only send).
SPACEPOST_BASE_URLOptional, default https://api.spacepost.dev
SPACEPOST_DEFAULT_FROMOptional sender (e.g. Acme <[email protected]>) used when send_email has no from
SPACEPOST_READ_ONLYtrue = --read-only
SPACEPOST_TOOLSETS= --toolsets
SPACEPOST_PERMISSION= --permission
Flag
--read-onlyOnly tools for GET endpoints
--toolsets a,bOnly these API areas (OpenAPI tags): emails, domains, apikeys, webhooks, audiences, contacts, broadcasts, suppressions, tenants
--permission sending_accessOnly tools a send-only key can use (operations with x-permission: sending_access)
--list-toolsPrint the tools for the given options and exit
--help, --version

The hosted endpoint takes the same options as query parameters: /mcp?read_only=true&toolsets=emails,domains. It derives the permission filter from the caller's key: sending_access keys see only the sending tools in tools/list. Other tools are not blocked by MCP; calling one goes to the API, which answers restricted_api_key as it does for REST.

Claude Code

bash
# hostedclaude mcp add --transport http spacepost https://api.spacepost.dev/mcp --header "Authorization: Bearer sp_live_..."# localclaude mcp add spacepost -e SPACEPOST_API_KEY=sp_live_... -e SPACEPOST_DEFAULT_FROM="Acme <[email protected]>" -- npx -y @spacepost/mcp

Cursor (~/.cursor/mcp.json or .cursor/mcp.json)

json
{  "mcpServers": {    "spacepost": { "url": "https://api.spacepost.dev/mcp", "headers": { "Authorization": "Bearer sp_live_..." } }  }}

Claude Desktop (claude_desktop_config.json)

json
{  "mcpServers": {    "spacepost": {      "command": "npx",      "args": ["-y", "@spacepost/mcp"],      "env": { "SPACEPOST_API_KEY": "sp_live_...", "SPACEPOST_DEFAULT_FROM": "Acme <[email protected]>" }    }  }}

Docker

bash
docker build -t spacepost-mcp .docker run -i --rm -e SPACEPOST_API_KEY=sp_live_... spacepost-mcp

The image builds the server from this repo's source and runs it over stdio as a non-root user. The key is read from the environment at runtime; nothing is baked into the image.

How tools are built

  • Name: operationId in snake_case (sendEmail → send_email, getBroadcastReadiness → get_broadcast_readiness). The 12 hand-written tools of 0.1 keep their names.
  • Input: one flat JSON Schema object with path params (snake_case: audience_id, id_or_email), query params, header params (Idempotency-Key → idempotency_key) and the top-level JSON body fields. A body field that collides with a parameter name is exposed as body_<field>; a non-object body (the batch array) as body. $ref/allOf are inlined; enums, formats, patterns, bounds, defaults and descriptions are kept.
  • Description: summary + description from the spec, curated extras, the key permission and the HTTP route.
  • Annotations: GET → readOnlyHint; DELETE → destructiveHint; GET/PUT/DELETE → idempotentHint; overridable per operation.
  • Result: the API's JSON (text + structuredContent). Errors: isError: true with the Resend-style { statusCode, name, message } body and a hint.

Tuning a tool

Tools follow the API's OpenAPI document. Operations carry these extensions (set by SpacePost in the spec):

yaml
x-mcp: { hidden: false, description: "Extra guidance for agents.", destructive: true, idempotent: true, openWorld: true }x-permission: sending_access # only on operations a sending_access key may call

src/overlay.ts (keyed by operationId) holds the few curated descriptions that are about using a tool well rather than the API itself; x-mcp wins when both set a field.

Development

bash
bun installbun run build     # dist/index.js, spec includedbun testbun run generate  # refresh src/generated/openapi.json from https://api.spacepost.dev/openapi.json

Issues and pull requests are welcome. Security reports: [email protected].

0.2 breaking changes: results are the raw API JSON instead of short text summaries, and verify_domain returns the verify response (call get_domain for the new status).

License

MIT, see LICENSE. © Studio 404 d.o.o.

Source: README.md at commit eeb7307

Tools

46

list_emails

List emails

List emails. Returns sent and scheduled emails, newest first, without bodies. Requires a `full_access` API key. API: `GET /emails` (operationId `listEmails`, Emails).

Parametersafterlimitbefore

send_email

Send an email

Send an email. Validates and queues one email. Each recipient counts towards your quota. Use `scheduled_at` to send later (up to 30 days ahead). Pass `tenant_id` to send on behalf of a tenant (not needed when the `from` domain belongs to one). Fails with `422` if `tenant_id` conflicts with the domain's tenant, `403 sending_paused` if the tenant is paused and `429 daily_quota_exceeded` if it reached its daily cap. `from` must be on a verified domain (e.g. "Acme <[email protected]>"); call list_domains to find one. Provide `html`, `text` or both. Send to [email protected] (or bounced@ / complained@) to test without sending real mail. Delivered email cannot be recalled: confirm recipients and content with the user when unsure. Pass `idempotency_key` when retrying so the email is not sent twice. Request body: Either `html` or `text` is required. `reply_to` is also accepted as `replyTo` and `scheduled_at` as `scheduledAt`. Works with a `sending_access` or `full_access` API key. API: `POST /emails` (operationId `sendEmail`, Emails).

Parameterscctorequiredbccfromrequiredhtmltagstextheaderssubjectrequiredreply_totenant_idattachments+2 more

send_batch_emails

Send batch emails

Send batch emails. Sends up to 100 emails in one call. All-or-nothing, if any email is invalid none are sent. Attachments, `scheduled_at` and a per-email `tenant_id` are supported; the paused-tenant and tenant-cap errors apply to the whole batch. Put the emails in `body` as an array. Prefer send_email for a single message. Works with a `sending_access` or `full_access` API key. API: `POST /emails/batch` (operationId `sendBatchEmails`, Emails).

Parametersbodyrequiredidempotency_key

get_email

Retrieve an email

Retrieve an email. Requires a `full_access` API key. API: `GET /emails/{id}` (operationId `getEmail`, Emails).

Parametersidrequired

update_email

Reschedule an email

Reschedule an email. Changes `scheduled_at` of an email that is still `scheduled`. Requires a `full_access` API key. API: `PATCH /emails/{id}` (operationId `updateEmail`, Emails).

Parametersidrequiredscheduled_atrequired

cancel_email

Cancel a scheduled email

Cancel a scheduled email. Requires a `full_access` API key. API: `POST /emails/{id}/cancel` (operationId `cancelEmail`, Emails).

Parametersidrequired

list_domains

List domains

List domains. Requires a `full_access` API key. API: `GET /domains` (operationId `listDomains`, Domains).

Parametersafterlimitbefore

create_domain

Create a domain

Create a domain. Registers a domain and returns the DNS records to add (three DKIM CNAMEs, plus MX and SPF on the MAIL FROM subdomain). Domain names are globally unique. The number of domains is limited by your plan (Free 3, Pro 10, Scale 1,000). The response lists the DNS records (DKIM CNAMEs, MAIL FROM MX and SPF TXT) the user must add at their DNS provider; afterwards call verify_domain and then get_domain to see the new status. DNS changes can take minutes to hours. Requires a `full_access` API key. API: `POST /domains` (operationId `createDomain`, Domains).

Parametersnamerequiredregiontenant_idcustom_return_path

get_domain

Retrieve a domain

Retrieve a domain. Requires a `full_access` API key. API: `GET /domains/{id}` (operationId `getDomain`, Domains).

Parametersidrequired

update_domain

Update a domain

Update a domain. Toggles open and click tracking. Requires a `full_access` API key. API: `PATCH /domains/{id}` (operationId `updateDomain`, Domains).

Parametersidrequiredtlsopen_trackingclick_tracking

delete_domain

Delete a domain

Delete a domain. Requires a `full_access` API key. API: `DELETE /domains/{id}` (operationId `deleteDomain`, Domains).

Parametersidrequired

verify_domain

Verify a domain

Verify a domain. Re-checks DNS now. Retrieve the domain afterwards to read the new `status` and per-record statuses. Requires a `full_access` API key. API: `POST /domains/{id}/verify` (operationId `verifyDomain`, Domains).

Parametersidrequired

list_api_keys

List API keys

List API keys. Requires a `full_access` API key. API: `GET /api-keys` (operationId `listApiKeys`, API Keys).

Parametersafterlimitbefore

create_api_key

Create an API key

Create an API key. The `token` is returned only in this response. Requires a `full_access` API key. API: `POST /api-keys` (operationId `createApiKey`, API Keys).

Parametersnamerequireddomain_idpermission

delete_api_key

Delete an API key

Delete an API key. The key stops working immediately. The response body is an empty object. Requires a `full_access` API key. API: `DELETE /api-keys/{id}` (operationId `deleteApiKey`, API Keys).

Parametersidrequired

list_webhooks

List webhooks

List webhooks. Requires a `full_access` API key. API: `GET /webhooks` (operationId `listWebhooks`, Webhooks).

Parametersafterlimitbefore

create_webhook

Create a webhook

Create a webhook. In production the endpoint must use https and resolve to a public address. Requires a `full_access` API key. API: `POST /webhooks` (operationId `createWebhook`, Webhooks).

Parameterseventsrequiredendpointrequired

get_webhook

Retrieve a webhook

Retrieve a webhook. Requires a `full_access` API key. API: `GET /webhooks/{id}` (operationId `getWebhook`, Webhooks).

Parametersidrequired

update_webhook

Update a webhook

Update a webhook. Requires a `full_access` API key. API: `PATCH /webhooks/{id}` (operationId `updateWebhook`, Webhooks).

Parametersidrequiredeventsstatusendpoint

delete_webhook

Delete a webhook

Delete a webhook. Requires a `full_access` API key. API: `DELETE /webhooks/{id}` (operationId `deleteWebhook`, Webhooks).

Parametersidrequired

list_audiences

List audiences

List audiences. Requires a `full_access` API key. API: `GET /audiences` (operationId `listAudiences`, Audiences).

Parametersafterlimitbefore

create_audience

Create an audience

Create an audience. Requires a `full_access` API key. API: `POST /audiences` (operationId `createAudience`, Audiences).

Parametersnamerequired

get_audience

Retrieve an audience

Retrieve an audience. Requires a `full_access` API key. API: `GET /audiences/{id}` (operationId `getAudience`, Audiences).

Parametersidrequired

delete_audience

Delete an audience

Delete an audience. Also deletes its contacts. Requires a `full_access` API key. API: `DELETE /audiences/{id}` (operationId `deleteAudience`, Audiences).

Parametersidrequired

list_contacts

List contacts

List contacts. Requires a `full_access` API key. API: `GET /audiences/{audienceId}/contacts` (operationId `listContacts`, Contacts).

Parametersafterlimitbeforeaudience_idrequired

create_contact

Create a contact

Create a contact. Emails are lower-cased. An address can only appear once per audience. Requires a `full_access` API key. API: `POST /audiences/{audienceId}/contacts` (operationId `createContact`, Contacts).

Parametersemailrequiredlast_namefirst_nameaudience_idrequiredunsubscribed

get_contact

Retrieve a contact

Retrieve a contact. Requires a `full_access` API key. API: `GET /audiences/{audienceId}/contacts/{idOrEmail}` (operationId `getContact`, Contacts).

Parametersaudience_idrequiredid_or_emailrequired

update_contact

Update a contact

Update a contact. Requires a `full_access` API key. API: `PATCH /audiences/{audienceId}/contacts/{idOrEmail}` (operationId `updateContact`, Contacts).

Parameterslast_namefirst_nameaudience_idrequiredid_or_emailrequiredunsubscribed

delete_contact

Delete a contact

Delete a contact. Requires a `full_access` API key. API: `DELETE /audiences/{audienceId}/contacts/{idOrEmail}` (operationId `deleteContact`, Contacts).

Parametersaudience_idrequiredid_or_emailrequired

list_broadcasts

List broadcasts

List broadcasts. Requires a `full_access` API key. API: `GET /broadcasts` (operationId `listBroadcasts`, Broadcasts).

Parametersafterlimitbefore

create_broadcast

Create a broadcast

Create a broadcast. Creates a draft. The `from` address must belong to a verified domain of your team and `audience_id` to one of your audiences. Requires a `full_access` API key. API: `POST /broadcasts` (operationId `createBroadcast`, Broadcasts).

Parametersfromrequiredhtmlnametextsubjectrequiredreply_toaudience_idrequiredpreview_text

get_broadcast

Retrieve a broadcast

Retrieve a broadcast. Requires a `full_access` API key. API: `GET /broadcasts/{id}` (operationId `getBroadcast`, Broadcasts).

Parametersidrequired

update_broadcast

Update a broadcast

Update a broadcast. Only drafts can be updated. Request body: Any field of the create request; only drafts can be updated. Requires a `full_access` API key. API: `PATCH /broadcasts/{id}` (operationId `updateBroadcast`, Broadcasts).

Parametersidrequiredfromhtmlnametextsubjectreply_toaudience_idpreview_text

delete_broadcast

Delete a broadcast

Delete a broadcast. Only drafts and broadcasts that are scheduled for the future can be deleted. Requires a `full_access` API key. API: `DELETE /broadcasts/{id}` (operationId `deleteBroadcast`, Broadcasts).

Parametersidrequired

get_broadcast_readiness

Check a broadcast before sending

Check a broadcast before sending. SpacePost extension (not part of Resend). Returns a deliverability checklist: sender domain and DMARC, subject, Gmail clipping (HTML over 102 KB), image-heavy bodies, link shorteners, spam phrases, unsubscribe link and audience quality. `ready` is false when any check has level `error`; `POST /broadcasts/{id}/send` is then refused with `validation_error`. Warnings never block a send. Requires a `full_access` API key. API: `GET /broadcasts/{id}/readiness` (operationId `getBroadcastReadiness`, Broadcasts).

Parametersidrequired

send_broadcast

Send or schedule a broadcast

Send or schedule a broadcast. Queues a draft for delivery to every subscribed contact of its audience. The broadcast needs `html` or `text`. Without `scheduled_at` it starts immediately; the status becomes `queued`, then `sending` and `sent`. Sends to every subscribed contact in the audience. Run get_broadcast_readiness first and confirm with the user. Requires a `full_access` API key. API: `POST /broadcasts/{id}/send` (operationId `sendBroadcast`, Broadcasts).

Parametersidrequiredscheduled_at

list_suppressions

List suppressions

List suppressions. Requires a `full_access` API key. API: `GET /suppressions` (operationId `listSuppressions`, Suppressions).

Parametersafterlimitbefore

create_suppression

Add a suppression

Add a suppression. Adds the address with reason `manual`. Adding an address that is already suppressed returns the existing entry. Requires a `full_access` API key. API: `POST /suppressions` (operationId `createSuppression`, Suppressions).

Parametersemailrequired

delete_suppression

Remove a suppression

Remove a suppression. Requires a `full_access` API key. API: `DELETE /suppressions/{idOrEmail}` (operationId `deleteSuppression`, Suppressions).

Parametersid_or_emailrequired

list_tenants

List tenants

List tenants. Requires a `full_access` API key. API: `GET /tenants` (operationId `listTenants`, Tenants).

Parametersafterlimitbefore

create_tenant

Create a tenant

Create a tenant. Creates one of your customers, with its own SES tenant (isolated reputation). `external_id` must be unique within your account. Requires a `full_access` API key. API: `POST /tenants` (operationId `createTenant`, Tenants).

Parametersnamerequireddaily_limitexternal_id

get_tenant

Retrieve a tenant

Retrieve a tenant. Requires a `full_access` API key. API: `GET /tenants/{ref}` (operationId `getTenant`, Tenants).

Parametersrefrequired

update_tenant

Update a tenant

Update a tenant. Changes the name, `external_id` or `daily_limit` (`null` removes the cap). Requires a `full_access` API key. API: `PATCH /tenants/{ref}` (operationId `updateTenant`, Tenants).

Parametersrefrequirednamedaily_limitexternal_id

delete_tenant

Delete a tenant

Delete a tenant. Fails with `422` while the tenant still has domains; delete those first. Requires a `full_access` API key. API: `DELETE /tenants/{ref}` (operationId `deleteTenant`, Tenants).

Parametersrefrequired

pause_tenant

Pause a tenant

Pause a tenant. Stops all sending for the tenant. Sends return `403 sending_paused`; emails already queued fail. The body is optional. Requires a `full_access` API key. API: `POST /tenants/{ref}/pause` (operationId `pauseTenant`, Tenants).

Parametersrefrequiredreason

unpause_tenant

Unpause a tenant

Unpause a tenant. Resumes sending. A tenant that was paused by the reputation guard (bounce or complaint rate) can only be unpaused by a `trusted` or `internal` team; others get `403 invalid_access` and should contact support. Requires a `full_access` API key. API: `POST /tenants/{ref}/unpause` (operationId `unpauseTenant`, Tenants).

Parametersrefrequired

Version history

3
  1. v0.2.2LatestNov 4, 2026
  2. v0.2.2-1Oct 30, 2026
  3. v0.2.1Oct 29, 2026

Score

100% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts

Other Spacepost integrations