MOLTED EMAIL

MCP Server

Connect any MCP-compatible agent runtime to the Molted Email API with the @molted/mcp server package.

The @molted/mcp package exposes the Molted Email API as discoverable tools for any runtime that supports the Model Context Protocol. Claude Desktop, Cursor, VS Code Copilot, Windsurf, and any other MCP client can use it to send email, manage threads, classify inbound messages, and more.

Installation

npx -y @molted/mcp

Or install globally:

npm install -g @molted/mcp

Environment variables

VariableRequiredDefaultDescription
MOLTED_API_KEYYes-Your Molted API key (mm_live_* or mm_test_*)
MOLTED_API_URLNohttps://api.molted.emailAPI base URL

Setup

Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "molted": {
      "command": "npx",
      "args": ["-y", "@molted/mcp"],
      "env": {
        "MOLTED_API_KEY": "mm_live_..."
      }
    }
  }
}

Cursor

Add to .cursor/mcp.json in your project:

{
  "mcpServers": {
    "molted": {
      "command": "npx",
      "args": ["-y", "@molted/mcp"],
      "env": {
        "MOLTED_API_KEY": "mm_live_..."
      }
    }
  }
}

VS Code Copilot

Add to .vscode/mcp.json in your project:

{
  "servers": {
    "molted": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@molted/mcp"],
      "env": {
        "MOLTED_API_KEY": "mm_live_..."
      }
    }
  }
}

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "molted": {
      "command": "npx",
      "args": ["-y", "@molted/mcp"],
      "env": {
        "MOLTED_API_KEY": "mm_live_..."
      }
    }
  }
}

HTTP transport

For cloud agents or server-side use, run in HTTP mode:

MOLTED_API_KEY=mm_live_... molted-mcp --transport http --port 3100

The HTTP transport is stateless -- each request creates a fresh MCP session. This works well for serverless deployments and load-balanced environments.

Tools

The MCP server exposes 44 tools across eight groups (budget, threads, sending, intelligence, governance, analytics, journeys and segments, coordination), plus 8 resources and 5 prompts.

Budget

check_budget

Check remaining send capacity including daily/hourly limits and bounce/complaint budget. Call this before planning a campaign or batch send to verify you have capacity.

Parameters: None

Returns: { daily: { used, remaining }, hourly: { used, remaining }, negativeBudget: { bounces, complaints } }


Inbox and threads

read_inbox

List threads in a mailbox with optional filtering.

ParameterTypeRequiredDescription
mailbox_idstringNoFilter by mailbox UUID
statusstringNoFilter by status: open, waiting, resolved, escalated
limitnumberNoMax results (1-50, default 25)

Returns: { items: [{ id, contactEmail, subject, status, messageCount, lastMessageAt }], total }

get_thread

Get a full thread with all messages, intent classification, and SLA status.

ParameterTypeRequiredDescription
thread_idstringYesThread UUID

Returns: { thread: { id, status, contactEmail, ... }, envelopedMessages: [...] }

reply

Reply to a thread. Supports two modes:

  • Shorthand: Provide body (plain text) or html -- uses the _default template with an auto-generated dedupe key.
  • Template: Provide template_id, payload, and dedupe_key for custom templates.
ParameterTypeRequiredDescription
thread_idstringYesThread UUID to reply to
bodystringNoPlain text reply body (shorthand mode)
htmlstringNoHTML reply body (shorthand mode)
subjectstringNoOverride reply subject
template_idstringNoTemplate ID (template mode)
payloadobjectNoTemplate payload (template mode)
dedupe_keystringNoDeduplication key
send_reasonstringNoReason for sending (audit trail)

Returns: { status: "queued" | "sent", requestId }

archive

Archive a resolved thread, moving it out of the active inbox.

ParameterTypeRequiredDescription
thread_idstringYesThread UUID

Returns: { archived: 1 }

update_thread

Update a thread's status, metadata, or assignment.

ParameterTypeRequiredDescription
thread_idstringYesThread UUID
statusstringNoNew status: open, waiting, resolved, escalated
metadataobjectNoMetadata to set
assigned_agent_idstringNoAgent to assign to

Returns: The updated thread object.

approve

Approve a pending send in the approval queue (human-in-the-loop).

ParameterTypeRequiredDescription
thread_idstringYesThread UUID with pending approval
reasonstringYesReason for approving (audit trail)

