Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

dev.primitive/email

REMOTE · WWW.PRIMITIVE.DEV · SCANNED SEP 13

Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.

0 this week 95 Trust /100
Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. How we score → Why this is hard to score →

Endpoint Security97
  • The endpoint's TLS certificate is valid, in date, and uses a strong key. View diagnostics → Pass
  • Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token. View diagnostics → Pass
  • HTTPS is enforced; there's no plaintext access path. View diagnostics → Pass
  • The HSTS (Strict-Transport-Security) header is present. View diagnostics → Pass
  • DNSSEC is configured correctly; the domain's records validate against the full chain to the root. View diagnostics → Pass
  • The authorisation server offers only Dynamic Client Registration (RFC 7591), which MCP 2026-07-28 deprecated in favour of Client ID Metadata Documents. View diagnostics → Partial
Transport & Reachability100
Schema Quality & AI Usability81
  • 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 4508 tokens (~145/item across 31 items; 30 tools + 1 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management98
  • Stability check failed: schema churn in the 30 days we've observed: 0 tool removals, 1 breaking changes, 0 auth/transport breaks, 0 additions. See how to fix → Fail
Tool Coverage97
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 90% of tool parameters carry a description.Partial
  • Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety96
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • 5 of 6 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "sendEmailDemo" implies "send" and declares readOnlyHint instead, contradicting what its own name says it does. See how to fix → Partial
  • An AI judge read all 32 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
  • Supports UI / widget rendering.Pass
Install

How do I install the dev.primitive/email MCP server?

dev.primitive/email is a hosted endpoint at https://www.primitive.dev/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

remote · www.primitive.dev

# add to Claude Code
claude mcp add --transport http dev-primitive-email 'https://www.primitive.dev/mcp'
// .cursor/mcp.json
{
  "mcpServers": {
    "dev-primitive-email": {
      "url": "https://www.primitive.dev/mcp"
    }
  }
}
// .vscode/mcp.json
{
  "servers": {
    "dev-primitive-email": {
      "type": "http",
      "url": "https://www.primitive.dev/mcp"
    }
  }
}
# ~/.codex/config.toml
[mcp_servers.dev-primitive-email]
url = "https://www.primitive.dev/mcp"
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "dev-primitive-email": {
      "type": "remote",
      "url": "https://www.primitive.dev/mcp",
      "enabled": true
    }
  }
}
# add to OpenClaw
openclaw mcp add dev-primitive-email --url 'https://www.primitive.dev/mcp' --transport streamable-http
# ~/.hermes/config.yaml
mcp_servers:
  dev-primitive-email:
    url: "https://www.primitive.dev/mcp"
// ~/.netclaw/config/netclaw.json
{
  "McpServers": {
    "dev-primitive-email": {
      "Transport": "http",
      "Url": "https://www.primitive.dev/mcp"
    }
  }
}
# add to Vellum
assistant mcp add dev-primitive-email -t streamable-http -u 'https://www.primitive.dev/mcp'
// mcp.json
{
  "mcpServers": {
    "dev-primitive-email": {
      "type": "http",
      "url": "https://www.primitive.dev/mcp"
    }
  }
}

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 26 Aug 26 +1
    • We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
  • 24 Aug 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 91 to 95.

  • 22 Aug 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 85 to 88.

  • 20 Aug 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 78 to 81.

  • 18 Aug 26 0
    • Stability: 0.73 → fail security
    • A breaking change shipped without a version bump: still 0.1.0 security
    • The server rewrote its instructions, which are the text every model session reads security
    • Tool “awaitReply” rewrote its description, which is the text the model reads security
    • Tool “createEmailAddress” rewrote its description, which is the text the model reads security
    • Tool “getAccount” rewrote its description, which is the text the model reads security
    • Tool “sendEmail” rewrote its description, which is the text the model reads security
    • Schema quality: 115 → 145 functional
    • “awaitReply” changed the type of “wait”: string → boolean functional
    • “awaitReply” added an optional parameter “api_key” cosmetic
    • “awaitReply” reworded the description of “wait” cosmetic
    • “awaitReply” reworded the description of “wait_timeout_ms” cosmetic
    • Tool “createEmailAddress” changed its title: Get an email address (no signup) → Get a managed email domain (no signup) cosmetic
  • 16 Aug 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 67 to 70. That category is still filling its 30-day observation window: 20 days of observed history at the previous scan, 21 at this one. The score rises as the window fills, whether or not the server changes.

  • 14 Aug 26 0
    • Tool “sendEmailDemo” rewrote its description, which is the text the model reads security
    • Schema quality: pass → fail functional
    • New tool “createEmailAddress” functional
    • “getAccount” added an optional parameter “api_key” cosmetic
    • “getEmail” added an optional parameter “api_key” cosmetic
    • “getInboxStatus” added an optional parameter “api_key” cosmetic
    • “listEmails” added an optional parameter “api_key” cosmetic
    • “replyToEmail” added an optional parameter “api_key” cosmetic
    • “sendEmail” added an optional parameter “api_key” cosmetic
    • Tool “sendEmailDemo” changed its title: Try a send (no signup) → Preview a send (simulated, nothing is delivered) cosmetic
  • 11 Aug 26 0
    • We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 13 Sept 2026 · Probed https://www.primitive.dev/mcp

