Skip to main content
Glama
Apple Mail MCP

Apple Mail MCP

by cyberprive

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
APPLE_MAIL_MCP_LOG_PATHNoJSON log file path; rotates at 2 MB.~/Library/Logs/apple-mail-mcp.log
APPLE_MAIL_MCP_LOG_LEVELNoLog level: DEBUG, INFO, WARNING or ERROR.INFO
APPLE_MAIL_MCP_DRAFT_VISIBLENoSet to true to open the compose window for each draft; false saves silently.false
APPLE_MAIL_MCP_ATTACHMENTS_DIRNoThe only folder attachments may be saved into.~/Downloads/apple-mail-mcp
APPLE_MAIL_MCP_APPLESCRIPT_TIMEOUT_MSNoPer-call timeout for Mail, in milliseconds.45000

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}

Tools

Functions exposed to the LLM to take actions

NameDescription
pingA

Health check. Returns {ok: true, data: "OK"} if the MCP is reachable.

versionA

Return the MCP server version.

list_accountsA

List every account configured in Apple Mail.

Returns a list of {id, name, user_name, account_type, email_addresses, enabled}. The name field is the canonical handle to pass to other tools as account.

list_mailboxesA

List mailboxes (folders) inside an account.

Args: account: Account name as returned by list_accounts. with_counts: If true, include unread_count and total_count per mailbox. Slow on large accounts — Mail enumerates each folder to count messages. On a 30k-message iCloud account with 80+ folders this can take 30+ seconds. Default false.

Returns a list of {name, unread_count?, total_count?}.

search_messagesA

Search messages in a mailbox. Returns lightweight summaries.

Args: account: Account name (from list_accounts). mailbox: Mailbox name (from list_mailboxes). When omitted (or set to "@inbox"), the server auto-detects the account's inbox by trying the common localizations (INBOX, Bandeja de entrada, Posteingang, Boîte de réception, Caixa de entrada, etc.). since: ISO 8601 timestamp; only messages received at or after are returned. Defaults to 7 days ago if not provided — without a date floor, the script must materialize the entire mailbox, which is ruinous on large iCloud inboxes. Pass an explicit older date if you need to look further back. before: ISO 8601 timestamp; only messages received strictly before are returned. limit: Max results, capped at 500. Default 50. unread_only: If true, only return unread messages. query: Case-insensitive substring filter. Scope set by field. field: Where query is matched. One of: "subject" — subject line only "sender" — sender name + address "content" — full body text (slower; iterates message content) "all" — subject + sender (default; content excluded for perf)

Returns a list of {id, message_id, account, mailbox, subject, sender, date_received, read, snippet}. Use id with get_thread to fetch the full body.

get_threadA

Fetch the full content for a single message.

v1 returns one message (no thread reconstruction). For triage this is sufficient; full threading lands in v1.5.

Args: account: Account name. mailbox: Mailbox name (from search_messages output). id: Mail.app numeric message id (from search_messages output).

Returns {messages: [{id, message_id, account, mailbox, subject, sender, to, cc, date_received, date_sent, read, body}]}.

create_draftA

Create a plain-text draft in Apple Mail's Drafts folder.

Two modes:

  1. New message — pass to and subject. body is the message text.

  2. Reply — pass reply_to={"account":..., "mailbox":..., "id":...} (use the values returned by search_messages). subject and to become optional and are auto-set from the original. body is your reply text; the original message is automatically quoted below it. Threading headers (In-Reply-To/References) are set so the recipient's mail client groups this with the original conversation. cc / bcc are additive.

Args: account: Sender account name (from list_accounts). body: Plain-text reply/message text. May be empty. to: Recipient addresses. Required for new messages, optional for replies. subject: Subject line. Required for new messages, optional for replies (defaults to "Re: "). Pass an explicit value to override. cc, bcc: Optional CC/BCC addresses. reply_to: If set, creates a reply. {account, mailbox, id} of the original message. account here is the account where the original was received, which may differ from the sending account. reply_all: If true and replying, replies to all recipients. Default false. visible: If true, Mail brings the compose window forward; if false the draft is saved silently. Defaults to APPLE_MAIL_MCP_DRAFT_VISIBLE.

Returns metadata about the created draft. Does NOT return a persisted Drafts-mailbox id — Mail commits drafts asynchronously. Drafts are reviewed in Mail.app.

HTML body rendering is v1.5.

mark_readB