Returns: Approval confirmation.


Sending

send_email

Send a policy-checked email. Supports shorthand (body/html) and template modes.

ParameterTypeRequiredDescription
tostringYesRecipient email
bodystringNoPlain text body (shorthand)
htmlstringNoHTML body (shorthand)
subjectstringNoSubject line (shorthand)
template_idstringNoTemplate ID
payloadobjectNoTemplate payload
dedupe_keystringNoDeduplication key
send_reasonstringNoReason for sending
mailbox_idstringNoMailbox to send from
idempotency_keystringNoIdempotency key for safe retries

Returns: { status: "queued" | "blocked" | "pending_approval", requestId }

Policy blocks are returned as successful results with the block reason so your agent can reason about alternatives.

draft_email

Draft an email with AI-assisted composition and policy pre-check.

ParameterTypeRequiredDescription
tostringYesRecipient email
contextobjectNoBackground context for draft generation

Returns: { draftCandidates: [...], policyPreCheck: { allowed, reason }, contactContext }

dry_run

Simulate a send without dispatching. Preview the policy decision.

ParameterTypeRequiredDescription
tostringYesRecipient email
template_idstringYesTemplate to simulate
dedupe_keystringNoDeduplication key
payloadobjectNoTemplate payload
mailbox_idstringNoMailbox to simulate from

Returns: { wouldAllow: boolean, reason?, cooldownExpiresAt?, simulation: true }

batch_send

Send to multiple recipients with per-recipient policy evaluation. Max 500 recipients per batch.

ParameterTypeRequiredDescription
template_idstringYesTemplate for all recipients
sendsarrayYesArray of { to, dedupe_key, payload?, send_reason? }
mailbox_idstringNoMailbox to send from

Returns: { batchId, total, queued, blocked, results: [{ recipientEmail, requestId, status, reason? }] }

schedule_followup

Schedule a delayed follow-up email that auto-cancels if the recipient replies.

ParameterTypeRequiredDescription
contact_emailstringYesContact to follow up with
thread_request_idstringYesRequest ID from the initial send
delay_minutesnumberYesDelay before sending (1-43200)
cancel_on_replybooleanNoAuto-cancel on reply
trigger_conditionsobjectNoCustom trigger conditions

Returns: { followupId, status, scheduledAt }


Intelligence

classify_inbound

Classify an inbound email's intent.

ParameterTypeRequiredDescription
subjectstringYesEmail subject line
body_textstringYesPlain text body

Returns: { intent, confidence, suggestedAction, flags?, safetyVerdict? }

Intent categories: interested, objection, not_now, support, billing, legal, security, out_of_office.

next_best_action

Get a recommendation for what to do next with a contact based on timeline, fatigue, and intent signals.

ParameterTypeRequiredDescription
contact_emailstringYesContact email address

Returns: { recommendation, reasoning, contactSummary: { email, lastSendAt, isSuppressed } }

Recommendations: reply, wait, nudge, stop, escalate.

get_context

Get full contact timeline including sends, replies, journeys, engagement history, and suppression status.

ParameterTypeRequiredDescription
contact_emailstringYesContact email address

Returns: { timeline: { sends, journeyRuns, inboundMessages }, suppressionStatus, activeIncidents, lastClassification }

batch_classify

Classify multiple inbound emails in one call.

ParameterTypeRequiredDescription
messagesarrayYesArray of { subject, body_text }

Returns: { results: [{ intent, confidence, suggestedAction }] } in the same order as inputs.

batch_next_action

Get next-best-action recommendations for multiple contacts.

ParameterTypeRequiredDescription
contact_emailsarrayYesArray of email addresses

Returns: { results: [{ contactEmail, recommendation, reasoning }] }


Governance and outcomes

add_suppression

Suppress a contact or domain so no further emails are sent to them. Provide either recipient_email (email-level) or domain (domain-level).

ParameterTypeRequiredDescription
recipient_emailstringNoEmail address to suppress
domainstringNoDomain to suppress (e.g. example.com)
scopestringNoScope: tenant or campaign (platform-wide global scope is admin-only)
reason_codestringNoReason code: complaint, hard_bounce, manual_dnc, legal_request, role_account, domain_suppressed, no_engagement
sourcestringNoSource of the suppression

Returns: The created suppression record.

check_suppression

Check if an email address or domain is currently suppressed. Call this before sending to verify the recipient is not on a suppression list.

ParameterTypeRequiredDescription
recipient_emailstringNoEmail to check
domainstringNoDomain to check

Returns: Suppression records if found, empty array if not suppressed.

remove_suppression

Remove a suppression so the contact or domain can receive emails again.

ParameterTypeRequiredDescription
suppression_idstringNoUUID of the email suppression to remove
domainstringNoDomain suppression to remove

Returns: { deleted: true }

Check consent status for a contact (GDPR/CCPA compliance).

ParameterTypeRequiredDescription
recipient_emailstringYesEmail address to check

Returns: { hasConsent: boolean, basis: string }

Record consent for GDPR/CCPA compliance.

ParameterTypeRequiredDescription
recipient_emailstringYesEmail address
basisstringYesLegal basis: explicit_opt_in, legitimate_interest, contractual, legal_obligation
sourcestringNoWhere consent was given (e.g. signup_form)
jurisdictionstringNoLegal jurisdiction (e.g. GDPR, CCPA)
granted_atstringNoISO 8601 timestamp when consent was granted
revoked_atstringNoISO 8601 timestamp when consent was revoked

Returns: The consent record.

record_outcome

Record a business outcome (conversion, revenue, engagement) linked to email touches. Molted automatically attributes the outcome to recent email interactions.

ParameterTypeRequiredDescription
contact_emailstringYesContact email
event_typestringYesactivation, trial_conversion, meeting_booked, deal_closed, upsell, or custom
event_namestringYesEvent name (e.g. purchase, demo_booked)
revenuenumberNoRevenue amount in cents
metadataobjectNoAdditional metadata
occurred_atstringNoISO 8601 timestamp (defaults to now)

Returns: The ingested outcome record with attribution data.

outcome_dashboard

Get a revenue attribution summary showing how email campaigns contributed to business outcomes.

Parameters: None

Returns: { totalRevenue, conversions, topCampaigns }

journey_impact

Analyze which journeys had the most impact on business outcomes.

ParameterTypeRequiredDescription
modelstringNoAttribution model: first_touch, last_touch, or linear (default last_touch)

Returns: Journeys ranked by outcome contribution.


Analytics

fatigue_score

Get the fatigue score (0-100) for a contact. Measures how "tired" a recipient is of your emails based on send frequency, bounces, complaints, reply rate, and days since last engagement.

ParameterTypeRequiredDescription
emailstringYesThe contact email address to check

Returns: { contactEmail, fatigueScore, factors: { sendFrequency, bounceCount, complaintCount, replyRate, daysSinceLastEngagement }, recommendation }

Thresholds: Above 70 = stop sending. Above 40 = reduce frequency. Below 40 = safe.

send_velocity

Get your recent send volume and velocity trends. Use this to detect if you are ramping up too fast.

Parameters: None

Returns: { lastHour, last24Hours, last7Days, hourlyTrend: [{ hour, count }] }

deliverability

Get email deliverability metrics: delivery rate, bounce rate, and complaint rate.

ParameterTypeRequiredDescription
periodstringNoTime period: 24h, 7d, or 30d (default 7d)

Returns: { period, totalSent, delivered, bounced, complained, deliveryRate, bounceRate, complaintRate }

check_reputation

Check the reputation status of a specific mailbox.

ParameterTypeRequiredDescription
mailbox_idstringYesMailbox UUID

Returns: { id, mailbox_id, bounce_rate, complaint_rate, total_sends, total_bounces, total_complaints, status, last_calculated_at }

Status values: healthy, warning, paused. A paused mailbox blocks all sends until reputation recovers.


Journeys and segments

create_journey

Create a multi-step email journey (onboarding, nurture, re-engagement). Journeys start in "draft" status.

ParameterTypeRequiredDescription
namestringYesDisplay name for the journey
trigger_eventstringYesEvent name that triggers enrollment (e.g. "signup")
trigger_conditionsobjectNoOptional filter conditions on the event payload

Returns: { id }

activate_journey

Activate a draft journey or change its status.

ParameterTypeRequiredDescription
journey_idstringYesJourney UUID
statusstringNoTarget status: active, paused, or archived (default active)

Returns: { updated: true }

trigger_journey

Enroll a contact into a journey by ingesting a trigger event. The event is processed asynchronously.

ParameterTypeRequiredDescription
event_namestringYesEvent name matching a journey's trigger_event
contact_emailstringYesContact email to enroll
payloadobjectNoEvent properties available to journey steps

Returns: { eventId }

journey_status

Check a journey's configuration, status, and steps.

ParameterTypeRequiredDescription
journey_idstringYesJourney UUID

Returns: { id, name, status, trigger_event, trigger_conditions, steps: [{ id, step_order, step_type, config }] }

add_journey_step

Append or replace a step in an existing journey. Call repeatedly after create_journey to build a sequence, then activate_journey.

ParameterTypeRequiredDescription
journey_idstringYesJourney UUID
step_ordernumberYesExecution order (1-based). Steps run in ascending order.
step_typestringYessend, delay, branch, or end
configobjectNoStep configuration — shape depends on step_type (see below)

config per step_type:

  • send: { templateId, mailboxId?, payload?, dedupeKeyPrefix?, sendReason? }
  • delay: { delayMinutes } (the worker only reads this spelling — not minutes or delayMs)
  • branch: { conditions: [{ field, operator, value, nextStepOrder }], defaultNextStepOrder? }
  • end: {}

Returns: { id, step_order, step_type, config }

update_journey_step

Update an existing step. All fields are optional — supply only what you want to change.

ParameterTypeRequiredDescription
journey_idstringYesJourney UUID
step_idstringYesJourney-step UUID
step_ordernumberNoNew execution order (1-based)
step_typestringNoChange type (rare — usually keep the type and only update config)
configobjectNoNew configuration — same shape as add_journey_step.config. Passing config replaces the previous value (not a shallow merge).

Returns: updated step.

create_segment

Define an audience segment with AND/OR filter criteria on contact fields, metadata, and behavioral data.

ParameterTypeRequiredDescription
namestringYesSegment display name
filter_groupobjectYes{ logic: "and"|"or", filters: [{ type, field, operator, value }] }

Filter types: contact_field, metadata, account_field, firmographic, behavioral Operators: eq, neq, gt, gte, lt, lte, contains, not_contains, in, not_in, exists, not_exists, between

Returns: { id, name, filter_group, status }

compute_segment

Queue an asynchronous recomputation of segment membership for all contacts.

ParameterTypeRequiredDescription
segment_idstringYesSegment UUID

Returns: { queued: true, segmentId }

check_membership

Check if a specific contact is a member of a segment. Evaluates live against current data.

ParameterTypeRequiredDescription
segment_idstringYesSegment UUID
contact_emailstringYesContact email to check

Returns: { isMember: boolean, evaluatedLive: true }


Coordination

Multi-agent coordination tools that prevent simultaneous messaging and enable consensus decisions. Agents must register before using leases, heartbeats, or consensus.

register_agent

Register this agent with the coordination system. If an agent with the same name already exists, its heartbeat is refreshed.

ParameterTypeRequiredDescription
agent_namestringYesUnique name for this agent within the tenant
agent_rolestringNoRole of the agent (e.g. sdr, support, marketing)

Returns: { id, agentName, agentRole, lastHeartbeat, registeredAt }

heartbeat

Signal liveness to the coordination system. Agents that stop sending heartbeats have their leases auto-expired. Call periodically (every 1-2 minutes) while holding leases.

ParameterTypeRequiredDescription
agent_idstringNoAgent UUID (provide either agent_id or agent_name)
agent_namestringNoAgent name (provide either agent_id or agent_name)

Returns: { ok: true }

acquire_lease

Claim exclusive access to a contact. Prevents other agents from messaging the same contact simultaneously. If another agent already holds the lease, returns a conflict response with the current lease holder details.

ParameterTypeRequiredDescription
agent_idstringNoAgent UUID (provide either agent_id or agent_name)
agent_namestringNoAgent name (provide either agent_id or agent_name)
contact_emailstringYesEmail address of the contact to claim
intentstringNoIntent for contacting (e.g. outbound_sales, support). Default general
duration_minutesnumberNoLease duration in minutes. Default 30

Returns: { id, agentId, contactEmail, intent, expiresAt } on success, or { conflict: true, leaseHolder: { agentId, agentName } } if already held.

release_lease

Release a contact lease when done. Frees the contact for other agents to claim.

ParameterTypeRequiredDescription
lease_idstringYesUUID of the lease to release

Returns: { released: true }

list_leases

List all active contact leases in the tenant. Shows which agents hold leases on which contacts, with expiry times.

Parameters: None

Returns: Array of { id, agentId, contactEmail, intent, expiresAt }

create_consensus

Propose a high-risk action for multi-agent consensus. Other agents can vote to approve or reject. Resolved automatically when a majority of active agents have voted.

ParameterTypeRequiredDescription
agent_idstringNoProposing agent UUID (provide either agent_id or agent_name)
agent_namestringNoProposing agent name (provide either agent_id or agent_name)
actionstringYesThe proposed action (e.g. send_sensitive_email, delete_contact)
contact_emailstringYesEmail of the contact this action affects
reasonstringYesWhy this action is being proposed
timeout_minutesnumberNoTime to wait for votes before expiring. Default 5

Returns: { id, status, action, contactEmail, reason, timeoutAt }

get_consensus

Get the current state of a consensus request including votes cast and status.

ParameterTypeRequiredDescription
consensus_idstringYesConsensus request UUID

Returns: { id, status, action, contactEmail, reason, timeoutAt }

Status values: pending, approved, rejected, expired.

vote

Cast a vote on a multi-agent consensus request. Each agent can only vote once per request.

ParameterTypeRequiredDescription
consensus_idstringYesConsensus request UUID
agent_idstringYesVoting agent UUID
votestringYesapprove or reject
reasonstringNoReason for the vote

Returns: { id, vote, consensusStatus }


Resources

Resources provide read-only context that agents can pull into their working memory without calling tools. Access them via resources/list and resources/read in any MCP client.

URIDescription
molted://mailboxesAll mailboxes with address, reputation, autonomy, and send limits
molted://mailboxes/{id}/configFull mailbox configuration: rules, SLA, alerts, autonomy level
molted://templatesAvailable email templates with variable schemas
molted://templates/{id}Specific template with version history
molted://segmentsAudience segments with filter definitions
molted://journeysActive email journeys with step definitions
molted://policy-rulesCurrent policy rules and thresholds
molted://domainsVerified sending domains with DNS and warmup status

Resources return JSON data from the Molted API. Template URIs ({id} parameters) auto-populate from the list callback, so MCP clients that support resource templates will show available mailboxes and templates as completions.

Prompts

Prompts are pre-built multi-step workflows that agents can invoke. Each prompt returns a message sequence that guides the agent through chaining multiple tools together.

draft-followup

Given a thread, draft an appropriate follow-up email. Reads the thread, checks budget, and composes a reply matching the conversation tone.

ArgumentTypeRequiredDescription
thread_idstringYesThread UUID to follow up on
mailbox_idstringNoMailbox UUID to send from

triage-inbox

Process unread threads: classify intent, recommend action, and auto-archive resolved/spam/OOO threads.

ArgumentTypeRequiredDescription
mailbox_idstringNoMailbox UUID to triage (omit for all)
max_threadsstringNoMaximum threads to process (default 20)

pre-send-check

Before sending an email, verify it is safe: check suppression status, consent, and remaining budget. Returns a GO / NO-GO recommendation.

ArgumentTypeRequiredDescription
to_emailstringYesRecipient email to validate
mailbox_idstringNoMailbox UUID to send from

investigate-bounce

Investigate why an email bounced and recommend corrective action. Automatically suppresses hard bounces.

ArgumentTypeRequiredDescription
thread_idstringYesThread UUID of the bounced email
mailbox_idstringNoMailbox UUID

campaign-readiness

Check if conditions are right to send a campaign to a segment: budget capacity, template readiness, domain health, and negative-signal budget.

ArgumentTypeRequiredDescription
segment_idstringYesSegment UUID
mailbox_idstringNoMailbox UUID
template_idstringNoTemplate UUID

Error handling

The MCP server maps API responses to structured tool results:

HTTP StatusBehavior
2xxSuccess with parsed JSON data
429Rate limited -- includes retry timing
403Insufficient scope -- key lacks required permissions
401Authentication error -- invalid or expired key
404Resource not found
5xxServer error

Policy blocks (e.g., suppressed contact, rate limit exceeded) are returned as successful results with the block reason. This lets your agent reason about why the send was blocked and decide on alternatives rather than treating it as an error.

Scoped keys

API keys can be scoped to specific mailboxes. When using a scoped key, all tools automatically operate within that mailbox's context. This is useful for multi-tenant setups where each agent should only access its own mailbox. See Authentication for details on key scoping.