TLS valid

Negotiated TLS 1.3 with TLS_AES_128_GCM_SHA256 .

Subject Issuer Valid from Valid until Key Signature Serial
CN=primitive.dev CN=YE2,O=Let's Encrypt,C=US 1 Aug 2026 30 Oct 2026 ECDSA 256 ECDSA-SHA384 6fbed9ebd59789d8bd951e2445d19856f00
SANs: *.primitive.dev, primitive.dev
CN=YE2,O=Let's Encrypt,C=US (CA) CN=Root YE,O=ISRG,C=US 3 Sept 2025 2 Sept 2028 ECDSA 384 ECDSA-SHA384 4df3b15dd6c0784c507cd37b58e6f115
CN=Root YE,O=ISRG,C=US (CA) CN=ISRG Root X2,O=Internet Security Research Group,C=US 13 May 2026 2 Sept 2032 ECDSA 384 ECDSA-SHA384 872165fc34b6e5fba8add5b3705fb53a
CN=ISRG Root X2,O=Internet Security Research Group,C=US (CA) CN=ISRG Root X1,O=Internet Security Research Group,C=US 13 May 2026 2 Sept 2032 ECDSA 384 SHA256-RSA 6c8f1dc727c7117f7baf853ac980f9cd

Background: What to check on a remote MCP endpoint →

DNSSEC secure

Validation of www.primitive.dev. Secure

Zone DS Keys Algorithms Outcome
. trust_anchor 20326, 38696 8, 8 Verified
dev. present 60074 8 Verified
primitive.dev. present 2371 13 Verified
www.primitive.dev. Verified address RRset verified with the apex keys
Authentication Enforced and verified

The endpoint asked for a token and published valid RFC 9728 metadata describing how to get one.

Result Enforced and verified
Enforced On tool calls
HTTP status 200

WWW-Authenticate challenge Bearer realm="Primitive MCP", resource_metadata="https://www.primitive.dev/.well-known/oauth-protected-resource/mcp", error="invalid_token", error_description="Bearer token required for /mcp"

Bearer realm="Primitive MCP", resource_metadata="https://www.primitive.dev/.well-known/oauth-protected-resource/mcp", error="invalid_token", error_description="Bearer token required for /mcp"
Header Value
strict-transport-security max-age=63072000; includeSubDomains
content-security-policy base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'
x-content-type-options nosniff
x-frame-options DENY
referrer-policy strict-origin-when-cross-origin
permissions-policy accelerometer=(), bluetooth=(), browsing-topics=(), camera=(), geolocation=(), gyroscope=(), hid=(), magnetometer=(), microphone=(), payment=(), serial=(), usb=()

Protected resource metadata

Document https://www.primitive.dev/.well-known/oauth-protected-resource/mcp
Retrieved Yes
Resource https://www.primitive.dev/mcp
Authorisation server https://www.primitive.dev

Background: How OAuth 2.1 works in the 2026 MCP spec →

Transports 2 probes
Transport URL Outcome Status Location
streamable-http https://www.primitive.dev/mcp Verified 200
http (plaintext) http://www.primitive.dev/mcp HTTPS enforced 301 https://www.primitive.dev/mcp
MCP tools · 30 exposed · ~3,675 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
addDomain ~72

Claim a new domain and receive the DNS records to publish. Returns dns_records with the exact records to add. If the domain has an mx_conflict (existing mail provider), re-call with confirmed: true to proceed. After publishing DNS records, call verifyDomain to complete setup.

NameTypeReqDescription
requestBodyobjectyes
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

awaitReply ~246

Wait for the threaded reply to a sent email. Call this immediately after sendEmail or replyToEmail when you expect an answer. With only the sent email's id it long-polls for up to 30 seconds by default. Do not report that nobody replied or ask the user to check later until this call returns with no reply. Set wait=false only for a deliberate immediate poll. Matching uses reply threading, not a sender or subject guess.

NameTypeReqDescription
api_keystringPrimitive API key (prim_...). Only needed when this connection has no signed-in account: pass the api_key returned by createEmailAddress, unchanged, on every call for the rest of the conversation. Om…
idstringyesThe sent email id to fetch the reply for (from a sendEmail/replyToEmail response).
waitbooleanWhen true, long-poll until a reply arrives or wait_timeout_ms elapses. Defaults to true. Set false only for a single immediate poll.
wait_timeout_msnumberHow long to wait when wait=true (1000 to 30000 ms). Defaults to 30000.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

cancelScheduledSend ~93

Cancel a still-scheduled send before it dispatches (terminal status "canceled"; the same idempotency key becomes reusable). Pass the sent email id from a sendEmail response that used scheduled_at, or from listSentEmails. Returns a conflict error once the send has already started dispatching.

NameTypeReqDescription
idstringyesSent email ID of the scheduled send, from a sendEmail response or listSentEmails.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

createEmailAddress ~244

Get this user's Primitive managed inbox domain, creating the account on first use: no signup form, no password, no email verification, no browser. CALL THIS FIRST whenever you do not already have a Primitive API key and the user wants to send or receive email, instead of telling them to sign up or visit a website. On first use the REST response's address field is a domain such as pink-ram.primitive.email, not a complete mailbox. When it is non-null, this MCP result also includes sender_address such as agent@pink-ram.primitive.email for use as sendEmail.requestBody.from. It also returns an api_key. IMPORTANT: pass that api_key as the `api_key` argument on every later Primitive tool call in this conversation, exactly as returned; those calls fail without it. If this user already has a domain, the result repeats it with existing_account: true. Report it as their existing managed inbox rather than announcing a new one, and calling again will not produce a different one. The result also carries an upgrade link the user can open whenever they want to attach this domain to a full account.

NameTypeReqDescription
requestBodyobjectyes
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

createEndpoint ~61

Create a webhook endpoint to receive email.received events. If an endpoint with the same URL already exists but is deactivated, it is reactivated. After creating, call testEndpoint to confirm your signature verifier accepts the payload.

NameTypeReqDescription
requestBodyobjectyes
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

createFilter ~38

Create a whitelist or blocklist filter rule. Patterns are stored lowercase. Per-domain filters require a Pro plan.

NameTypeReqDescription
requestBodyobjectyes
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

deleteEndpoint ~37

Soft-delete a webhook endpoint. The endpoint will no longer receive deliveries.

NameTypeReqDescription
idstringyesEndpoint ID from listEndpoints or createEndpoint.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

deleteFilter ~29

Delete a filter rule.

NameTypeReqDescription
idstringyesFilter rule ID from listFilters or createFilter.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

downloadDomainZoneFile ~104

Download a BIND-format DNS zone file for a domain. Useful when users want to import all required DNS records at once rather than copying them individually. Returns plain text in BIND zone file format.

NameTypeReqDescription
idstringyesDomain ID from listDomains or addDomain.
outbound_onlybooleanWhen true, include only outbound DNS records (SPF, DKIM, DMARC). Defaults to all records for unverified domains, outbound-only for verified.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

downloadEmailAttachments ~94

Download all attachments for an inbound email as a gzip-compressed tar archive. Returns the archive as a base64-encoded string along with the attachment count and SHA-256 digest. Prefer getEmail first to check the attachment manifest before downloading.

NameTypeReqDescription
idstringyesInbound email ID.
tokenstringSigned download token from a webhook payload. Optional — the bearer token is used when this is omitted.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

getAccount ~134

Use this when you need the authenticated Primitive account summary, including plan, onboarding state, and managed inbox domain. managed_inbox_address is a domain, not a complete mailbox. When it is non-null, this MCP result also includes sender_address, such as agent@pink-ram.primitive.email, for use as sendEmail.requestBody.from.

NameTypeReqDescription
api_keystringPrimitive API key (prim_...). Only needed when this connection has no signed-in account: pass the api_key returned by createEmailAddress, unchanged, on every call for the rest of the conversation. Om…
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

getConversation ~103

Get the full conversation an inbound email belongs to as ordered, chat-model-ready turns with bodies. Each message is oldest-first with a direction (inbound/outbound) and a derived role (inbound→user, outbound→assistant). For a brand-new message, returns just that one turn. The response includes a truncated boolean (true when the message cap was reached) and a message_count field.

NameTypeReqDescription
idstringyesID of any inbound email in the conversation.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

getEmail ~111

Use this when you need full details for one inbound email ID, including parsed bodies, threading metadata, SMTP envelope, webhook state, and replies.

NameTypeReqDescription
api_keystringPrimitive API key (prim_...). Only needed when this connection has no signed-in account: pass the api_key returned by createEmailAddress, unchanged, on every call for the rest of the conversation. Om…
idstringyesInbound email ID from listEmails or searchEmails.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

getInboxStatus ~94

Use this when the user asks whether inbound email is ready or needs setup. Returns domains, routes, deployed Functions, and recent inbound activity.

NameTypeReqDescription
api_keystringPrimitive API key (prim_...). Only needed when this connection has no signed-in account: pass the api_key returned by createEmailAddress, unchanged, on every call for the rest of the conversation. Om…
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

getOutboundStatus ~76

What can I send FROM? Lists this account's verified outbound (sendable) domains plus any domains still pending DNS verification, with next actions. Call this BEFORE sendEmail to pick a valid `from` domain — the account email is not necessarily sendable. The same sendable list is echoed in a cannot_send_from_domain error.

Input schema present but exposes no named parameters.

NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

getSentEmail ~81

Get the full record for a single sent email by id, including body_text and body_html. Use to inspect delivery details for a specific send — e.g. the SMTP response on a bounced row, or the gate denial reason on a gate_denied row.

NameTypeReqDescription
idstringyesSent email ID from listSentEmails or a /send-mail response.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

getThread ~100

Get a conversation thread by id: metadata plus all inbound and outbound messages interleaved oldest-first. Each message has a direction (inbound/outbound) and id; fetch inbound message bodies via getEmail, or outbound bodies via getSentEmail. Discover thread_id from any email or sent-email record. Compare message_count against messages.length to detect truncation.

NameTypeReqDescription
idstringyesThread ID from the thread_id field on any email or sent-email.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

listDomains ~45

List all inbound domains for the organization, both verified and unverified. Each domain includes its verification status and DNS records. Use before addDomain to check whether a domain is already claimed.

Input schema present but exposes no named parameters.

NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

listEmails ~357

Use this when you need to browse inbound emails received at verified domains with cursor pagination, status filters, date filters, or sender/recipient search.

NameTypeReqDescription
api_keystringPrimitive API key (prim_...). Only needed when this connection has no signed-in account: pass the api_key returned by createEmailAddress, unchanged, on every call for the rest of the conversation. Om…
cursorstringBackward (history) pagination cursor from a previous response's `meta.cursor` field: returns emails OLDER than this position, newest-first. Mutually exclusive with `since`.
date_fromstringInclusive lower bound on created_at (ISO 8601).
date_tostringInclusive upper bound on created_at (ISO 8601).
domain_idstringFilter to emails received on a specific verified domain.
limitnumberMaximum number of emails to return (1–100, default 50).
searchstringFree-text search across sender, recipient, and subject.
sincestringForward-tail cursor (a `meta.cursor` value, format `{ISO datetime}|{UUID}`): returns emails strictly NEWER than this position, oldest-first, for lossless polling of just-arrived mail. Mutually exclus…
statusstringFilter to emails in this processing status.
waitnumberLong-poll up to this many seconds (0–30, default 0) holding the request for new mail instead of returning an empty page immediately. Requires `since`. Returns as soon as matching mail arrives, or an…
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

listEndpoints ~31

List all active webhook endpoints for the organization. Each endpoint shows its URL, enabled state, and optional domain restriction.

Input schema present but exposes no named parameters.

NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

listFilters ~20

List all whitelist and blocklist filter rules for the organization.

Input schema present but exposes no named parameters.

NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

listSentEmails ~229

List outbound emails sent by this org, with cursor pagination and filters. Bodies are omitted from list rows to keep responses small — use getSentEmail to fetch a specific row with full body. Useful for auditing delivery status, finding bounced sends, or checking gate-denied attempts.

NameTypeReqDescription
cursorstringPagination cursor from a previous response's `meta.cursor` field.
date_fromstringInclusive lower bound on created_at (ISO 8601).
date_tostringInclusive upper bound on created_at (ISO 8601).
idempotency_keystringFilter to rows with the given client idempotency key.
limitnumberMaximum number of sent emails to return (1–100, default 50).
request_idstringFilter to the row matching a specific server-issued request_id from a /send-mail response.
statusstringFilter to rows in this status. Use "scheduled" to find pending scheduled sends (cancelable via cancelScheduledSend) and "canceled" for ones already canceled.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

listWebhookDeliveries ~155

List webhook delivery attempts with pagination and filters. Each delivery includes the target endpoint and a nested email object with sender/recipient/subject. Useful for diagnosing delivery failures or confirming a specific email was delivered.

NameTypeReqDescription
cursorstringPagination cursor from a previous response's `meta.cursor` field.
date_fromstringInclusive lower bound on attempted_at (ISO 8601).
date_tostringInclusive upper bound on attempted_at (ISO 8601).
email_idstringFilter by inbound email ID.
limitnumberMaximum number of delivery records to return (1–100, default 50).
statusstringFilter to deliveries in this status.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

replayWebhookDelivery ~60

Re-send a stored webhook payload from a previous delivery attempt to its original endpoint. Rate limited per org (burst + sustained windows, shared budget with email webhook replays).

NameTypeReqDescription
idstringyesDelivery ID (numeric string from listWebhookDeliveries).
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

replyToEmail ~122

Use this when the user has selected a specific inbound email and confirmed a reply. Sends real outbound email with threading handled server-side.

NameTypeReqDescription
api_keystringPrimitive API key (prim_...). Only needed when this connection has no signed-in account: pass the api_key returned by createEmailAddress, unchanged, on every call for the rest of the conversation. Om…
idstringyesInbound email ID to reply to. Threading headers are set server-side.
requestBodyobjectyes
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

searchEmails ~383

Use this when you need to find inbound emails with structured filters or full-text matching. Use sort=received_at_asc plus date_from for new-mail polling.

NameTypeReqDescription
bodystringFilter to emails whose body contains this string.
cursorstringPagination cursor from a previous response's `meta.cursor` field.
date_fromstringInclusive lower bound on received_at (ISO 8601).
date_tostringInclusive upper bound on received_at (ISO 8601).
domain_idstringFilter to emails received on a specific verified domain.
fromstringFilter to emails from this sender address or domain.
has_attachmentstringFilter to emails that have ("true") or lack ("false") attachments.
include_facetsstringInclude aggregated facet counts (sender, domain, status) in the response (default true).
limitnumberMaximum number of emails to return (1–100, default 50).
qstringFull-text query matched across subject, body, sender, and recipient.
reply_to_sent_email_idstringFilter to inbound emails that are replies to a specific sent email ID.
snippetstringInclude a short body snippet in each result (default true).
sortstringSort order. Use received_at_asc with date_from for polling new mail.
spam_score_gtenumberFilter to emails with a spam score at or above this value.
spam_score_ltnumberFilter to emails with a spam score strictly below this value.
statusstringFilter to emails in this processing status.
subjectstringFilter to emails whose subject contains this string.
tostringFilter to emails addressed to this recipient.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

sendEmail ~235

Use this when the user has confirmed a new outbound email. Sends real email through Primitive's relay and can wait for the first SMTP delivery outcome, or schedule the send for a future time with scheduled_at. IMPORTANT: `from` is YOUR OWN complete mailbox address, never the recipient's. Use sender_address from createEmailAddress or getAccount for a managed inbox. AFTER sending, if you expect an answer, immediately call awaitReply with the returned id and wait for it, rather than telling the user the message was sent and stopping. Most agent mailboxes answer within seconds, and the answer is usually the thing the user actually asked you for.

NameTypeReqDescription
Idempotency-KeystringClient-supplied idempotency key. Retrying with the same key returns the original result without re-sending.
api_keystringPrimitive API key (prim_...). Only needed when this connection has no signed-in account: pass the api_key returned by createEmailAddress, unchanged, on every call for the rest of the conversation. Om…
requestBodyobjectyes
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

sendEmailDemo ~180

SIMULATION ONLY: nothing is delivered. NEVER call this when the user actually wants an email to arrive, and never describe its result as a sent email: no message is sent, queued, or stored, and the recipient receives nothing. To really send with no account, call createEmailAddress (instant, no signup form and no verification) and then sendEmail with the api_key it returns; that is the correct path for any genuine send request. This tool exists only to preview the response shape: it validates the body against the exact same schema as sendEmail (including cc/bcc, reply_to, tags, attachments, and scheduled_at) and returns a synthetic success envelope marked demo: true. Demo requests are capped at 16KB total body, so large attachments are rejected even though the schema allows them.

NameTypeReqDescription
requestBodyobjectyes
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

testEndpoint ~60

Send a sample email.received event to a webhook endpoint to verify your signature verifier. Rate limited to 4/min and 30/hr. Successful deliveries and verified-domain endpoints are exempt.

NameTypeReqDescription
idstringyesEndpoint ID from listEndpoints or createEndpoint.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

verifyDomain ~81

Check DNS records for a domain claim (MX, TXT, SPF, DKIM, DMARC). On success the domain becomes verified and starts receiving mail. On failure, returns which checks passed and which still need attention. If DNS propagation is incomplete, wait a few minutes and retry.

NameTypeReqDescription
idstringyesDomain ID returned by addDomain or listDomains.
NameTypeReqDescription
datayes
statusnumberyes
statusTextstring
toolstringyes

No examples provided.

Common questions

What is the dev.primitive/email MCP server?

dev.primitive/email is an MCP server listed in the public MCP registry as dev.primitive/email. Email infrastructure for AI agents, send, receive, search, and reply to email over MCP. This page covers its hosted endpoint (https://www.primitive.dev/mcp).

Is the dev.primitive/email MCP server safe to use?

dev.primitive/email scores 95 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the dev.primitive/email MCP server expose?

dev.primitive/email exposes 30 tools: listDomains, addDomain, verifyDomain, downloadDomainZoneFile, getAccount, and 25 more. Their descriptions and schemas cost roughly 3,675 tokens of context every time the server is loaded.

Does the dev.primitive/email MCP server require authentication?

Yes. dev.primitive/email asked us for credentials when we connected, so you will need to authorise it in your MCP client before it can do anything.

Is the dev.primitive/email MCP server still maintained?

dev.primitive/email is still listed as active in the MCP registry. We last reached this channel on 13 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.