Mark a single message as read.

Args: account, mailbox, id: As returned by search_messages.

mark_unreadB

Mark a single message as unread.

Args: account, mailbox, id: As returned by search_messages.

move_to_mailboxA

[DESTRUCTIVE] Move a message from one mailbox to another within the same account.

This tool refuses without confirm=true. Always surface the planned move to the user and get explicit approval before passing confirm=true — moving a message changes user-visible state (especially when the target is Trash, Junk, or Archive). Reversible by moving back, but disruptive.

Both mailbox and target_mailbox accept either an exact mailbox name OR a localization-aware alias starting with "@": @inbox, @archive, @drafts, @sent, @trash, @junk The MCP resolves the alias against the account's actual folder names (e.g. @archive → "Archivo" on a Spanish-localized M365 account, "Archive" on iCloud English). The returned to_mailbox field is the resolved literal name so callers can log accurately.

Args: account, mailbox, id: As returned by search_messages. target_mailbox: Destination — exact name or @alias. confirm: Must be true to actually perform the move. False (default) returns a CONFIRM_REQUIRED envelope describing the action.

flag_messageA

Set or clear the flag color on a message.

Args: account, mailbox, id: As returned by search_messages. color: 0..6 sets a color; -1 clears the flag. 0 red · 1 orange · 2 yellow · 3 green · 4 blue · 5 purple · 6 gray

list_attachmentsA

List attachments on a message.

Args: account, mailbox, id: As returned by search_messages.

Returns a list of {index, name, size, mime_type, downloaded}. Pass index to save_attachment. downloaded=false means the attachment body isn't on disk yet — open the message in Mail.app to fetch it before saving.

save_attachmentA

Save one attachment to disk, inside the attachments folder.

Files can only be written inside the attachments folder (APPLE_MAIL_MCP_ATTACHMENTS_DIR, default ~/Downloads/apple-mail-mcp). Paths outside it are refused. The attachment's filename comes from the sender and is cleaned (no path separators, no leading dots); the result reports both name (as saved) and original_name.

Args: account, mailbox, id: As returned by search_messages. index: 1-based index from list_attachments. target_dir: Optional subfolder. Relative paths are taken relative to the attachments folder; absolute paths must be inside it. Default: the folder itself. Created if missing. overwrite: If false (default), append " (2)", " (3)" etc. when the name is taken. True replaces existing files and requires confirm=true. confirm: Required with overwrite=true. Get the user's approval first.

Returns {saved_path, name, original_name, size, downloaded}.

save_all_attachmentsA

Save every attachment on a message, inside the attachments folder.

Same rules as save_attachment: writes only inside APPLE_MAIL_MCP_ATTACHMENTS_DIR, filenames cleaned, overwrite needs confirm.

Args: account, mailbox, id: As returned by search_messages. target_dir: Optional subfolder (relative, or absolute inside the folder). overwrite: If false (default), taken names get a " (2)", " (3)" suffix. True replaces existing files and requires confirm=true. confirm: Required with overwrite=true. Get the user's approval first.

Returns {saved: [{index, saved_path, name, original_name, size}], skipped: [{index, name, reason}]}. reason is typically "not_downloaded" — open the message in Mail.app to fetch it.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.9/5.0

Scored across 14 tools

Disambiguation5/5

Each tool targets a distinct resource or action: search_messages returns summaries while get_thread fetches full bodies, mark_read/mark_unread are complementary opposites, and save_attachment vs save_all_attachments differ clearly in scope. The only mild overlap is version vs ping, but those are conventional and clearly differentiated (build info vs health probe).

Naming Consistency4/5

The set is almost entirely consistent snake_case verb_noun (list_accounts, search_messages, create_draft, move_to_mailbox, save_attachment). The outliers are 'version' and 'ping', which are noun/verb-less utility names, but these are conventional and readable, so the deviation is minor.

Tool Count5/5

Fourteen tools sit comfortably in the well-scoped 3-15 range, and each earns its place across account discovery, search, read, draft, move, flag, and attachment workflows. Nothing feels redundant or padded.

Completeness4/5

Core lifecycle is well covered: account/mailbox discovery, search, full-message fetch, drafting (including replies), moving (with @trash effectively enabling delete), flagging, and attachment save. Minor gaps remain—no explicit send or permanent-delete tool, no forward helper, and no batch mark-read—but these are arguably intentional safety choices and workable around.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues