MCP Server
AI-driven management with subscriber ops, engagement queries, and template preview.
The MCP (Model Context Protocol) server lets you manage the entire email system through Claude Code. No dashboard, no CLI scripts - just talk to Claude.
Setup
claude mcp add mailshot -- npx @mailshot/mcpThe server uses your local AWS credentials. Make sure the credentials have access to DynamoDB, S3, SES, and Step Functions in the target region.
Required environment variables (read from .env at repo root):
REGIONTABLE_NAMEEVENTS_TABLE_NAMETEMPLATE_BUCKET_NAME
Tool categories
Subscribers
| Tool | Description |
|---|---|
get_subscriber(email) | Full view: profile, active executions, recent send log, suppression record |
list_subscribers(status?, limit?) | Scan profiles filtered by status: active, unsubscribed, suppressed |
update_subscriber(email, attributes) | Update profile attributes (does not affect unsubscribed/suppressed flags) |
delete_subscriber(email) | Remove all records from both tables |
unsubscribe_subscriber(email) | Mark as unsubscribed, stop all active executions |
resubscribe_subscriber(email) | Clear unsubscribed flag and remove suppression record |
Suppression
| Tool | Description |
|---|---|
list_suppressed() | Scan for all suppression records |
remove_suppression(email) | Delete suppression record and clear suppressed flag |
Engagement
| Tool | Description |
|---|---|
get_subscriber_events(email, eventType?, startDate?, endDate?, limit?) | Query events for a subscriber |
get_template_events(templateKey, eventType?, startDate?, endDate?, limit?) | Query events across subscribers for a template (via TemplateIndex GSI) |
get_sequence_events(sequenceId, eventType?, startDate?, endDate?, limit?) | Scan events for a sequence |
get_delivery_stats(startDate, endDate) | Aggregate counts by event type |
Sequences
| Tool | Description |
|---|---|
list_sequences() | List deployed sequences (template prefixes + state machines), each with activeExecutionCount of subscribers currently in it |
list_sequence_subscribers(sequenceId, limit?) | Show subscribers currently running in a sequence (active executions, newest first). Powered by the inverted EXEC#<seq> row. |
export_sequence(sequenceId) | Reverse-parse a deployed sequence's ASL back to a SequenceDefinition, including templates and EventBridge trigger config |
Templates
| Tool | Description |
|---|---|
list_templates() | List all templates in S3 |
preview_template(templateKey, email, firstName?, attributes?) | Fetch from S3, render with LiquidJS using subscriber data |
validate_template(templateKey) | Check template exists and renders without errors |
Broadcasts
| Tool | Description |
|---|---|
send_broadcast(broadcastId, templateKey, subject, senderFromEmail, senderFromName, senderReplyToEmail?, listUnsubscribe?, filterTags?, filterAttributes?, dryRun?) | Invoke BroadcastFn directly to resolve subscribers and fan out via SQS. Set dryRun: true to preview audience size without sending. |
get_broadcast(broadcastId) | Get a broadcast record with config, filters, audienceSize, and live counters (deliveryCount, openCount, clickCount, bounceCount, complaintCount). |
list_broadcasts(limit?) | List recent broadcasts (most recent first), each merged with its live counters. |
System
| Tool | Description |
|---|---|
get_failed_executions(stateMachineArn, startDate?, limit?) | List failed Step Functions executions |
get_delivery_stats(startDate, endDate) | Delivery/open/click/bounce/complaint counts |
Skills
| Tool | Description |
|---|---|
sync_skills(projectRoot?) | Refresh .claude/skills/ from the canonical files shipped with @mailshot/skills. Defaults to the current working directory. Overwrites existing files — git is the safety net for local edits. |
Example conversations
"How is the onboarding sequence performing?"
Claude uses get_delivery_stats and get_template_events to pull open rates, click rates, and bounce rates for each template in the sequence.
"Who is currently in the onboarding sequence?"
Claude uses list_sequence_subscribers to return a list of subscribers with active executions in onboarding, including when each one started and their execution ARN. The /inspect-sequence skill wraps this with engagement and recent failures.
"Show me everyone who bounced this week"
Claude uses list_suppressed and get_subscriber_events to identify bounced subscribers and show the bounce details.
"Unsubscribe user@example.com and show me their history"
Claude uses get_subscriber to show the full profile, then unsubscribe_subscriber to mark them as unsubscribed and stop executions.
"Preview the welcome email for user@example.com"
Claude uses preview_template to render the template with the subscriber's actual profile data and shows the HTML output.
"Are there any failed executions?"
Claude uses get_failed_executions to check each state machine for failures and reports the details.
How it works
The MCP server is a Node.js process that communicates with Claude Code over stdio using the Model Context Protocol. It:
- Registers tools with Zod schemas for input validation
- Receives tool calls from Claude Code
- Executes AWS SDK calls using local credentials
- Returns structured results
The server has no state of its own - it's a thin wrapper over AWS APIs, purpose-built for the operations you need when managing email sequences.