apple-mail-mcp
This server enables AI assistants to read, search, send, and manage emails in Apple Mail on macOS, with support for both AppleScript and direct IMAP/SMTP backends.
Email Operations
Search messages by sender, subject, content, date range, read/flagged status
Read full message content (plain text or HTML)
List messages with pagination and filters
Send new emails (single or mail-merge to up to 100 recipients with
{{placeholder}}substitution)Create drafts, reply (including reply-all), and forward messages
Mark read/unread, flag/unflag (with optional colors), delete, and move messages — individually or in batch (up to 100)
Group messages into conversation threads by subject or IMAP references
Attachment Handling
List attachment metadata (name, MIME type, size)
Save attachments to disk or fetch as inline base64
Mailbox & Account Management
List, create, delete, and rename mailboxes/folders
List configured mail accounts (iCloud, Gmail, Exchange, etc.)
Get unread counts per mailbox, account, or globally
Mail Rules
List, enable/disable, create, and delete mail rules with custom conditions and actions
Contact Integration
Search macOS Contacts.app by name to look up email addresses and phone numbers
Email Templates
Save, list, retrieve, use, and delete reusable templates with placeholder support, persisted to disk across restarts
Diagnostics
Health check for Mail.app connectivity
Doctor: detailed diagnostics for permissions, accounts, IMAP/SMTP with remediation guidance
Mail statistics: total/unread counts and recently received stats (24h/7d/30d)
Sync status: check whether Mail.app is actively syncing
Allows AI assistants to read, send, search, and manage emails in Apple Mail on macOS.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@apple-mail-mcpShow me my unread emails from today"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Apple Mail MCP Server
A Model Context Protocol (MCP) server that enables AI assistants like Claude to read, send, search, and manage emails in Apple Mail on macOS.
Note: This is the npm/Node.js package — install with
npxornpm. There is an unrelated Python project of the same name on PyPI (imdinu/apple-mail-mcp) installed viapipx/uvx. If you're usinguvxand seeing acycloptsdependency error, you're looking for that project, not this one.
What is This?
This server acts as a bridge between AI assistants and Apple Mail. Once configured, you can ask Claude (or any MCP-compatible AI) to:
"Check my inbox for unread messages"
"Find emails from john@example.com"
"Send an email to the team about the meeting"
"Create a draft email for me to review"
"Reply to that message"
"Forward this to my colleague"
"Move old newsletters to the Archive folder"
The AI assistant communicates with this server, which then uses AppleScript to interact with the Mail app on your Mac. All data stays local on your machine.
Related MCP server: macos-mail-mcp
Quick Start
Using Claude Code (Easiest)
If you're using Claude Code (in Terminal or VS Code), just ask Claude to install it:
Install the sweetrb/apple-mail-mcp MCP server so you can help me manage my Apple MailClaude will handle the installation and configuration automatically.
Or register it deterministically in one command:
claude mcp add apple-mail -s user -- npx -y apple-mail-mcpUsing the Plugin Marketplace
Install as a Claude Code plugin for automatic configuration and enhanced AI behavior:
/plugin marketplace add sweetrb/apple-mail-mcp
/plugin install apple-mailThis method also installs a skill that teaches Claude when and how to use Apple Mail effectively.
Configuring IMAP/SMTP for a plugin install: a plugin install has no editable
envblock, so supply settings via the config file at~/Library/Application Support/apple-mail-mcp/config.json— Method B in the IMAP / SMTP Setup Guide. Passwords stay in the macOS Keychain; run thedoctortool to verify.
Using the Codex Marketplace
Install the same public marketplace in Codex:
codex plugin marketplace add sweetrb/apple-mail-mcp
codex plugin add apple-mail@apple-mail-mcpThe Codex package registers the same apple-mail MCP server through an exactly pinned runtime — npx -y apple-mail-mcp@<plugin version> — and includes the Apple Mail skill guidance. The pin in codex/.mcp.json is rewritten to match package.json by scripts/sync-plugin-version.mjs on every version bump, so the plugin manifest and the server it launches are always the same release; CI fails the PR if they drift.
Other Hosts (Hermes, Antigravity)
Two more hosts can run the same apple-mail MCP server (npx -y apple-mail-mcp):
Hermes Agent (NousResearch) — Hermes has no plugin/marketplace drop-in, so there is nothing in this repo to install from. Register the server with the CLI:
hermes mcp add apple-mail --command npx --args -y apple-mail-mcpOr add it to
~/.hermes/config.yamlby hand:mcp_servers: apple-mail: command: npx args: ["-y", "apple-mail-mcp"]Restart your Hermes session afterward so the tools load.
Antigravity (Google) — add the server entry from
.antigravity-plugin/mcp_config.jsonto~/.gemini/config/mcp_config.json(or via Antigravity's MCP settings).
Manual Installation
1. Install the server:
npm install -g apple-mail-mcp2. Add to Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"apple-mail": {
"command": "npx",
"args": ["apple-mail-mcp"]
}
}
}3. Restart Claude Desktop and start using natural language:
"Show me my unread emails"On first use, macOS will ask for permission to automate Mail.app. Click "OK" to allow.
Configuring email (IMAP & SMTP)
The server works out of the box over AppleScript with no configuration. Two opt-in power features take a one-time setup:
Fast IMAP reads — server-side search, counts, and large-mailbox handling that AppleScript is too slow for (it times out on big Gmail mailboxes).
Clean SMTP sending —
send-emailsubmits clean MIME directly, avoiding the macOS 15+ Mail.app<blockquote>wrapping that otherwise makes sent mail look quoted/indented like a reply.
Both are driven by non-secret APPLE_MAIL_MCP_* settings — supplied via an env
block or a config.json file (for hosts like Claude Desktop that strip env)
— with passwords kept in the macOS Keychain, never in config.
👉 IMAP / SMTP Setup Guide — step-by-step: app passwords,
Keychain, both config methods, multi-account, SMTP, verification with the doctor
tool, and troubleshooting. Verify any time by running the doctor tool.
Requirements
macOS - Apple Mail and AppleScript are macOS-only
Node.js 20+ - Required for the MCP server
Node.js 22.5+ and Full Disk Access - Required by
search-contactsonly. It reads the Contacts database directly through Node's built-innode:sqlite, which does not exist before 22.5. On an older runtime, or without Full Disk Access for the Node binary, it logs one line to stderr and returns an empty list rather than an error — so "no contacts found" can mean "cannot read Contacts". Every other tool works on Node 20+. See Node runtime & TCC permissions.Apple Mail - Must have at least one account configured (iCloud, Gmail, Exchange, etc.)
Features
Messages
Feature | Description |
List Messages | List messages with pagination, sender filter, date display |
Search Messages | Search by sender, subject, content, date range, read/flagged status — across all accounts |
Read Messages | Get full email content (plain text or HTML) |
Send Email | Compose and send new emails (attach by file path or inline base64 content) |
Send Serial Email | Mail merge — send personalized emails to a list of recipients with {{placeholder}} support |
Create Draft | Save emails to Drafts folder (attach by file path or inline base64 content) |
Reply | Reply to messages (with reply-all support) |
Forward | Forward messages to new recipients |
Get Thread | Group a conversation by normalized subject (across AppleScript or IMAP) |
Mark Read/Unread | Change read status (single or batch) |
Flag/Unflag | Flag or unflag messages (single or batch) |
Delete Messages | Move messages to trash (single or batch) |
Move Messages | Organize into mailboxes (single or batch) |
List Attachments | View attachment metadata (name, type, size) |
Save Attachment | Save attachments to disk |
Fetch Attachment | Get an attachment's bytes as base64 (no disk write) |
Read/list/get tools also return structured JSON (structuredContent) alongside the text, so agents can consume results without parsing prose.
Mailbox & Account Management
Feature | Description |
List Mailboxes | Show all folders with message/unread counts |
Create/Delete/Rename Mailbox | Full mailbox lifecycle management |
List Accounts | Show configured accounts |
Unread Count | Get unread counts per mailbox |
Rules, Contacts & Templates
Feature | Description |
List Rules | View all mail rules and their enabled status |
Enable/Disable Rules | Toggle mail rules on or off |
Create/Delete Rules | Create rules with conditions + actions, or delete by name |
Search Contacts | Look up contacts from Contacts.app by name |
Email Templates | Save, list, use, and delete reusable email templates (persisted to disk across restarts) |
Diagnostics
Feature | Description |
Health Check | Verify Mail.app connectivity |
Doctor | Diagnose Mail permission, account state, and each IMAP/SMTP backend with actionable messages |
Statistics | Message and unread counts per account, recently received stats |
Sync Status | Check if Mail.app is actively syncing |
Effect reconciliation | Every delete/move reports what it actually did to the mailbox ( |
MCP resources & prompts
Resources expose read-only context the client can attach without a tool call:
mail://accounts, mail://templates, and mail://mailboxes/{account}. Prompts
package common workflows: triage-inbox, compose-reply, weekly-summary.
Tool Reference
This section documents all available tools. AI agents should use these tool names and parameters exactly as specified.
Message Operations
search-messages
Search for messages matching criteria. Searches all accounts by default.
Parameter | Type | Required | Description |
| string | No | Text to search in subject/sender |
| string | No | Filter by sender email address |
| string | No | Filter by subject line |
| string | No | Mailbox to search in (omit to search all mailboxes) |
| string | No | Account to search in (omit to search all accounts) |
| boolean | No | Filter by read status |
| boolean | No | Filter by flagged status |
| string | No | Start date filter (e.g., "January 1, 2026") |
| string | No | End date filter (e.g., "March 1, 2026") |
| number | No | Max results, 1–500 (default: 50) |
Large mailboxes & partial results. Apple Mail's AppleScript bridge cannot search very large IMAP/Gmail mailboxes (tens of thousands of messages) before the Apple Event times out — empirically even reading the newest 20 messages of a 44k-message mailbox takes ~45s. To avoid burning minutes only to return a misleading empty result, an unscoped (all-mailboxes) search skips mailboxes whose message count exceeds a threshold (default 5000), enforces a per-account time budget, and reports anything it skipped or that timed out rather than silently returning nothing. When coverage is incomplete the result includes an explicit warning, e.g.:
⚠️ Partial results — this is NOT a confirmed "no such mail":
- skipped mailbox(es) too large to search via AppleScript: Gmail / All Mail (44287) — scope the search with `mailbox` + a `dateFrom`/`dateTo` window to target themTo search inside a large mailbox, scope the call with mailbox (and ideally a
dateFrom/dateTo window). Tune or disable the skip threshold with the
APPLE_MAIL_MAX_SEARCH_MAILBOX environment variable (default 5000; set to 0
to disable the guard and attempt every mailbox regardless of size).
(#24)
get-message
Get the full content of a message.
Parameter | Type | Required | Description |
| string | Yes | Message ID |
| boolean | No | Return HTML source instead of plain text |
| string | No | Mailbox holding the message (e.g. |
| string | No | Account holding the message. Pair with |
Returns: Subject line and message body (plain text by default, HTML if preferHtml is true and HTML content is available).
Large messages / attachments: reading a full message routes through
osascript, whose captured output buffer defaults to 64 MB. Override it with theAPPLE_MAIL_MCP_MAX_BUFFERenvironment variable (in bytes) if you work with messages whose raw MIME (e.g. a large embedded attachment) exceeds that — a value below the message size makes the read fail with a buffer-overflow error rather than truncating (#27).
list-messages
List messages in a mailbox.
Parameter | Type | Required | Description |
| string | No | Mailbox name (omit to list from all mailboxes) |
| string | No | Account name |
| number | No | Max messages, 1–500 (default: 50) |
| number | No | Number of messages to skip, ≥ 0 (for pagination) |
| string | No | Filter by sender email address or name |
| boolean | No | Only show unread messages |
Returns: List of messages with ID, date, subject, and sender.
send-email
Send a new email immediately.
⚠️ Safety: Sends real mail immediately and cannot be unsent. Confirm the recipients, subject, and body with the user before calling.
Parameter | Type | Required | Description |
| string[] | Yes | Recipient addresses |
| string | Yes | Email subject |
| string | Yes | Email body (plain text) |
| string[] | No | CC recipients |
| string[] | No | BCC recipients |
| string | No | Mail.app account label, or an email-form SMTP From override. An SMTP override must match |
| (string | {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths inside the configured read roots (e.g., |
|
| No | Send transport. If omitted, SMTP is used automatically when configured (otherwise AppleScript). Pass |
Example:
{
"to": ["colleague@company.com"],
"subject": "Meeting Tomorrow",
"body": "Hi, just confirming our meeting at 2pm tomorrow.",
"account": "Work",
"attachments": ["/Users/me/Documents/agenda.pdf"]
}SMTP transport
On macOS 15+ (Sequoia/Tahoe), Mail.app wraps any AppleScript-injected body in
<blockquote type="cite"> under the Apple-Mail-URLShareWrapperClass template,
so emails sent through the default applescript transport render to recipients
as if they were quoted/forwarded (Apple radar FB11734014, open since
Ventura). The SMTP transport bypasses Mail.app entirely and submits clean MIME
directly. Once SMTP is configured, send-email uses it automatically (no
need to pass transport per call); pass transport: "applescript" to force the
Mail.app path.
Two differences to know when SMTP is auto-preferred:
No Sent-folder copy. SMTP submission does not file the message in Mail.app's Sent mailbox (the server's own "save to Sent" may, depending on provider). Use
transport: "applescript"if you need the local Sent copy.accountis a From override, not account selection. Over SMTP,accountis used as the From address only when it is an email address; a Mail.app account label (e.g."Work") can't select an account over SMTP, so a call that passes one is left on the AppleScript path automatically. To force account selection, passtransport: "applescript"explicitly. For sender safety, an email-form override must match the SMTP login user, the configuredAPPLE_MAIL_MCP_SMTP_FROM, or an address listed in the comma-separatedAPPLE_MAIL_MCP_SMTP_ALLOWED_FROM; any other From address is rejected before connecting.
Both plain-text and HTML bodies are supported — over SMTP an HTML body (CLI
--html-body-file) is sent as multipart/alternative with the plain-text
fallback.
Configure SMTP via environment variables on the MCP server. The password is read from the macOS Keychain by default, so no secret goes in config:
Non-implicit-TLS SMTP connections fail closed if STARTTLS is unavailable.
APPLE_MAIL_MCP_SMTP_ALLOW_PLAINTEXT=1 is a deliberate escape hatch for a
trusted isolated server or test fixture; it disables the upgrade requirement and
can expose credentials and message content. The server emits a warning when it
is used. Keep the default unset.
Variable | Required | Default | Description |
| Yes | — | SMTP server hostname (e.g. |
| Yes | — | SMTP username |
| No |
| SMTP port |
| No |
|
|
| No |
| Set |
| No | = user | From address |
| No | — | Comma-separated sender aliases permitted as per-message From overrides |
| No | — | Password (if set, used instead of the Keychain) |
| No | = host | Keychain item service/server name |
| No | = user | Keychain item account |
Store the password in the Keychain once (an app-specific password for Gmail/
iCloud). A generic-password item with an explicit service name keeps it from
colliding with the system mail account password, and matches
APPLE_MAIL_MCP_SMTP_KEYCHAIN_SERVICE:
# Fastmail (Keychain service defaults to the host)
security add-internet-password -s smtp.fastmail.com -a you@example.com -w
# Gmail / Google Workspace, using a dedicated Keychain service name:
# APPLE_MAIL_MCP_SMTP_HOST=smtp.gmail.com
# APPLE_MAIL_MCP_SMTP_USER=you@gmail.com
# APPLE_MAIL_MCP_SMTP_KEYCHAIN_SERVICE=apple-mail-mcp-smtp
security add-generic-password -s apple-mail-mcp-smtp -a you@gmail.com -wOnce the env vars are set, a plain send-email (no transport) already goes
out clean:
{
"to": ["colleague@company.com"],
"subject": "Standings",
"body": "Plain body — no blockquote wrapping."
}apple-mail-send CLI (no MCP server required)
The package also installs an apple-mail-send binary — a standalone CLI over the
same SMTP path, for cron jobs, scheduled tasks, and scripts that can't run an MCP
session. It reads the identical APPLE_MAIL_MCP_SMTP_* env + Keychain config:
apple-mail-send \
--from you@example.com --to colleague@company.com \
--subject "Standings" --body-file /tmp/body.txt \
[--html-body-file /tmp/body.html] [--attach /tmp/report.pdf]Repeatable --to/--cc/--bcc/--attach; an --html-body-file is sent as a
multipart/alternative alongside the plain --body-file. Exit codes follow
sysexits.h: 0 success, 64 usage error, 66 unreadable body file, 78
SMTP not configured.
IMAP backend — opt-in
📘 For step-by-step setup (app passwords, Keychain, config methods, multi-account, upgrading, troubleshooting), see the IMAP / SMTP Setup Guide. The summary below is the reference; the guide is the walkthrough.
AppleScript runs search/list predicates client-side over the Apple Event
bridge, which is slow and can time out (false-empty) on large Gmail/IMAP
mailboxes (see #24), and
its delete/rename mailbox and draft handlers don't work on server-side
accounts at all (#42). When an account is configured for IMAP, the MCP routes to
a server-side IMAP backend (#43)
that is fast and correct on exactly those mailboxes. This is opt-in and
additive: any account without IMAP configured behaves exactly as before
(AppleScript).
What routes to IMAP when an account is IMAP-configured:
Read:
search-messages,list-messages(server-sideSEARCH, typically sub-second), andget-message.Folder ops:
create-mailbox,rename-mailbox,delete-mailbox— IMAP'sCREATE/RENAME/DELETEsucceed on the iCloud/Gmail/Workspace/Exchange mailboxes Mail.app's AppleScript bridge can't touch (#42).Message mutations:
mark-as-read/unread,flag-message/unflag-message,move-message,delete-message.Batch mutations (2.1):
batch-mark-as-read/unread,batch-flag/unflag-messages,batch-move-messages,batch-delete-messages—imap:ids are grouped by mailbox and applied as a singleUID STORE/UID MOVE; numeric ids in the same batch still use AppleScript.Counts & stats (2.1):
get-unread-countandlist-mailboxesuseSTATUS;get-mail-statsusesSTATUS+SEARCH SINCE— authoritative and fast even on huge mailboxes. As of v2.6.0 these prefer IMAP whenever it's configured (see Read routing below), merging across accounts when noaccountis given.Attachments (2.1):
list-attachments,save-attachment,fetch-attachmentuseBODYSTRUCTURE+FETCH BODY[part]forimap:ids — faster and able to see MIME-embedded attachments AppleScript misses.Threading (2.1):
get-threadlinks a conversation viaReferences/Message-ID(HEADER SEARCH) for animap:seed, falling back to subject grouping otherwise.
Message ids are backend-tagged. The IMAP read path emits self-describing ids
of the form imap:<token> (the token encodes the account, mailbox path, and
UID). Pass that id back to get-message, a message mutation, a batch op, or the
attachment/thread tools and it routes to IMAP automatically; bare numeric ids
continue to use AppleScript. So an agent never has to know which backend a
message came from — the id carries it.
Read routing (v2.6.0): reads PREFER direct IMAP whenever IMAP is configured.
The read tools — search-messages, get-thread, list-messages,
list-mailboxes, get-unread-count, get-mail-stats — now go to IMAP whenever
any APPLE_MAIL_MCP_IMAP_* account is configured, not just when an explicit
matching account is passed. There are three cases:
Explicit IMAP account — single-account IMAP (fast server-side path).
Explicit non-IMAP account — AppleScript (that account isn't on IMAP).
No
accountgiven — merge across all accounts: the query fans out over every configured IMAP account, and AppleScript runs only for the accounts no IMAP config covers (the account list is partitioned — accounts already served by IMAP are not re-scanned via AppleScript). If every Mail account is IMAP-configured, AppleScript is skipped entirely. The results are merged so no account is dropped. Message lists still de-duplicate as a safety net (preferring the IMAP copy, which carries the round-trippableimap:id) and sort newest-first; count tools (get-unread-count,get-mail-stats) count each account via exactly one backend so a coverage mismatch can never double- (or under-) count.An omitted mailbox on
search-messagessearches the account's entire store, not just one default folder (v2.17.1, #199). Per account, the fan-out uses the server-advertised RFC 6154\Allmailbox when one exists (Gmail/Workspace's[Gmail]/All Mail); otherwise it searches every selectable mailbox the server lists (iCloud, generic IMAP), merges the matches, de-duplicates by Message-ID, and sorts newest-first before applyinglimit/offset. A mailbox that can't be selected or searched is named in the result instead of silently dropping coverage. Scanning every mailbox on a large, deeply-nested account costs oneSEARCH+ a boundedFETCHper mailbox over the pooled IMAP connection — pin amailboxto skip the fan-out when you already know where to look.list-messages(no query) still defaults an omitted mailbox toINBOXon every provider — only unscoped search scans the whole account.
If IMAP is not configured at all, every read behaves exactly as before
(pure AppleScript). The three mailbox-write ops (create-mailbox,
delete-mailbox, rename-mailbox) remain conservative — they route to IMAP only
for an explicitly-named IMAP account, never on an omitted account.
Variable | Required | Default | Description |
| Yes | — | Login address; setting it enables IMAP |
| No | = user | Mail account name to match for routing |
| No |
| IMAP server hostname |
| No |
| IMAP port (993 = implicit TLS) |
| No |
| Set |
| No | — | Password (if set, used instead of the Keychain) |
| No | — | Keychain item service/server name |
| No | = user | Keychain item account |
| No | — | JSON array of additional IMAP accounts for multi-account setups (see below) |
| No |
| Set |
| No |
| Idle timeout (ms) before a pooled IMAP connection is closed ( |
| No |
| Per-account wall-clock budget for |
| No |
| Overall wall-clock deadline for one |
Multiple IMAP accounts (C2): set APPLE_MAIL_MCP_IMAP_ACCOUNTS to a JSON array, e.g.
[{"account":"Work","user":"me@co.com","host":"imap.co.com","keychainService":"imap.co.com"}].
Each entry accepts account, user, host, port, password, keychainService,
keychainAccount. Calls route to the account matching their account argument (or the
decoded imap: id), and each account keeps its own pooled connection.
Non-implicit-TLS IMAP connections require STARTTLS and fail closed when the server
does not offer a usable upgrade. APPLE_MAIL_MCP_IMAP_ALLOW_PLAINTEXT=1 is a
deliberate escape hatch for a trusted isolated server or test fixture; it disables
the upgrade requirement and can expose credentials and message content. Keep the
default unset.
As with SMTP, the password is read from the macOS Keychain by default (use
an app-specific password for Gmail/Workspace/iCloud), so no secret goes in
config. Gmail label semantics: common names (All Mail, Sent, Trash,
Spam, Important, …) map to their [Gmail]/… IMAP paths automatically.
Note: IMAP connections are pooled — one kept-alive connection per account is reused across calls (verified with a NOOP, closed after
APPLE_MAIL_MCP_IMAP_IDLE_MSof inactivity), so there's no per-call connection overhead (#50).iCloud: set
APPLE_MAIL_MCP_IMAP_HOST=imap.mail.me.com,APPLE_MAIL_MCP_IMAP_USERto your iCloud address,APPLE_MAIL_MCP_IMAP_ACCOUNTto the Mail account name (e.g.iCloud), and use an app-specific password (from appleid.apple.com) stored in the Keychain.
Connection footprint (playing nice with Gmail)
IMAP connections are a shared, capped resource: Gmail allows at most 15 simultaneous IMAP connections per account, and Apple Mail itself needs some of those slots. This server keeps its footprint small:
One pooled connection per account, reused across calls and closed after ~30s idle (tune with
APPLE_MAIL_MCP_IMAP_IDLE_MS;0= never close). So a server that isn't actively serving IMAP calls holds zero connections.IMAP IDLE is opt-in (
APPLE_MAIL_MCP_IMAP_IDLE=1). When on, it adds one persistent connection per account (a long-lived watcher), on top of the pooled request connection — leave it off if you don't need push notifications.Connections are dropped on shutdown — SIGINT/SIGTERM and stdin-EOF (the MCP client/parent going away). As of v2.6.1 the server also self-exits if it becomes orphaned (parent force-quit/crashed → reparented to launchd), polling every 30s, so it can't linger holding sockets after its session is gone.
The catch is multiple concurrent instances. A host like the Claude desktop
app spawns a separate set of MCP servers per open conversation (and respawns
them after a crash), so the footprint is per instance × accounts. With IDLE
off, an idle instance trends to 0 connections; with many active conversations
or IDLE on, the per-account total climbs toward Gmail's 15-connection cap and can
starve Apple Mail of slots (→ intermittent "cannot connect"). If you hit that,
close idle Claude conversations, keep APPLE_MAIL_MCP_IMAP_IDLE off unless you
need push, and/or lower APPLE_MAIL_MCP_IMAP_IDLE_MS.
Configuration file (when the host strips env)
Some host apps (e.g. Claude Desktop) launch the MCP server with a scrubbed
environment and ignore the env block in their server config, so there's no way
to pass APPLE_MAIL_MCP_* settings through it. In that case, put them in a JSON
file the host doesn't manage — APPLE_MAIL_MCP_CONFIG_FILE, or by default
~/Library/Application Support/apple-mail-mcp/config.json:
{
"APPLE_MAIL_MCP_IMAP_USER": "you@gmail.com",
"APPLE_MAIL_MCP_IMAP_HOST": "imap.gmail.com",
"APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE": "imap.gmail.com",
"APPLE_MAIL_MCP_IMAP_KEYCHAIN_ACCOUNT": "you@gmail.com",
"APPLE_MAIL_MCP_IMAP_IDLE": "1"
}The server reads it at startup and merges values into the environment without
overriding anything already set there (so an explicit env still wins). Store
only non-secret config here — passwords belong in the Keychain, never in this
file.
Push notifications (IMAP IDLE) — opt-in
When APPLE_MAIL_MCP_IMAP_IDLE=1, the server opens a dedicated, long-lived
connection to each configured IMAP account and watches its INBOX for new
mail. On arrival it pushes two MCP notifications to the client (no polling by the
client required):
notifications/message(logging) — a human-readable line, e.g.New mail in "Work": 2 new message(s) (INBOX now 1843).notifications/resources/updated— for the affected account's resourcemail://mailboxes/{account}, so a client subscribed to that resource knows to re-read it.
This requires an IMAP account to be configured (single-account env or
APPLE_MAIL_MCP_IMAP_ACCOUNTS); accounts that only use AppleScript aren't
watched. Detection is real-time via the IMAP IDLE EXISTS event where the
server pushes it, with an automatic polling fallback for servers that don't.
Dropped connections reconnect with backoff, and the watchers shut down cleanly on
SIGINT/SIGTERM.
Enable it in your MCP client config alongside the IMAP settings:
{
"mcpServers": {
"apple-mail": {
"command": "node",
"args": ["/path/to/apple-mail-mcp/build/index.js"],
"env": {
"APPLE_MAIL_MCP_IMAP_USER": "you@gmail.com",
"APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE": "imap.gmail.com",
"APPLE_MAIL_MCP_IMAP_IDLE": "1"
}
}
}
}Note: this is most useful with clients that surface MCP logging messages or subscribe to resource-update notifications. Clients that ignore notifications are unaffected — the feature is opt-in and adds no behavior unless enabled.
send-serial-email
Send individual personalized emails to a list of recipients (mail merge). Each recipient receives their own email — recipients don't see each other. Supports {{placeholder}} tokens in both subject and body.
Parameter | Type | Required | Description |
| object[] | Yes | List of recipients, max 100 (see below) |
| string | Yes | Email subject — use |
| string | Yes | Email body — use |
| string | No | Send from specific account |
| number | No | Delay between sends in ms (default: 500, max 10000) |
Each recipient object:
Field | Type | Required | Description |
| string | Yes | Recipient email address |
| object | Yes | Key-value pairs for placeholder replacement |
Example:
{
"recipients": [
{ "email": "alice@example.com", "variables": { "Name": "Alice", "Company": "Acme" } },
{ "email": "bob@example.com", "variables": { "Name": "Bob", "Company": "Globex" } }
],
"subject": "Hello {{Name}}!",
"body": "Dear {{Name}},\n\nGreat to connect about {{Company}}.\n\nBest regards"
}Returns: Per-recipient success/failure results with a summary count.
⚠️ Safety: Sends real mail immediately to every recipient and cannot be unsent. Confirm the recipient list, subject, and body with the user before calling.
create-draft
Save an email to Drafts without sending.
Parameter | Type | Required | Description |
| string[] | Yes | Recipient addresses |
| string | Yes | Email subject |
| string | Yes | Email body (plain text) |
| string[] | No | CC recipients |
| string[] | No | BCC recipients |
| string | No | Account for draft |
| (string | {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths inside the configured read roots and/or inline |
Returns: Confirmation that draft was created.
get-thread
Group a conversation by normalized subject (across the AppleScript or IMAP backend).
Parameter | Type | Required | Description |
| string | Yes | A message ID in the conversation (numeric or |
| string | No | Account to search (omit to search all) |
| string | No | Mailbox to search (omit to search all) |
| number | No | Max messages in the thread (default 50) |
Returns: The conversation's messages, oldest-first.
fetch-attachment
Return an attachment's bytes as base64 (the read counterpart to inline-base64 send).
Parameter | Type | Required | Description |
| string | Yes | Message ID (numeric or |
| string | Yes | Attachment filename (from |
Returns: The attachment bytes, base64-encoded (also in structuredContent.contentBase64).
resolve-message-id
Map imap: message IDs to their numeric Mail.app IDs, via each message's RFC 5322 Message-ID (the join key both backends share). Needed only for the two tools that are numeric-ID-only — reply-to-message and forward-message. Numeric IDs pass through unchanged.
Parameter | Type | Required | Description |
| string[] | Yes | 1–100 message IDs, each numeric or |
Returns: For each input ID, its numericId (or null when it can't be resolved) and the messageId used, plus count and resolvedCount. The lookup scopes to the message's account and checks its INBOX first, to avoid scanning a large All Mail/Archive mailbox.
You do not need this for flag colors (v2.10.0+). Colors used to require the numeric-ID path, and older docs and tool descriptions said so.
flag-messageandbatch-flag-messagesnow write the color over IMAP directly, as Mail.app's$MailFlagBit0/1/2keywords, so a smart mailbox keyed on flag color matches an IMAP-flagged message. Resolving IDs just to apply a color reintroduces the AppleScript/TCC dependency 2.10.0 removed. Flag, move, mark, and delete all acceptimap:IDs as-is.
reply-to-message
Reply to an existing message.
Parameter | Type | Required | Description |
| string | Yes | Message ID to reply to |
| string | Yes | Reply body |
| boolean | No | Reply to all recipients (default: false) |
| boolean | No | Send immediately (default: true, false = save as draft) |
Example - Reply to sender only:
{
"id": "12345",
"body": "Thanks for the update!"
}Example - Reply all, save as draft:
{
"id": "12345",
"body": "I'll review this and get back to everyone.",
"replyAll": true,
"send": false
}Transport (v2.5.0): when SMTP is configured,
reply-to-messagesends via clean SMTP, threading the reply with proper RFC 5322In-Reply-To/Referencesheaders (built from the original message) so it lands in the same conversation. When SMTP is not configured (or the original lacks the headers needed to thread), it falls back to Mail.app's AppleScriptreply … without opening window— same reliable-from-background-process path as before. See SMTP transport.
⚠️ Safety: With the default send: true, sends real mail immediately and cannot be unsent. Confirm the recipients, subject, and body with the user before calling (or pass send: false to save a draft for review).
forward-message
Forward a message to new recipients.
Parameter | Type | Required | Description |
| string | Yes | Message ID to forward |
| string[] | Yes | Recipients to forward to |
| string | No | Message to prepend |
| boolean | No | Send immediately (default: true, false = save as draft) |
Transport (v2.5.0): when SMTP is configured,
forward-messagesends via clean SMTP (a fresh message with the original quoted, no threading headers — a forward starts a new conversation). When SMTP is not configured it falls back to Mail.app's AppleScriptforward … without opening window. See SMTP transport.
⚠️ Safety: With the default send: true, sends real mail immediately and cannot be unsent. Confirm the recipients, subject, and body with the user before calling (or pass send: false to save a draft for review).
mark-as-read / mark-as-unread
Change read status of a message.
Parameter | Type | Required | Description |
| string | Yes | Message ID |
flag-message / unflag-message
Flag or unflag a message. flag-message optionally takes a flag color; unflag-message removes the flag entirely (which also clears any color).
Parameter | Type | Required | Description |
| string | Yes | Message ID |
| string | No | ( |
Flag colors are an Apple Mail feature — the message's flag index (0 red, 1 orange, 2 yellow, 3 green, 4 blue, 5 purple, 6 gray), which is the property a Mail smart mailbox can match on. The color is applied on both routes (since 2.10.0): AppleScript sets the flag index directly, and for an IMAP-routed id (imap:…) the color is written as Mail.app's $MailFlagBit0/1/2 keywords — a 3-bit field holding the same palette index. \Flagged on its own really is colorless, but those keywords ride alongside it in an ordinary UID STORE, so a smart mailbox keyed on flag color matches an IMAP-flagged message too. You do not need to resolve to a numeric id just to color a flag.
To read a color, the IMAP read path returns flagColorIndex in structuredContent — the same 0-6 palette index, omitted when the message carries no color bits. The AppleScript read path does not populate it.
delete-message
Delete a message (move to trash).
Parameter | Type | Required | Description |
| string | Yes | Message ID |
structuredContent carries countDelta — what the delete actually did to the
source mailbox. See Auditing destructive operations.
⚠️ Safety: Destructive. Requires explicit user confirmation; search/list first to confirm the message id.
move-message
Move a message to a different mailbox.
Parameter | Type | Required | Description |
| string | Yes | Message ID |
| string | Yes | Destination mailbox — full path ( |
| string | No | Account containing mailbox |
A destination is matched first as a full path, then as a leaf name. If a leaf
name matches more than one mailbox (e.g. Archive under both Work and
Thornlands), the move is refused with an error naming every candidate — pass
the full path. The same applies to batch-move-messages, delete-mailbox and
rename-mailbox.
structuredContent carries countDelta — what the move actually did to the
source mailbox. See Auditing destructive operations.
list-attachments
List attachments on a message.
Parameter | Type | Required | Description |
| string | Yes | Message ID |
Returns: List of attachments with name, MIME type, and size.
save-attachment
Save a message attachment to disk.
The destination must not already exist: save-attachment fails closed instead
of overwriting an existing file. AppleScript and MIME fallback paths stage the
bytes privately, commit with an exclusive create, and leave the saved file
owner-readable/writable (0600).
Parameter | Type | Required | Description |
| string | Yes | Message ID |
| string | Yes | Filename of the attachment |
| string | Yes | Directory to save to |
Batch Operations
All batch operations accept an array of message IDs (max 100 per batch) and return per-item success/failure results.
Numeric IDs are scoped to the mailbox you listed them from. Mail.app numbers messages per
mailbox, so on a label store (Gmail, iCloud) one message answers to the same id in INBOX,
Important and All Mail at once — and deleting the All Mail copy is not the same operation as
deleting the INBOX copy. Each id is therefore bound to the mailbox it was listed/searched from and
the operation is applied only there, so list or search the mailbox immediately before acting on
it. An id the server hasn't seen listed is accepted only when exactly one mailbox holds it;
if several do, that id fails with the candidate mailboxes named instead of being applied to an
arbitrary copy. imap:… ids carry their own account + mailbox + UID and are never ambiguous.
Say which mailbox with sourceMailbox / sourceAccount. The binding above is remembered
per running server, so a client that reconnects, restarts, or replays a saved list of ids has
nothing recorded and every id takes the slower whole-tree path — where, on a label store, it is
likely to be refused as ambiguous. Passing the source mailbox explicitly is the reliable way to
stay scoped, and it overrides the remembered location. These parameters name where the ids came
from; for batch-move-messages that is distinct from mailbox, the destination.
sourceMailbox and sourceAccount are an atomic scope pair: provide both for numeric ids.
The server never fills in a missing account from mutable default-send state, because the same
mailbox name can exist in more than one account and numeric ids are only unique within an account
and mailbox. A whitespace-only source field is rejected. sourceAccount by itself pins nothing,
since the mailbox is what an id is scoped to; imap:… ids ignore both fields because they carry
their own account, mailbox, and UID identity.
A repeated id is one message. ids is treated as a set: a duplicate names the same message,
so it is operated on once, and the batch returns one result per distinct id. success is
therefore a count of messages, not of list positions.
batch-delete-messages
Parameter | Type | Required | Description |
| string[] | Yes | Message IDs to delete (max 100) |
| string | No | Mailbox the numeric ids were listed from — pins them to it. Ignored for |
| string | No | Account the numeric ids were listed from. Required when |
structuredContent carries countDelta — what the batch actually did to each
source mailbox. See Auditing destructive operations.
⚠️ Safety: Destructive. Requires explicit user confirmation; search/list first to confirm the message ids.
batch-move-messages
Parameter | Type | Required | Description |
| string[] | Yes | Message IDs to move (max 100) |
| string | Yes | Destination mailbox |
| string | No | Account containing mailbox |
| string | No | Mailbox the numeric ids were listed from — pins them to it. Ignored for |
| string | No | Account the numeric ids were listed from. Required when |
structuredContent carries countDelta — what the batch actually did to each
source mailbox. See Auditing destructive operations.
batch-mark-as-read / batch-mark-as-unread
Parameter | Type | Required | Description |
| string[] | Yes | Message IDs (max 100) |
| string | No | Mailbox the numeric ids were listed from — pins them to it. Ignored for |
| string | No | Account the numeric ids were listed from. Required when |
batch-flag-messages / batch-unflag-messages
Parameter | Type | Required | Description |
| string[] | Yes | Message IDs (max 100) |
| string | No | ( |
| string | No | Mailbox the numeric ids were listed from — pins them to it. Ignored for |
| string | No | Account the numeric ids were listed from. Required when |
Mailbox Operations
list-mailboxes
List all mailboxes for an account.
Parameter | Type | Required | Description |
| string | No | Account to list from, or |
Returns: List of mailbox paths (account-relative, e.g. Archive/Inbox for
a nested mailbox — a top-level Inbox stays Inbox) with message and unread
counts. A source that could not be read is named (partial: true +
failedAccounts) rather than dropped, and a listing Mail refused outright
returns an error naming the accounts that do exist — never an empty list.
Nested mailboxes and Gmail labels. Every mailbox parameter across this
server (search-messages, list-messages, get-unread-count, move-message,
delete-mailbox, rename-mailbox, create-rule's moveTo) accepts either the full
path or a leaf name that is unique across the account — the same rule
move-message has always used. A leaf name that matches more than one mailbox
(e.g. a top-level Inbox and an Archive/Inbox on an Exchange account) is
refused rather than guessed; pass the full path to disambiguate. This also
means Gmail's nested special mailboxes now report their real path, e.g.
[Gmail]/All Mail rather than All Mail — a visible change from before 2.17.0.
Mail's local "On My Mac" mailboxes are not children of any account — they
hang off the application — so they are reported under the synthetic account label
On My Mac. An unscoped call includes them (listed last); account="On My Mac" lists only them. on my computer, local and local folders are accepted
as aliases.
They deliberately do not appear in list-accounts, which reports real
accounts only: the local store is a store, not an account. Nothing selects it
implicitly — omitting account still resolves to a real account for every other
tool.
The mail inside them is reachable too: list-messages and search-messages
accept account="On My Mac", and get-message resolves an id that lives only in
a local mailbox. An id present both in an account mailbox and locally is
reported as ambiguous rather than silently resolving to the account copy.
get-unread-count
Get unread message count.
Parameter | Type | Required | Description |
| string | No | Mailbox to check (omit for INBOX) |
| string | No | Account to check (omit to sum each account's INBOX) |
Returns: The unread count for the requested scope.
Omitting
mailboxcounts INBOX, not a cross-mailbox total. This changed in 2.8.15: summing every mailbox was slow and wrong on Gmail, where one message appears in INBOX, All Mail and every label it carries. For account-wide totals useget-mail-stats.
create-mailbox
Create a new mailbox.
Parameter | Type | Required | Description |
| string | Yes | Mailbox name |
| string | No | Account to create in |
delete-mailbox
Delete a mailbox.
Parameter | Type | Required | Description |
| string | Yes | Mailbox name |
| string | No | Account containing mailbox |
⚠️ Safety: Destructive — deletes the mailbox and its contents. Requires explicit user confirmation; list mailboxes first to confirm the name.
rename-mailbox
Rename a mailbox (creates new, moves messages, deletes old).
Parameter | Type | Required | Description |
| string | Yes | Current mailbox name |
| string | Yes | New mailbox name |
| string | No | Account containing mailbox |
Smart Mailbox Operations (intelligente Postfächer)
Requires Full Disk Access. These tools read and write
~/Library/Mail/V*/MailData/SyncedSmartMailboxes.plist, which is TCC-protected. Without Full Disk Access for the server's Node runtime the read simply finds nothing, and the tools report "no smart mailboxes" or "launch Mail at least once" rather than a permission error — see Node runtime & TCC permissions.
Smart mailboxes are Apple Mail's criteria-based virtual views — not real folders, so no messages are moved. AppleScript's smart mailbox / intelligentes Postfach terms don't compile reliably on localized (e.g. German) macOS, so these tools read and edit ~/Library/Mail/V*/MailData/SyncedSmartMailboxes.plist directly.
How writes stay safe: creating or deleting a smart mailbox first backs the plist up to SyncedSmartMailboxes.plist.bak, edits a temp copy with plutil/PlistBuddy, validates it with plutil -lint, and only then atomically renames it into place. Your existing smart mailboxes — including any with date/data criteria — are never rewritten, only the single target entry is added or removed. These tools do not quit or restart Mail: quit Mail first for reliable results, since a running Mail may not show a new smart mailbox until it's relaunched and can overwrite plist edits it didn't make.
list-smart-mailboxes
List existing smart mailboxes.
Parameters: None
Returns: List of smart mailbox names + criteria summary.
create-smart-mailbox
Create a smart mailbox with a simple contains rule.
Parameter | Type | Required | Description |
| string | Yes | Name for the smart mailbox |
| string | No | Match if From contains this |
| string | No | Match if Subject contains this |
| string | No | Match if Body contains this |
Provide at least one of the three *Contains fields.
⚠️ Safety: edits SyncedSmartMailboxes.plist (backed up + atomic, existing smart mailboxes preserved). Quit Mail first for reliable results; the new smart mailbox appears the next time Mail launches.
delete-smart-mailbox
Delete a smart mailbox by name.
Parameter | Type | Required | Description |
| string | Yes | Smart mailbox name |
⚠️ Safety: destructive — removes the smart mailbox from SyncedSmartMailboxes.plist (backed up + atomic; every other smart mailbox is preserved). Not undoable in-app. Confirm the exact name with list-smart-mailboxes first, and quit Mail first for reliable results.
create-newsletter-smart-mailboxes
High-level tool: scan recent messages in your INBOXes, detect likely newsletters (volume + signals like List-Unsubscribe, noreply, repetitive subjects), and create smart mailboxes for them (names prefixed "NL: ...").
Parameter | Type | Required | Description |
| boolean | No | Default true — only propose, do not create |
| number | No | Min messages from a sender (default 3) |
| number | No | Lookback window in days (default 90) |
Defaults to a safe dry run that only proposes. Pass dryRun: false to actually create the smart mailboxes for newsletters cluttering your Inbox.
⚠️ Safety: with dryRun: false this edits SyncedSmartMailboxes.plist (backed up + atomic, existing entries preserved) and can create many smart mailboxes at once — review a dry run first. Scans up to ~400 recent messages per inbox via AppleScript, which can be slow on large mailboxes.
Account Operations
list-accounts
List all configured Mail accounts.
Parameters: None
Returns: List of account names and email addresses.
Rules
list-rules
List all mail rules.
Parameters: None
Returns: List of rule names and enabled status.
enable-rule / disable-rule
Enable or disable a mail rule.
Parameter | Type | Required | Description |
| string | Yes | Rule name |
create-rule
Create a Mail rule with one or more conditions and actions.
Parameter | Type | Required | Description |
| string | Yes | Rule name (must be unique) |
| object[] | Yes | One or more |
| object | Yes | At least one of |
| boolean | No |
|
| boolean | No | Whether the rule is enabled on creation (default |
Each condition is { field, operator, value } where field is one of from, to, cc, subject, content and operator is one of contains, notContains, equals, beginsWith, endsWith. Actions: markRead / markFlagged / delete (booleans), moveTo (mailbox name) with optional moveToAccount.
New rules are created disabled by default, including rules that delete or move
messages. Review the conditions and actions with list-rules and in Mail.app,
then call enable-rule explicitly when the rule is approved. Set
enabled: true only when immediate activation is deliberate.
Example:
{
"name": "Newsletters",
"conditions": [{ "field": "from", "operator": "contains", "value": "newsletter" }],
"actions": { "markRead": true, "moveTo": "Reading" }
}delete-rule
Delete a mail rule by name.
Parameter | Type | Required | Description |
| string | Yes | Rule name |
⚠️ Safety: Destructive. Requires explicit user confirmation; list rules first to confirm the name.
Contacts
search-contacts
Search the macOS Contacts database by name, organization, nickname, or email substring.
Since 2.8.7 this reads the AddressBook SQLite files directly rather than driving Contacts.app over AppleScript, so Contacts.app need not be running and no Automation grant is involved — but the Node runtime does need Full Disk Access, and Node 22.5+ (see Requirements). Without either, the tool returns an empty list rather than an error.
Parameter | Type | Required | Description |
| string | Yes | Substring matched against full name, organization, nickname, or any email address |
Returns: List of contacts with name, email addresses, and phone numbers. Results are not truncated — a broad query returns every match.
Templates
Email templates are persisted to disk so they survive server restarts, stored as JSON at APPLE_MAIL_MCP_TEMPLATES_FILE (default ~/Library/Application Support/apple-mail-mcp/templates.json).
save-template
Save or update an email template.
Parameter | Type | Required | Description |
| string | Yes | Template name |
| string | Yes | Default subject line |
| string | Yes | Template body |
| string[] | No | Default recipients |
| string[] | No | Default CC recipients |
| string | No | Template ID (for updating) |
list-templates
List all saved templates.
Parameters: None
get-template
Get a template by ID.
Parameter | Type | Required | Description |
| string | Yes | Template ID |
delete-template
Delete a template.
Parameter | Type | Required | Description |
| string | Yes | Template ID |
⚠️ Safety: Destructive — removes the template from the on-disk store. Requires explicit user confirmation; list templates first to confirm the id.
use-template
Create a draft from a template, with optional overrides.
Parameter | Type | Required | Description |
| string | Yes | Template ID |
| string[] | No | Override recipients |
| string[] | No | Override CC |
| string | No | Override subject |
| string | No | Override body |
Diagnostics
health-check
Verify Mail.app connectivity and permissions.
Parameters: None
Returns: Status of all health checks (app running, permissions, account access).
doctor
Run a full setup diagnostic: Mail.app automation permission, account state (flagging disabled accounts), and each configured IMAP/SMTP backend — each reported as ok / warn / fail with an actionable message.
Parameters: None
Returns: A per-check report (structuredContent carries the raw {healthy, checks[]}).
get-mail-stats
Get mail statistics.
Parameter | Type | Required | Description |
| string | No | Limit to one account (uses fast IMAP |
Returns: Total and per-account message/unread counts, plus recently received stats (24h, 7d, 30d). The scoped IMAP path also returns a perMailbox breakdown.
Gathering stats costs one IMAP STATUS per mailbox, and Gmail lists every label
as a mailbox, so a large account is not instant. Accounts are counted
concurrently, and each is bounded by APPLE_MAIL_MCP_STATS_BUDGET_MS
(default 25000). In the merged all-accounts path an account that fails or
overruns is reported via partial: true + failedAccounts rather than being
folded in as a silent zero; a scoped call to a single account returns an error
naming the budget instead. Raise the budget if you have a very large account.
The whole call is additionally bounded by one wall-clock deadline,
APPLE_MAIL_MCP_STATS_DEADLINE_MS (default 50000), which covers the Mail.app
account enumeration as well as every per-account read. Per-step budgets alone
were not enough: their worst cases add up, and the sum could exceed a
client's request timeout, so the call died with nothing returned instead of
degrading. Keep the deadline below your MCP client's request timeout — whatever
cannot be read inside it is named in failedAccounts, so you always get a
partial answer rather than a dead call.
Concurrent get-mail-stats calls do not run concurrently. Tool calls are
serialized so they cannot race into Mail.app's single-threaded AppleScript
dispatch, so each call waits for the ones ahead of it and per-call latency grows
with queue depth — N concurrent calls take about N × the single-call cost. Since
this is the most expensive read tool, that is very visible here: measured on 3
IMAP accounts, three concurrent calls returned at 5.5s / 10.3s / 15.6s against a
~5.2s solo cost. The deadline is measured from when the request arrived, so
that wait is spent from the same budget as the work: a call that waited ≥1s
reports queueWaitMs, and one that arrives with its deadline already spent
returns straight away naming the queue rather than starting work whose answer
would land after your client has given up. Issue these calls one at a time, and
prefer get-unread-count when a single number will do.
get-sync-status
Check Mail.app sync activity.
Parameters: None
Returns: Whether sync is detected, pending uploads, recent activity, and seconds since last change.
Auditing destructive operations
delete-message, move-message, batch-delete-messages and
batch-move-messages report what they actually did, not merely that Mail.app did
not raise an error. This exists because of
#155: a batch delete was
reported to have removed two messages whose ids were never passed, and nothing in
the server recorded enough to explain it.
countDelta — always on, no configuration
Every one of those four tools counts the affected source mailbox immediately
before and immediately after the mutation, inside the same AppleScript it was
already running (no extra osascript invocations, no measurable cost), and
returns the comparison in structuredContent:
{
"ok": true,
"success": 2,
"failed": 0,
"countDelta": [
{
"account": "you@gmail.com",
"mailbox": "INBOX",
"before": 412,
"after": 408,
"expected": 2,
"observed": 4,
"status": "over"
}
]
}status is deliberately not a pass/fail flag:
| Meaning | Warns? |
| Exactly as many messages left the mailbox as the operation acted on. | No |
| More left than were operated on. Messages are unaccounted for. | Yes |
| No comparison this server is willing to assert. | No |
unknownReason distinguishes four cases that are not interchangeable:
| Meaning |
| Mail would not report a count at all ( |
| No expectation is predictable, so no comparison exists — a move whose destination is the source mailbox. |
| The count did not move. On a store that flags deletions instead of removing them this is the ordinary, correct reading for an operation that fully succeeded. |
| The count moved, but by less than the operation accounted for. A flag-only store cannot produce this, which is why it is worth telling apart. |
underwas removed in 2.11.0. It used to mean "fewer left than expected" and was documented as routine. Field evidence retired it — see Whyobservedis a lower bound.
What an over warning does and does not tell you
Only over produces a warning in the tool's text response. Be precise about what
that warning proves, because a warning is useful only for as long as it is
trusted:
It establishes that more messages left the source mailbox across the window of the operation than the operation accounted for. That is the data-loss direction, and it is the #155 signature.
It does not establish that this server removed them. The reading is a before/after pair around a window, so anything else that removes mail from that mailbox inside the window reads identically: a Mail.app rule firing mid-batch, a server-side filter, another client (phone, webmail, a second Mail.app) deleting or moving, or an IMAP expunge landing between the two counts.
Concurrent departure is the benign cause to rule out first, and the warning
text says so. What the asymmetry argument actually buys is the other half:
concurrent arrivals cannot produce over, because a message arriving
mid-operation raises the after-count and biases the reading short.
That is why over is the interesting direction — a strong signal, not a proof.
Setting APPLE_MAIL_MCP_AUDIT_LOG is what settles which one you have: the
collateral diff below names the messages that disappeared, and "the
newsletter my rule files every morning" is a very different report from a message
nothing should have touched.
Why observed is a lower bound (#155)
observed is the movement of Mail's count. It is a lower bound on how many
messages left, not a count of how many left.
On iCloud, @scottstern0325 ran the check that settled this: for two batches
reporting observed: 0, the messages were located in Trash, matched by
date received + sender against the audit log's pre-image. The deletes had
happened. Mail's count had not caught up. Across four readings — 0 of 4, 0 of 1
(a single-id delete), 15 of 16, and 14 of 15 — the shortfall bore no relation
to batch size, which is what a lagging count looks like and not what a
store-behaviour rule looks like.
So a short reading is not evidence about your operation. The per-id outcomes are what report success; this number is not. Do not retry on the strength of it — that is how a message gets deleted twice.
Two things follow:
A count that does not move at all is still the ordinary reading on a store that flags deletions instead of removing them (Gmail label mailboxes, IMAP accounts with "move deleted messages to Trash" off). It reports
unknownReason: "count-did-not-move"and says so, and it is never warned about — a warning that fires on every ordinary Gmail delete would be ignored exactly when it matters.To confirm where messages went, match them at the destination by
date receivedplus sender — not by the numeric ids you passed. Ids are renumbered by the move and do not survive it.
Removed in 2.11.0: the "reported success with no observed effect" warning.
Shipped in 2.10.30, it fired when the count was flat, the snapshot read cleanly
and nothing had disappeared. Its premise was that the snapshot corroborated the
count — but both are read back-to-back in the same script, and the record that
prompted it turns out to have had both instruments stale at once. It therefore
fired on stores that had done exactly what they were asked. It is gone rather
than narrowed; over is the only surviving assertion.
Three more honesty rules:
The expectation is per source mailbox. On a Gmail label store, deleting the
INBOXcopy drops the\Inboxlabel and deleting the[Gmail]/All Mailcopy trashes the message — different operations, but either way the mailbox the ids came from loses exactly one entry per id. That is what is compared. A move's destination count is not checked.A move whose destination is the source mailbox is not compared at all. No message should leave, but what Mail does to the count when a message is re-filed into the mailbox it already occupies is unspecified — so
expectedisnull,statusisunknown,notesays why, and no warning is raised. A warning computed against a guessed expectation would fire on an operation that did exactly what it was asked to, which is the one thing this instrumentation must never do.This makes a self-move a blind spot for the always-on layer, and the cost is worth stating plainly: if messages genuinely do disappear during a self-move, nothing warns you, because there was no expectation to compare against.
statusisunknownrather thanmatch, so the result does not claim the operation was clean — but it does not flag it either. The collateral diff still names anything that vanished, so enableAPPLE_MAIL_MCP_AUDIT_LOGif you need coverage for same-mailbox moves.A repeated id is one message. The batch tools operate on each distinct id once and return one result per distinct id, so
successcounts messages rather than list positions — andexpectedstays comparable with the mailbox instead of double-counting a duplicate into a falseover.
imap: ids are reconciled too, as of 2.15.0. batch-delete-messages and
batch-move-messages return the same countDelta structure on the IMAP path, so
one shape covers both backends and a mixed batch reports an entry per source
mailbox from whichever backend handled it. The entries are concatenated, never
summed — Mail's own count can lag (#155) while the server's STATUS cannot, and
averaging the two would hide which reading you were looking at.
Only the operations that actually remove messages from their source reconcile.
batch-mark-as-read and the flag tools change no count, so emitting
expected: N, observed: 0 for them would manufacture an alarm; they report no
countDelta at all.
Note the mis-targeting class countDelta was originally built for cannot occur
on the IMAP path — a UID names exactly one message in exactly one mailbox — so
there the value is effect confirmation rather than target confirmation.
Single-message tools carry a post-condition check instead. delete-message and
move-message on an imap: id return a verification object in
structuredContent:
{
"verification": {
"verdict": "verified",
"how": "COPYUID: UID 5 arrived in \"Archive\" as UID 91"
}
}
| Meaning |
| The effect was observed — either the server's UIDPLUS |
| The server accepted the command and nothing could confirm the effect. Populates |
unverified is not a failure and must not be rendered as one — it means
"accepted, no observation either way". It is reported rather than hidden because
an absent verification must never read as a successful one, the same rule the
collateral diff follows. A message that is still in the source mailbox after an
accepted move is reported unverified rather than failed, because a Gmail label
store can legitimately keep a message visible in an all-mail view after a move.
APPLE_MAIL_MCP_AUDIT_LOG — opt-in forensic log
Variable | Default | Description |
| (off) | Absolute path to an NDJSON file. Setting it enables the audit log and the collateral diff below |
|
| Set |
|
| Skip the collateral snapshot for mailboxes larger than this many messages. |
|
| How many messages the collateral snapshot reads from Mail per request. Lower it if Mail declines slices on a very large mailbox |
When set, each destructive operation appends one JSON object per line
containing: timestamp, tool name, server version, the arguments it was called
with, the pre-image of every message it resolved (account, mailbox, numeric
id, RFC Message-ID, date received), the per-id outcome (ok / notfound /
error + reason), the countDelta above, and the collateral diff.
The pre-image is the part that matters after the fact: a Mail.app numeric id is unique only within a mailbox and is reused, so on its own it proves nothing about which message was acted on. The RFC Message-ID does.
The record is framed against its own contents. The Message-ID and (when
enabled) the subject are written by whoever sent the mail, so the control
characters this server frames records with are stripped out of every such value
before it is written — a Message-ID crafted to close a record and open a forged
one cannot invent evidence in the log it is being recorded in. The same stripping
is applied to every other value read out of Mail at runtime (date received,
mailbox and account names, the text of an error Mail raised, the candidate list
behind an "ambiguous id" refusal), so no emitter is an exception. A value that
arrives with those characters in it (which a well-formed Message-ID never does)
is logged with each of them replaced by U+FFFD, so the record shows that the
value was altered rather than quietly shortening it.
Collateral identification — which messages actually disappeared
Also gated on APPLE_MAIL_MCP_AUDIT_LOG. The mailbox's (numeric id, Message-ID)
pairs are captured before and after the mutation and diffed, so the log names
every message that left — including ones the caller never listed:
{
"account": "you@gmail.com",
"mailbox": "INBOX",
"snapshot": "ok",
"disappeared": [
{ "id": "75811", "messageId": "a@example.com" },
{ "id": "75814", "messageId": "d@example.com" }
],
"unrequested": [{ "id": "75814", "messageId": "d@example.com" }],
"appeared": []
}A non-empty unrequested is the #155 symptom, with names attached. Please
attach that line to the issue if you ever see one.
id is always the plain decimal id you passed, even on a mailbox whose ids
exceed AppleScript's 2^29 integer range (where Mail hands them back as
9.99999999E+8). That normalisation is also what keeps unrequested truthful:
compared in the raw form, a message you explicitly asked to delete would be
reported here as collateral.
This is O(mailbox size), so it is bounded by APPLE_MAIL_MCP_AUDIT_SNAPSHOT_MAX.
When the bound bites, the record says so explicitly ("snapshot": "skipped" with
a reason) rather than omitting the field — a silently skipped snapshot would read
as "nothing collateral happened", which is worse than no snapshot at all.
countDelta is unaffected by the skip and still reconciles the counts.
Partial snapshots on large mailboxes
The mailbox is read in APPLE_MAIL_MCP_AUDIT_SNAPSHOT_CHUNK-sized slices, each
retried once on its own. It used to be a single whole-mailbox read, which meant
Mail declining that one request lost the entire diff — and the bigger the
mailbox, the more likely that was. The mechanism that attributes collateral
damage was therefore least reliable exactly when the blast radius was largest.
When a slice still will not read, the snapshot is reported as partial and it
names its own gap:
{
"snapshot": "partial",
"unobserved": [{ "phase": "after", "ranges": "251-500" }],
"appeared": [],
"skipReason": "Mail would not read 251-500 (after) of this mailbox, so the snapshot has a hole in it. …"
}Each half of the diff is withheld when the snapshot that could refute it has a hole, because a wrong name here is worse than a missing one:
Hole in |
|
|
neither ( | reported | reported |
| reported (an undercount — a message never read before cannot be missed after) | withheld |
| withheld — a message absent from a partial | reported |
both | withheld | withheld |
An absent field means "not computable", never "empty". Check
"snapshot": "ok" before reading disappeared as a clean bill of health.
⚠️
"ok"is necessary, not sufficient. The enumeration's range is bounded by Mail's own message count, and #155 established that count can lag the mutation. A count reading low truncates the enumeration silently — the unread tail is never requested, so it never registers as a failed slice and the status still says"ok"— and messages past that bound would then look like they disappeared. Until that is fixed, treat adisappearedentry as a lead to check, not a proof.
Privacy, and what the file costs you
Default: identifying metadata only — Message-ID, date, mailbox, account, numeric id. Enough to say which message, nothing about what it says.
Subjects are behind their own opt-in (
APPLE_MAIL_MCP_AUDIT_SUBJECTS=1) because a subject line is frequently the entire sensitive payload, and it is not needed to diagnose #155.Message bodies are never logged, under any setting.
The file grows without bound and is never rotated or truncated by this server. Point it somewhere you control, and delete it when you are done. It is written with your user's permissions, wherever you point it; there is no default location precisely so that turning it on is a deliberate act.
Writes go to that file and nowhere else. Diagnostics go to stderr; nothing is ever written to stdout, which is the JSON-RPC transport.
Usage Patterns
Basic Workflow
User: "Check my inbox for new emails"
AI: [calls list-messages]
"You have 12 messages. Here are the most recent..."
User: "Show me emails from Sarah"
AI: [calls search-messages with query="Sarah"]
"Found 3 emails from Sarah across all mailboxes..."
User: "Read the first one"
AI: [calls get-message with id="..."]
"Subject: Project Update..."Working with Accounts
By default, operations use Mail.app's configured default send account. Search operations check all accounts when no account is specified. To work with specific accounts:
User: "What email accounts do I have?"
AI: [calls list-accounts]
"You have 3 accounts: iCloud, Gmail, Work Exchange"
User: "Show unread emails in my Work account"
AI: [calls list-messages with account="Work Exchange", mailbox="INBOX"]
"Your Work account has 5 unread messages..."To pin which account is used when a tool call omits account, set the
APPLE_MAIL_MCP_DEFAULT_ACCOUNT environment variable to an account name or
email. When unset (the default), the server falls back to Mail.app's
default-send account if it is enabled, otherwise the first enabled account. A
disabled account is never selected implicitly — this env var (an explicit,
deliberate pin) is one of the few ways to target one (#47).
Sending Emails Safely
User: "Draft an email to the team about the deadline"
AI: [calls create-draft with to=["team@..."], subject="...", body="..."]
"I've created a draft. Please review it in Mail.app before sending."
User: "Send it"
AI: [User opens Mail.app and sends manually, or AI calls send-email]Sending Personalized Emails (Mail Merge)
User: "Send a personalized email to Alice (alice@acme.com), Bob (bob@globex.com),
and Carol (carol@initech.com). Subject: 'Project Update for {{Company}}',
Body: 'Hi {{Name}}, here is the latest update for {{Company}}.'"
AI: [calls send-serial-email with recipients, subject template, and body template]
"Successfully sent 3 email(s):
- alice@acme.com: sent
- bob@globex.com: sent
- carol@initech.com: sent"Organizing Messages
User: "Move all newsletters to Archive"
AI: [calls search-messages to find newsletters]
AI: [calls move-message for each, with mailbox="Archive"]
"Moved 8 newsletters to Archive"Documentation
Installation Options
npm (Recommended)
npm install -g apple-mail-mcpFrom Source
git clone https://github.com/sweetrb/apple-mail-mcp.git
cd apple-mail-mcpThe repo ships prebuilt, dependency-free build/index.js and build/cli.js bundles, so a bare clone runs with nothing but Node installed. npm install and npm run build are only needed when you change the source.
You can also install straight from GitHub with
npm install -g github:sweetrb/apple-mail-mcp, but that builds from source (requires pnpm) — prefer the registry package above.
If installed from source, use this configuration:
{
"mcpServers": {
"apple-mail": {
"command": "node",
"args": ["/path/to/apple-mail-mcp/build/index.js"]
}
}
}Running from a clone in Claude Code (project-scope .mcp.json)
This repo ships a .mcp.json at its root so that, when you run claude from inside a clone, the server is registered automatically as a project-scope server — no manual config needed. Just launch Claude Code from the repo directory and approve the server when prompted (the bundled build/index.js is committed, so no build step is required).
The entrypoint is written as:
"args": ["${CLAUDE_PROJECT_DIR:-.}/build/index.js"]CLAUDE_PROJECT_DIR is the variable Claude Code injects into a project/user-scoped server's environment, and it resolves to the repo root. You must launch claude from inside the repo for this to work — the bare . fallback is only a last resort and is not reliable, because it resolves against the launching process's working directory, not the repo.
Why not
${CLAUDE_PLUGIN_ROOT}?CLAUDE_PLUGIN_ROOTis set only for marketplace plugin installs, never for a project-scope clone, so it can't drive the clone workflow. Conversely, a plugin install can't useCLAUDE_PROJECT_DIR(in a plugin, that points at the user's project, not the plugin's own directory). Claude Code does not support nested defaults like${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}, so a single entrypoint string cannot serve both contexts. The two distribution paths are therefore decoupled: the plugin carries its own MCP config in.claude-plugin/plugin.json(using${CLAUDE_PLUGIN_ROOT}), while the root.mcp.jsonis dedicated to the clone workflow (using${CLAUDE_PROJECT_DIR:-.}). Becauseplugin.jsondeclares its ownmcpServers, the plugin does not also auto-load the root.mcp.json, so there is no double-registration.
Heads-up on scope precedence: project-scope (
.mcp.json) outranks user-scope. If you also have anapple-mailentry registered at user scope (e.g. an absolute path in~/.claude.json), the project-scope entry wins and the user-scope one is ignored entirely. Pick one — for local development on this repo, the project-scope.mcp.jsonis the intended source. To pin a specific local build instead, register it at local scope (claude mcp add apple-mail -s local -- node /abs/path/build/index.js), which outranks project scope.
Security and Privacy
No third parties - The server talks only to Mail.app on this Mac (AppleScript) and, when you configure them, directly to your own mail provider over TLS (IMAP/SMTP). Nothing is sent to this project or any other service. With the default AppleScript backend everything stays on-device; the opt-in IMAP/SMTP backends necessarily reach your provider, which is what they are for.
Permission required - macOS will prompt for automation permission on first use.
No credential storage - The server doesn't store any passwords or authentication tokens.
Email safety - Use
create-draftto review emails before sending.Attachment read boundary - Outbound file attachments may come from ordinary files under the home directory,
/Volumes, or temporary directories by default. Hidden files and known credential/configuration locations (including.ssh,.aws,.config/gh, Keychains, and applicationconfig.jsonfiles) are denied. SetAPPLE_MAIL_MCP_ATTACHMENT_READ_ROOTSto a colon-separated list of explicit absolute additional roots when a deliberate other location is required. Paths are canonicalized before use, so symlink escapes are rejected./tmpis world-writable and is a convenience root, not a user-content trust boundary. Inline base64 attachments are unaffected.
Known Limitations
Limitation | Reason |
macOS only | Apple Mail and AppleScript are macOS-specific |
MCP | The |
Attachment read path restrictions | Outbound file attachments must use full absolute paths inside the default home-directory, |
Smart mailboxes need Mail quit | Smart mailboxes are supported (see Smart Mailbox Operations), but |
Very large mailboxes not searchable via AppleScript | Apple Mail's AppleScript bridge times out on mailboxes with tens of thousands of messages, so unscoped |
Can't delete/rename server-side mailboxes or mutate drafts via AppleScript | Mail.app's AppleScript bridge can only |
Message ID format | Message IDs must be numeric (AppleScript ids) or |
Batch size cap | Batch operations are limited to 100 messages per request |
Date filter format | Date filters must be valid parseable dates (e.g., "January 1, 2026" or "2026-03-15"); bare numbers or non-date strings are rejected |
Attachment save path restrictions |
|
Attachment count limit |
|
IMAP attachment fetch size |
|
Mail.app <blockquote> wrapping on macOS 15+ (workaround in v1.6.0)
On macOS 15+ Mail.app wraps AppleScript-injected message bodies in
<blockquote type="cite"> under the Apple-Mail-URLShareWrapperClass template,
so mail sent via the default applescript transport renders to recipients as
quoted/forwarded content (Apple radar FB11734014, open since Ventura, no
fix). Since v1.6.0, send-email accepts transport: "smtp" to bypass Mail.app
and send clean MIME directly — see SMTP transport. The
AppleScript path is still the default and still exhibits Apple's wrapping.
(#12)
Reply / Forward from Background Processes (Fixed in v1.4.0)
Prior to v1.4.0, reply-to-message and forward-message would send messages with empty body text when the MCP server ran as a background process (e.g., spawned via execSync from Node.js, which is how Claude Code invokes it).
Root cause: The AppleScript reply msg with opening window command creates a GUI compose window asynchronously. When set content runs immediately after, the window may not be ready, and the content assignment is silently ignored. Delays (delay 1, delay 2) were unreliable — the compose window's readiness depends on system load, Mail.app state, and whether the process has GUI access.
Fix: Replaced with opening window with without opening window for both reply and forward commands. With this approach, set content works immediately and reliably from background processes. In-Reply-To and References headers are still set correctly by Mail.app, and no GUI compose window is opened.
Update (v2.5.0): when SMTP is configured, reply-to-message and forward-message now prefer clean direct SMTP instead of AppleScript — the same prefer-direct model as send-email. Replies are threaded with RFC 5322 In-Reply-To/References headers built from the original message; forwards start a new conversation. The AppleScript without opening window path above remains the fallback when SMTP is not configured (or, for replies, when the original message lacks the headers needed to thread).
See #7 for full details and the list of approaches that were tested.
Backslash Escaping (Important for AI Agents)
When sending content containing backslashes (\) to this MCP server, you must escape them as \\ in the JSON parameters.
Why: The MCP protocol uses JSON for parameter passing. In JSON, a single backslash is an escape character. To include a literal backslash in content, it must be escaped as \\.
Correct — email containing a shell path with an escaped space:
{
"to": ["colleague@company.com"],
"subject": "File Location",
"body": "Run: cp ~/Library/Mobile\\ Documents/report.pdf ~/Desktop/"
}→ arrives as: Run: cp ~/Library/Mobile\ Documents/report.pdf ~/Desktop/
In a JSON string literal, \\ — two characters — denotes one literal backslash. Four backslashes (\\\\) denote two literal backslashes, so send those only when the text genuinely contains \\.
Incorrect — the unescaped backslash makes this invalid JSON:
"body": "Run: cp ~/Library/Mobile\ Documents/report.pdf ~/Desktop/"\ (backslash-space) is not a valid JSON escape sequence, so the call is rejected — or, with a laxer parser, the backslash is silently dropped.
Common patterns requiring escaping:
Shell escaped spaces:
Mobile\ Documents→Mobile\\ Documentsin JSONRegex patterns:
\d+→\\d+in JSONA literal double backslash:
\\→\\\\in JSON
If you see errors when sending emails with backslashes, double-check that backslashes are properly escaped in the JSON payload.
Troubleshooting
"Mail.app not responding"
Ensure Mail.app is not frozen
Try opening Mail.app manually
Restart the MCP server
"Permission denied"
macOS needs automation permission
Go to System Settings > Privacy & Security > Automation
Ensure your terminal/Claude has permission to control Mail
"Message not found"
Message may have been deleted or moved
Message IDs change if the message is moved between mailboxes
Use
search-messagesto find the current message ID
"... is present in more than one mailbox"
A bare numeric ID identifies a message only within a mailbox, and a label store (Gmail, iCloud) reports the same message under the same ID in
INBOX,ImportantandAll Mailat once. The server refuses rather than guessing which copy you meant.Fix it by running
list-messages/search-messageson the mailbox you actually want to act on, then using the IDs from that result — the operation is then scoped to that mailbox.It only affects IDs the server hasn't seen listed (carried over from an earlier session, or typed by hand).
imap:…IDs encode their own mailbox and never hit this.
search-messages says "Partial results" or skips a mailbox
This is expected for very large IMAP/Gmail mailboxes (e.g. Gmail's
All Mail,Important): Apple Mail can't scan them via AppleScript before timing out, so they're skipped and named in the result rather than silently returning empty.To search inside one, scope the call with
mailboxand adateFrom/dateTowindow.Raise or disable the threshold with
APPLE_MAIL_MAX_SEARCH_MAILBOX(default5000;0disables the guard) — note that disabling it can make a single search take minutes.A
Partial resultswarning means coverage was incomplete; it is not a confirmed "no such mail."
"Account not found"
Account names must match exactly (case-sensitive)
Use
list-accountsto see exact account names
"Failed to send email"
Check your network connection
Verify Mail.app can send emails manually
Check if the account is configured correctly in Mail.app
"invalid outputSchema … unsupported dialect" — every tool is refused
Full text:
Tool '<name>' has an invalid outputSchema: JSON Schema declares an unsupported dialect ("$schema": "http://json-schema.org/draft-07/schema#"). The default validator supports JSON Schema 2020-12 only.The server connects, but no tool is usable.Upgrade to 2.10.12 or later. Earlier versions advertised their tool schemas in JSON Schema draft-07 (the MCP SDK's converter default); MCP has since standardized on 2020-12 and clients reject anything else. 2.10.12 normalizes every advertised
inputSchema/outputSchemato 2020-12 on the way out. See issue #147.Nothing to configure — restart your host app after upgrading so it re-reads the tool list.
apple-mail server fails to connect when run from a clone
The root
.mcp.jsonresolves its entrypoint via${CLAUDE_PROJECT_DIR:-.}/build/index.js. Launchclaudefrom inside the repo directory —CLAUDE_PROJECT_DIRonly resolves to the repo root in that case; the bare.fallback uses the launching shell's working directory and will point at the wrong place otherwise.If you've been editing the source, rerun
npm run build— the server isbuild/index.js, and the committed bundle only reflects your changes after a rebuild.Run
claude mcp listto check status. If you see a conflicting scopes warning forapple-mail, you have it registered at more than one scope; project-scope wins. See Running from a clone for how scope precedence resolves.If
claude mcp get apple-mailshows ⏸ Pending approval, approve the project-scope server (Claude Code prompts on startup, or run it again after approving).
Development
This repo is pnpm-only — package.json's preinstall guard hard-fails an npm install, because npm resolves off-lockfile and the committed bundle would then mismatch CI.
corepack enable && pnpm install --frozen-lockfile # Install dependencies
pnpm run build # Typecheck, then bundle src/index.ts + src/cli.ts into build/ (esbuild)
pnpm test # Run unit tests
pnpm run test:integration # Run integration tests (requires Mail.app)
pnpm run test:all # Run all tests (unit + integration)
pnpm run lint # Check code style
pnpm run format # Format codeAuthor
Rob Sweet - President, Superior Technologies Research
A software consulting, contracting, and development company.
Email: rob@superiortech.io
GitHub: @sweetrb
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Related Projects
Part of a family of macOS MCP servers:
apple-notes-mcp — MCP server for Apple Notes (create, search, update, and export notes)
apple-numbers-mcp — MCP server for Apple Numbers (read and write .numbers spreadsheets)
apple-photos-mcp — MCP server for Apple Photos (query metadata and export originals)
Recurring macOS permission prompts
If macOS keeps re-prompting for Full Disk Access or Automation for node (often after a brew upgrade), see docs/NODE-RUNTIME-AND-TCC-PERMISSIONS.md — the fix is to run this server under the official, Developer-ID-signed Node so the grant survives Node updates.
Available Tools
50 toolsbatch-delete-messagesA
Use when: deleting multiple messages in one call (1–100 ids; moves them to Trash). Returns: counts of how many were deleted and how many failed, plus the distinct reasons for any failures. Do not use when: deleting just one (use delete-message) or filing messages away (use batch-move-messages). Safety: destructive and applies to many messages at once — require explicit user confirmation, and search-messages/list-messages first to confirm every id is correct before deleting. Pass sourceMailbox/sourceAccount (the mailbox you listed the ids from) so each numeric id is pinned to that mailbox; an id that matches in several mailboxes is refused, not guessed.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | ||
| sourceAccount | No | Account the numeric ids were listed from. Required when sourceMailbox is supplied; on its own it pins nothing. | |
| sourceMailbox | No | Mailbox the numeric ids were listed from (e.g. 'INBOX'). Must be paired with sourceAccount to form an unambiguous scope. Ignored for imap: ids. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| errors | No | |
| failed | No | |
| mailbox | No | |
| success | No | |
| countDelta | No | |
| errorsTruncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully carries the transparency burden. It discloses that messages are moved to Trash, returns counts and failure reasons, warns it is destructive, requires explicit user confirmation, and explains the subtle id-scoping rule (ambiguous ids are 'refused, not guessed'). No contradiction with annotations since none exist.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized into clear labeled sections ('Use when', 'Do not use when', 'Safety'), each sentence earning its place. It is slightly longer than necessary—some redundancy between 'moves them to Trash' and 'destructive'—but every detail serves a purpose, making it highly scannable and dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the moderate complexity from the bulk operation, scoping rules, and failure modes, the description covers all essentials: what it does, what it returns, when not to use it, and critical safety/precondition steps. It does not explicitly state idempotency or concurrency behavior, but nothing important is missing for this tool's usage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67% (sourceAccount and sourceMailbox have descriptions, ids does not). The description adds substantial meaning to the 'ids' parameter (1–100, mailbox-scoped) and explains how sourceMailbox/sourceAccount pin ids to a mailbox and how ambiguous matches are handled, going well beyond the schema's basic field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'deleting multiple messages in one call (1–100 ids; moves them to Trash).' It uses a specific verb-resource pairing and explicitly distinguishes itself from siblings by naming 'delete-message' (single) and 'batch-move-messages' (filing), making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit 'Use when' and 'Do not use when' guidance, naming specific alternative tools (delete-message, batch-move-messages) and instructing to 'search-messages/list-messages first to confirm every id is correct before deleting.' This is model guidance for an agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
batch-flag-messagesA
Use when: flagging multiple messages (1–100 ids) in one call, optionally with a color (red/orange/yellow/green/blue/purple/gray).
Returns: counts of how many were flagged and how many failed.
Do not use when: flagging just one (use flag-message) or removing flags (use batch-unflag-messages). Get the ids from search-messages or list-messages first. Pass sourceMailbox/sourceAccount (the mailbox you listed the ids from) so each numeric id is pinned to that mailbox; an id that matches in several mailboxes is refused, not guessed.
Note: the color is applied on both routes — AppleScript sets the flag index, IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads — so a mixed batch of numeric and imap: ids all end up colored.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | ||
| color | No | Optional flag color (Apple Mail palette: red, orange, yellow, green, blue, purple, gray — 'grey' accepted). Omit for Mail's default flag. The color is applied on both routes: AppleScript sets the flag index, and IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads — so a smart mailbox keyed on flag color matches either way. | |
| sourceAccount | No | Account the numeric ids were listed from. Required when sourceMailbox is supplied; on its own it pins nothing. | |
| sourceMailbox | No | Mailbox the numeric ids were listed from (e.g. 'INBOX'). Must be paired with sourceAccount to form an unambiguous scope. Ignored for imap: ids. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| errors | No | |
| failed | No | |
| mailbox | No | |
| success | No | |
| errorsTruncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries full burden. It discloses behavior: returns success/failure counts, the dual routing (AppleScript vs IMAP) for colors, and that ambiguous ids are refused rather than guessed. These are valuable behavioral details beyond the input schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Each sentence earns its place. The text is structured into clear sections (use when, returns, do not use, note) and is front-loaded with the core purpose. No fluff or redundant content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the full workflow: when to use, prerequisites (get ids first), parameter-specific guidance (sourceAccount/sourceMailbox pairing), the return format, edge case (ambiguous ids), and implementation detail (color applied on both routes). With output schema present, return values are well-covered; this description complements it fully.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is high (75%) with descriptions for color, sourceAccount, and sourceMailbox. The description adds extra meaning by explaining why sourceMailbox/sourceAccount are needed (pinning numeric ids, ambiguity refusal) and clarifying the color behavior across both routes, surpassing the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the tool flags multiple messages (1–100 ids) in one call with an optional color. It clearly distinguishes from siblings by explicitly naming flag-message for single flags and batch-unflag-messages for removing flags.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' with named alternatives. It also instructs to get ids from search-messages or list-messages first and explains how to supply sourceMailbox/sourceAccount to disambiguate ids.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
batch-mark-as-readA
Use when: marking multiple messages (1–100 ids) as read in one call. Returns: counts of how many were marked read and how many failed. Do not use when: marking just one (use mark-as-read) or marking unread (use batch-mark-as-unread). Get the ids from search-messages or list-messages first. Pass sourceMailbox/sourceAccount (the mailbox you listed the ids from) so each numeric id is pinned to that mailbox; an id that matches in several mailboxes is refused, not guessed.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | ||
| sourceAccount | No | Account the numeric ids were listed from. Required when sourceMailbox is supplied; on its own it pins nothing. | |
| sourceMailbox | No | Mailbox the numeric ids were listed from (e.g. 'INBOX'). Must be paired with sourceAccount to form an unambiguous scope. Ignored for imap: ids. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| errors | No | |
| failed | No | |
| mailbox | No | |
| success | No | |
| errorsTruncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and discloses return values ('counts of how many were marked read and how many failed') and an important edge case ('an id that matches in several mailboxes is refused, not guessed'). It does not mention idempotency or auth, but the core behavioral traits are covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with labeled sections ('Use when', 'Returns', 'Do not use when') and a concise final instruction. Every sentence serves a purpose without unnecessary padding or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's parameter count and output schema, the description provides complete contextual guidance: usage conditions, alternatives, return counts, prerequisites, and ambiguous-id handling. It is sufficient for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema lacks a description for the 'ids' parameter and only partially covers sourceAccount/sourceMailbox. The description adds essential meaning by explaining that ids come from search-messages/list-messages and clarifying that sourceMailbox/sourceAccount is needed to pin numeric ids to a specific mailbox.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the verb and resource: 'marking multiple messages (1–100 ids) as read in one call.' It also distinguishes itself from siblings by naming 'mark-as-read' for single messages and 'batch-mark-as-unread' for unread.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description includes explicit 'Use when' and 'Do not use when' clauses with alternative tool names, and provides a clear prerequisite: 'Get the ids from search-messages or list-messages first.' It also explains the sourceMailbox/sourceAccount requirement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
batch-mark-as-unreadA
Use when: marking multiple messages (1–100 ids) as unread in one call. Returns: counts of how many were marked unread and how many failed. Do not use when: marking just one (use mark-as-unread) or marking read (use batch-mark-as-read). Get the ids from search-messages or list-messages first. Pass sourceMailbox/sourceAccount (the mailbox you listed the ids from) so each numeric id is pinned to that mailbox; an id that matches in several mailboxes is refused, not guessed.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | ||
| sourceAccount | No | Account the numeric ids were listed from. Required when sourceMailbox is supplied; on its own it pins nothing. | |
| sourceMailbox | No | Mailbox the numeric ids were listed from (e.g. 'INBOX'). Must be paired with sourceAccount to form an unambiguous scope. Ignored for imap: ids. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| errors | No | |
| failed | No | |
| mailbox | No | |
| success | No | |
| errorsTruncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description carries full responsibility. It discloses the return value ('counts of how many were marked unread and how many failed'), the failure/refusal behavior for ambiguous ids ('an id that matches in several mailboxes is refused, not guessed'), and the importance of sourceMailbox/sourceAccount for pinning ids. This goes beyond the schema and provides critical runtime behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-organized, with clear 'Use when', 'Returns', 'Do not use when', and 'Pass' sections. Every sentence adds either usage guidance, a return detail, or parameter semantics, with no filler. It is front-loaded and scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a batch tool with 3 parameters and an output schema, the description is complete. It explains when to use, what to expect in the return, how to obtain inputs, and how to disambiguate ids. It even handles edge cases like ambiguous mailboxes. The presence of an output schema reduces the need to describe return structure, but the description still provides the essential counts summary.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description coverage is 67%, but the description compensates by explaining the ids parameter's numeric/IMAP format and the purpose of sourceAccount/sourceMailbox. It clarifies that sourceAccount alone pins nothing and that sourceMailbox must be paired with it, and that imap ids ignore the mailbox scope. This adds meaningful semantic context beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb and resource: 'marking multiple messages (1–100 ids) as unread in one call.' It also distinguishes from siblings by explicitly mentioning when to use mark-as-unread for single messages and batch-mark-as-read for the read counterpart. This is a specific, unambiguous purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description begins with an explicit 'Use when' condition and provides a 'Do not use when' clause with direct references to alternative tools. It also gives a prerequisite step ('Get the ids from search-messages or list-messages first'), which is valuable guidance for correct usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
batch-move-messagesA
Use when: moving multiple messages (1–100 ids) into the same destination mailbox/folder in one call, e.g. bulk archiving. Returns: counts of how many were moved and how many failed, plus the distinct reasons for any failures. Do not use when: moving just one (use move-message) or deleting (use batch-delete-messages). Use list-mailboxes to confirm the destination name exists. Safety: moves many real messages at once — confirm the destination mailbox, and search-messages/list-messages first to confirm the ids. Pass sourceMailbox/sourceAccount (the mailbox you listed the ids from — not the destination) so each numeric id is pinned to that mailbox; an id that matches in several mailboxes is refused, not guessed.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | ||
| account | No | Account containing the destination mailbox | |
| mailbox | Yes | ||
| sourceAccount | No | Account the numeric ids were listed from. Required when sourceMailbox is supplied; on its own it pins nothing. | |
| sourceMailbox | No | Mailbox the numeric ids were listed from (e.g. 'INBOX'). Must be paired with sourceAccount to form an unambiguous scope. Ignored for imap: ids. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| errors | No | |
| failed | No | |
| mailbox | No | |
| success | No | |
| countDelta | No | |
| errorsTruncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full responsibility for behavioral disclosure. It warns that the operation moves many real messages, explains that ambiguous ids are refused rather than guessed, describes return counts and failure reasons, and explains the sourceMailbox/sourceAccount scoping semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with labeled sections (Use when, Returns, Do not use when, Safety) and every sentence adds useful information. It is longer than average but each part earns its place given the complexity and safety considerations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there are 5 parameters, no annotations, and the high-stakes mutating nature of the operation, the description provides comprehensive context: when to use, when not to use, prerequisites, return values, safety warnings, and precise parameter semantics. It is sufficient for correct tool invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers only 60% of parameters, but the description significantly compensates. It clarifies the distinction between destination mailbox and sourceMailbox, requires sourceAccount pairing, explains imap: id behavior is ignored for source scoping, and clarifies that ids must be pinned to the source mailbox.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the operation: moving multiple messages (1–100 ids) into the same destination mailbox/folder in one call. It explicitly references the tool name's scope and distinguishes it from related tools by exclusion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance, concrete when-not-to-use cases with alternative tool names (move-message, batch-delete-messages), and prerequisite advice to verify destination with list-mailboxes and confirm ids with search/list-messages.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
batch-unflag-messagesA
Use when: removing flags from multiple messages (1–100 ids) in one call. Returns: counts of how many were unflagged and how many failed. Do not use when: unflagging just one (use unflag-message) or adding flags (use batch-flag-messages). Get the ids from search-messages or list-messages first. Pass sourceMailbox/sourceAccount (the mailbox you listed the ids from) so each numeric id is pinned to that mailbox; an id that matches in several mailboxes is refused, not guessed.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | ||
| sourceAccount | No | Account the numeric ids were listed from. Required when sourceMailbox is supplied; on its own it pins nothing. | |
| sourceMailbox | No | Mailbox the numeric ids were listed from (e.g. 'INBOX'). Must be paired with sourceAccount to form an unambiguous scope. Ignored for imap: ids. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| errors | No | |
| failed | No | |
| mailbox | No | |
| success | No | |
| errorsTruncated | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries full burden. It discloses return counts (unflagged and failed), the requirement for sourceMailbox/sourceAccount to pin numeric ids, and that ambiguous ids are refused rather than guessed. This is rich behavioral context beyond what the schema provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loaded with the primary use case, and each sentence earns its place. No redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a batch mutation tool with an output schema, the description covers usage, alternatives, parameter disambiguation, and return behavior. It is sufficiently complete for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%, with sourceAccount and sourceMailbox already described. The description adds crucial semantics for these parameters (pinning, refusal behavior) and clarifies the ids use case (1-100 messages). While it doesn't detail id format, the schema's pattern handles that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the tool removes flags from multiple messages (1-100 ids) in one call, with a specific verb and resource. Explicitly distinguishes from siblings by naming unflag-message for single and batch-flag-messages for adding flags.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' guidance with alternative tool names. Also instructs to get ids from search-messages or list-messages beforehand, giving clear prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create-draftA
Use when: composing an email the user should review in Mail.app before sending — the safe default for any new message (to/cc/bcc are arrays, optional attachments). Returns: a confirmation that the draft was created, with recipients and attachment count. Do not use when: the user has already confirmed they want it sent now (use send-email). Safety: low risk — creates a draft only and sends nothing; the user must open Mail.app and send it themselves.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | CC recipients | |
| to | Yes | ||
| bcc | No | BCC recipients | |
| body | Yes | ||
| account | No | Account to create draft in | |
| subject | Yes | ||
| attachments | No | Files to attach: absolute paths in the configured attachment read roots (e.g. '/Users/me/Documents/report.pdf') and/or inline {filename, contentBase64} objects up to 25 MiB decoded each. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| recipients | No | |
| attachmentCount | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses key behavior: 'creates a draft only and sends nothing', 'the user must open Mail.app and send it themselves', and notes low risk. It also specifies the return value (confirmation with recipients and attachment count), leaving no ambiguity about side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured with labeled sections ('Use when', 'Returns', 'Do not use when', 'Safety'), front-loading the most critical information. Every sentence adds value without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the moderate schema coverage and absence of annotations, the description sufficiently covers usage, safety, and return value. It could optionally mention permission requirements or edge cases, but is complete enough for an agent to correctly invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 57%, so the description compensates by clarifying 'to/cc/bcc are arrays, optional attachments' and noting that attachments can be inline or paths. It also contextualizes parameters by stating 'safe default for any new message' and tying output to attachments count, adding meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: composing an email for user review in Mail.app before sending, distinguishing it as the safe default for new messages. It explicitly contrasts with send-email, making the resource and action unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly provides when to use ('when composing an email the user should review before sending') and when not to use ('when the user has already confirmed they want it sent now'), naming the alternative (send-email). This is exemplary guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create-mailboxA
Use when: creating a new mailbox/folder in an account. Returns: a confirmation that the mailbox was created. Do not use when: renaming an existing one (use rename-mailbox) or deleting one (use delete-mailbox). Use list-mailboxes to see what already exists. Safety: creates a real folder in the mail account — confirm the name and target account first.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| account | No | Account to create the mailbox in |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description discloses that the tool 'creates a real folder' and includes a safety warning to confirm name and target account. It also states the return value is a confirmation. This covers the key side effect, though it omits details like permissions or duplicate handling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the primary use case, followed by return info, exclusions, and a safety reminder. Every sentence is purposeful and no redundant text exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity and the presence of an output schema, the description covers creation, return value, alternatives, and safety. It could mention error cases or uniqueness requirements, but it is sufficiently complete for an agent to use it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers 'account' with a description but not 'name' (50% coverage). The description adds context by referencing 'name and target account' in the safety note and clarifying the purpose of the main parameter. It does not fully specify name constraints, but the schema's minLength provides some guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'creating a new mailbox/folder in an account.' It distinguishes from sibling tools by explicitly naming rename-mailbox and delete-mailbox as alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when:' and 'Do not use when:' guidance, naming specific alternatives (rename-mailbox, delete-mailbox) and recommending list-mailboxes to check existing mailboxes. This gives the agent clear decision criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create-newsletter-smart-mailboxesA
Use when: auto-discovering newsletter/bulk senders in your INBOX(es) and (optionally) creating a dedicated smart mailbox per sender (named "NL: "). Defaults to a safe dry run that only proposes. Returns: the proposed or created smart mailboxes with their match scores. Do not use when: you already know the exact sender (use create-smart-mailbox) or want real folders (use create-mailbox). Safety: with dryRun=false it edits Apple Mail's SyncedSmartMailboxes.plist (backed up, atomic, existing entries preserved) and can create many smart mailboxes at once — review a dryRun first. It scans up to ~400 recent messages per inbox via AppleScript, which can be slow on large mailboxes.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Look back this many days in INBOXes | |
| dryRun | No | If true (default), only propose; if false, actually create | |
| minCount | No | Minimum messages from sender in the period |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| dryRun | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully bears the behavioral disclosure burden. It reveals the default dry-run safety, the fact that dryRun=false edits Apple Mail's SyncedSmartMailboxes.plist with backup and atomicity, that existing entries are preserved, and that the scan can be slow on large mailboxes. This is exceptionally transparent for a mutation-capable tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with labeled sections (Use when, Returns, Do not use when, Safety), and every sentence provides valuable information. It is appropriately sized for a complex tool and front-loads the primary use case.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose, usage alternatives, return values, safety, side effects, and performance. Given the tool's complexity (3 parameters, no annotations, output schema present), the description is complete and self-sufficient. Output schema exists so return format details are not required in the description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds some behavioral context for dryRun (safe proposal vs. actual creation) but does not significantly expand parameter semantics beyond what the schema already documents. The 'scans up to ~400 recent messages' detail adds performance context rather than clarifying parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: auto-discovering newsletter/bulk senders in inboxes and optionally creating a dedicated smart mailbox per sender. It uses specific verbs and names the resource (INBOX(es) and smart mailboxes), and it distinguishes itself from create-smart-mailbox and create-mailbox.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly provides 'Use when' and 'Do not use when' sections, naming alternative tools (create-smart-mailbox for known senders, create-mailbox for real folders). This gives clear contextual guidance for when to select this tool vs. siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create-ruleA
Use when: creating a new Mail rule with one or more conditions (field/operator/value) and at least one action (markRead, markFlagged, delete, or moveTo). Set matchAll to require all conditions vs. any. Returns: a confirmation naming the rule and its condition count. Do not use when: toggling an existing rule (use enable-rule / disable-rule) or removing one (use delete-rule). Use list-rules to avoid duplicating an existing rule. Safety: creates a rule that automatically acts on real mail (including delete/move actions) on an ongoing basis — confirm the conditions and actions with the user before calling.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| actions | Yes | ||
| enabled | No | Enable immediately; defaults to false so the rule must be reviewed first | |
| matchAll | No | ||
| conditions | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | No | |
| created | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite no annotations, the description discloses that creating a rule has ongoing safety implications, including automatic action on real mail and the need to confirm with the user. It also mentions the default enabled state from the schema, adding behavioral context beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with 'Use when', 'Returns', 'Do not use when', and 'Safety' sections, each adding unique value. It is concise yet comprehensive, with minimal fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complex nested schema and no annotations, the description covers safety, usage boundaries, and return format, making it complete for an agent to use without additional external context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is low (20%) and the description explains key fields like matchAll, actions, and conditions, and references the enabled default. It could detail sub-fields (e.g., operators) but the core parameters are clarified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the tool creates a new Mail rule, with specifics on conditions and actions. It is clearly distinct from siblings like enable-rule and delete-rule. The purpose is explicit and actionable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' scenarios, naming alternative tools (enable-rule, disable-rule, delete-rule, list-rules). This directly guides the agent on when to invoke this tool versus siblings, which is exemplary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create-smart-mailboxA
Use when: creating an Apple Mail smart mailbox (a criteria-based virtual view) that matches a sender, subject, or body substring — works on German-localized macOS where AppleScript's smart-mailbox terms fail. Returns: confirmation of creation, or a note that a smart mailbox with that name already existed. Do not use when: creating a real folder (use create-mailbox). Safety: edits Apple Mail's SyncedSmartMailboxes.plist directly. It backs the file up (.bak) and writes atomically, and never rewrites your existing smart mailboxes. It does not quit Mail — quit Mail first for reliable results, since a running Mail may not show the new smart mailbox until relaunched and can overwrite plist edits it did not make.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| bodyContains | No | Match body (contains) | |
| fromContains | No | Match sender (From contains) | |
| subjectContains | No | Match subject (contains) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| name | No | |
| alreadyExisted | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it delivers: it discloses direct plist editing, backup creation (.bak), atomic writes, that existing smart mailboxes are not rewritten, and that Mail is not quit automatically. It also warns about Mail overwriting plist edits if running, which is valuable behavioral transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with clear labeled sections: use when, returns, do not use, and safety. It is front-loaded with the core purpose, and every sentence adds distinct, useful information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description fully covers invocation context, return behavior, exclusions, safety mechanisms, and operational prerequisites (quitting Mail). An output schema exists, so return-value detail is not required; remaining minor gaps like combined-criteria semantics do not undermine completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema describes three of four params with 'contains' phrasing (75% coverage); the description adds the concept of 'substring' and groups them as sender/subject/body criteria. This provides some semantic clarification beyond the schema, though it does not give deep per-parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Use when: creating an Apple Mail smart mailbox (a criteria-based virtual view)' and names the specific action and resource. It clearly distinguishes from 'create-mailbox' for real folders, and specifies the matching criteria (sender, subject, body substring).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description includes explicit 'Use when' and 'Do not use when' instructions, citing 'create-mailbox' as the alternative for real folders. It also adds actionable context like German-localized macOS compatibility and the instruction to quit Mail first, giving the agent clear conditions for appropriate use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete-mailboxA
Use when: deleting a mailbox/folder from an account. Returns: a confirmation that the mailbox was deleted. Do not use when: renaming it (use rename-mailbox) or deleting messages within it (use delete-message / batch-delete-messages). Safety: destructive — deleting a mailbox removes the folder and any messages it contains. Require explicit user confirmation and use list-mailboxes first to confirm the exact name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| account | No | Account containing the mailbox |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses destructive consequences, removal of contained messages, requirement for explicit user confirmation, and prerequisite to list-mailboxes first. This is highly transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loaded with use cases, and structured into clear sections (Use when, Returns, Do not use when, Safety). Every sentence adds value without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive tool with no annotations, the description covers purpose, usage boundaries, return value, safety, prerequisites, and needed confirmation. It is fully contextual.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% (account has description, name does not). The description adds some context (e.g., exact name confirmation via list-mailboxes) but does not deeply elaborate on parameters. Since coverage is moderate and some extra meaning is added, a 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool deletes a mailbox/folder, uses a specific verb+resource, and distinguishes from siblings by naming alternatives like rename-mailbox and delete-message/batch-delete-messages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly provides when to use ('deleting a mailbox/folder'), what it returns, and when not to use (renaming, deleting messages), naming specific alternative tools. This is excellent guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete-messageA
Use when: deleting a single message by id (moves it to Trash). Returns: a confirmation that the message was deleted. Do not use when: deleting several at once (use batch-delete-messages) or just filing it away (use move-message). Safety: destructive — require explicit user confirmation, and search-messages/list-messages first to confirm you have the right id before deleting.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | |
| countDelta | No | |
| verification | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it flags the destructive nature, requires explicit user confirmation, and advises confirmation of the id. It doesn't cover all edge cases (e.g., attachments), but it covers the critical safety aspects. Slightly more detail on reversibility would push it higher.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured using labeled sections (Use when, Returns, Do not use when, Safety). Every sentence adds value, with no fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter destructive action with an output schema, the description covers all necessary context: when to use, what happens, and safety checks. It also differentiates from similar tools, making it complete for agent use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is only one parameter, id. The description explicitly says 'by id' and clarifies it's a message id. The schema provides a pattern, which helps further. The description adds enough context for the agent to understand the parameter's role without redundancy.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it deletes a single message by id and moves it to Trash. It distinguishes from siblings by explicitly pointing to batch-delete-messages and move-message, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance with 'Use when' and 'Do not use when', naming alternatives (batch-delete-messages, move-message). It also recommends verifying the id first, which is actionable for agent decision-making.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete-ruleA
Use when: permanently removing a Mail rule by name. Returns: a confirmation that the rule was deleted. Do not use when: you only want to pause it (use disable-rule) or create one (use create-rule). Safety: destructive — the rule is removed permanently. Require explicit user confirmation and use list-rules first to confirm the exact name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | No | |
| deleted | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses that the rule is removed permanently, warns it is destructive, and requires explicit user confirmation plus a preliminary list-rules call. This is strong transparency, though it does not mention error handling or behavior for non-existent names. The output schema likely covers return value format.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is tightly formatted into four labeled segments (Use when, Returns, Do not use when, Safety), each earning its place. It is front-loaded with the primary use case and avoids redundant content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (one parameter, no nested objects) and has an output schema to document return values. The description covers when, when-not, prerequisites, and safety completely. No gaps are apparent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides only a 'name' field with minLength. The description clarifies that name refers to the rule name and emphasizes using list-rules to confirm the exact name, adding practical meaning. It does not discuss case sensitivity, but for a single parameter it is sufficiently helpful.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Use when: permanently removing a Mail rule by name,' which clearly specifies the verb and resource. It further differentiates from sibling tools by explicitly mentioning disable-rule and create-rule, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit use and non-use guidance, naming alternatives (disable-rule, create-rule) and recommending list-rules first to confirm the exact name. This fully addresses when to use the tool versus alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete-smart-mailboxA
Use when: deleting an Apple Mail smart mailbox (virtual view) by name. Returns: confirmation of deletion. Do not use when: deleting a real folder (use delete-mailbox) or messages (use delete-message / batch-delete-messages). Safety: destructive — removes the smart mailbox from Apple Mail's SyncedSmartMailboxes.plist. It backs the file up (.bak) and writes atomically, preserving every other smart mailbox, but the removal is not undoable in-app. Confirm the exact name with list-smart-mailboxes first, and quit Mail first for reliable results.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It clearly states the tool is destructive, modifies SyncedSmartMailboxes.plist, creates a backup, writes atomically, preserves other smart mailboxes, and that removal is not undoable in-app. This exceeds expectations for transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with clear labels (Use when, Returns, Do not use when, Safety), making it easily scannable. Every sentence provides necessary information without redundancy, and the most critical usage guidance appears first.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This destructive tool has no annotations, but the description covers prerequisites, safety, file-level behavior, and exclusions. It also names the confirmation tool and the need to quit Mail, making it complete for safe invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema description coverage is 0%, there is only one parameter ('name') whose meaning is self-evident. The description adds value by emphasizing the name must be exact and recommending list-smart-mailboxes to confirm it, which indirectly clarifies the parameter's expected value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('deleting') and resource ('Apple Mail smart mailbox (virtual view) by name'), clearly distinguishing this tool from siblings. It also explicitly names alternatives for real folders and messages, leaving no ambiguity about its scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' guidance, naming alternative tools (delete-mailbox, delete-message, batch-delete-messages). It also instructs to confirm the exact name with list-smart-mailboxes and quit Mail first, giving concrete prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete-templateA
Use when: permanently removing a saved email template by id. Returns: a confirmation that the template was deleted. Do not use when: you only want to view it (use get-template) or update it (use save-template with the existing id). Safety: destructive — removes the template from the on-disk store permanently. Require explicit user confirmation and use list-templates first to confirm the id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and excels: it states the operation is destructive, removes permanently from the on-disk store, and requires explicit user confirmation. It also discloses the return type. This is comprehensive behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, uses clear logical sections (Use when, Returns, Do not use, Safety), and every sentence adds value. No fluff, well-structured, and easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one parameter, the description covers purpose, usage, alternatives, safety, parameter guidance, and return value. The output schema exists, so the description needn't detail return structure. All essential context is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the only param is 'id' (string minLength 1). The description adds practical meaning by instructing to use list-templates first to confirm the id, giving context for how to obtain a valid value. It doesn't detail format, but the single simple parameter makes this adequate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('permanently removing a saved email template by id') and distinguishes from siblings by explicitly referencing get-template and save-template. The verb+resource combination is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' guidance, naming specific alternatives (get-template, save-template). It also advises using list-templates first to confirm the id, which is actionable and prevents misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disable-ruleA
Use when: turning off an existing Mail rule by name (without deleting it). Returns: a confirmation that the rule was disabled. Do not use when: turning a rule on (use enable-rule), creating one (use create-rule), or removing it permanently (use delete-rule). Use list-rules to confirm the exact rule name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| name | No | |
| enabled | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the action (disable), clarifies it does not delete the rule, and mentions the return value (confirmation). However, it does not cover error cases (e.g., rule not found) or idempotency, which slightly limits transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loaded with the primary use case, and every sentence adds value. It avoids fluff and provides both guidance and return information in three short sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity tool with one parameter and an output schema, the description is largely complete. It covers purpose, usage, alternatives, and return value. The only gap is lack of error-handling details, but the presence of an output schema partially mitigates this.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides a simple 'name' string with no description, and schema coverage is 0%. The description compensates by explaining that the name refers to an existing rule and advising use of list-rules to confirm the exact name, giving practical meaning to the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: turning off an existing Mail rule by name without deleting it. It explicitly distinguishes this from sibling tools like enable-rule and delete-rule, making the purpose unambiguous and easy to differentiate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' guidance, listing alternatives for related operations (enable-rule, create-rule, delete-rule) and recommending list-rules to confirm the exact name. This is exemplary usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
doctorA
Use when: troubleshooting setup problems — diagnoses Mail.app automation permissions, account state, and the IMAP/SMTP backends with actionable remediation messages. Returns: a detailed diagnostic report (formatted text plus structured checks). Do not use when: you just want a quick up/down status (use health-check) or message counts (use get-mail-stats).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| checks | No | |
| healthy | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses the diagnostic (non-mutating) nature, the specific areas checked, and the return format (formatted text plus structured checks). It does not explicitly state 'read-only' or mention potential side effects, but the diagnostic framing strongly implies a safe analysis operation, which is sufficient for a zero-parameter tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with 'Use when', and includes a return-value note and a clear 'Do not use when' with alternatives. Every sentence earns its place—no fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's low complexity (zero parameters) and the presence of an output schema, the description adequately covers the purpose, target issues, return type, and exclusions. It provides enough context for an agent to select and invoke it confidently without further detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has 0 parameters, so the schema coverage is trivially 100%. Per the calibration rule, a 0-parameter tool receives a baseline of 4, and there are no additional parameter semantics needed since no inputs exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool diagnoses Mail.app automation permissions, account state, and IMAP/SMTP backends, which is a specific verb+resource+scope. It also distinguishes itself from siblings by naming alternatives like health-check and get-mail-stats, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly provides both 'Use when' conditions (troubleshooting setup problems) and 'Do not use when' exclusions (quick up/down status, message counts), with named alternative tools (health-check, get-mail-stats). This gives clear decision guidance for when to invoke this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
enable-ruleA
Use when: turning on an existing Mail rule by name. Returns: a confirmation that the rule was enabled. Do not use when: turning a rule off (use disable-rule), creating one (use create-rule), or deleting one (use delete-rule). Use list-rules to confirm the exact rule name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| name | No | |
| enabled | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description must carry the transparency burden. It discloses that the tool turns on an existing rule and returns a confirmation. It stops short of covering idempotency (e.g., enabling an already-enabled rule) or error scenarios, but for this simple operation, the core behavior and outcome are clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, using a clear 'Use when' / 'Do not use when' structure. Every sentence earns its place: purpose, return value, exclusions, and a useful hint about list-rules.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with a single simple parameter and an output schema, the description fully covers what the tool does, when to use it, what it returns, and how to verify the parameter. Sibling references further complete the contextual picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, so the description must compensate. It explains that the 'name' parameter is the rule's exact name through 'turning on an existing Mail rule by name' and 'confirm the exact rule name.' This adds meaningful semantic detail beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'turning on an existing Mail rule by name.' This uses a specific verb (turning on) and resource (existing Mail rule), and distinguishes it from sibling tools like disable-rule, create-rule, and delete-rule.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' guidance, naming alternatives for opposite or related operations. Also advises using list-rules to verify the exact rule name, which is actionable context for correct invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch-attachmentA
Use when: retrieving an attachment's raw bytes inline as base64 (by message id and attachmentName), e.g. to process its contents without keeping a file. Returns: the attachment's bytes base64-encoded, with its size and (for IMAP) MIME type. Do not use when: you don't know the attachment name (use list-attachments first) or you just want it saved to disk (use save-attachment). Safety: leaves no file behind, but the AppleScript path is not disk-free — Mail writes the attachment into a private temp directory, which is read back and then deleted. Needs no Full Disk Access either way: Mail performs that write under the Automation grant, and this server never reads the mail store itself.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| attachmentName | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| bytes | No | |
| mimeType | No | |
| contentBase64 | No | |
| attachmentName | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full responsibility for disclosing side effects and requirements. It covers: no file left behind (but temp file used and deleted), no Full Disk Access needed, and explains the underlying AppleScript temp-directory mechanism. It also states the return format (base64 bytes with size and MIME type), giving a transparent behavioral contract.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: 'Use when', 'Returns', 'Do not use when', and 'Safety'. It is front-loaded with the primary usage, and each sentence contributes unique value — no fluff or repetition. The length is appropriate for the level of detail, covering purpose, exclusions, output, and safety in a compact manner.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity and the presence of an output schema (which handles return structure), the description goes beyond the minimum. It explains when to use, when not to use with alternatives, side effects (temp file handling), permission requirements, and return content. It effectively addresses all essential context for correct invocation, including a dependency on list-attachments for unknown names.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema coverage is 0%, but the description adds meaning by stating 'by message id and attachmentName' and clarifying that attachmentName must be known (with a suggestion to use list-attachments). It doesn't elaborate on the id pattern, but the schema already has a permissive regex. The description gives sufficient semantic context to understand what each parameter represents and how to obtain the correct value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the tool's purpose: 'retrieving an attachment's raw bytes inline as base64 (by message id and attachmentName)'. It clearly differentiates from siblings by explicitly naming alternatives: 'use save-attachment' for saving to disk and 'use list-attachments first' when the attachment name is unknown. The verb+resource+scope is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance: it starts with 'Use when:' and includes a dedicated 'Do not use when:' section that names concrete alternatives for both exclusions. This directly addresses when to use this tool versus list-attachments and save-attachment, which are the most relevant siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
flag-messageA
Use when: flagging a single message (by id), optionally with a color (red/orange/yellow/green/blue/purple/gray). Returns: a confirmation that the message was flagged (and the color, when applied). Do not use when: flagging several at once (use batch-flag-messages) or removing a flag (use unflag-message). Get the id from search-messages or list-messages first. Note: the color is applied on both routes — AppleScript sets the flag index, IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| color | No | Optional flag color (Apple Mail palette: red, orange, yellow, green, blue, purple, gray — 'grey' accepted). Omit for Mail's default flag. The color is applied on both routes: AppleScript sets the flag index, and IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads — so a smart mailbox keyed on flag color matches either way. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | |
| color | No | |
| colorApplied | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of behavioral disclosure. It discloses that the operation returns a confirmation, explains the dual route (AppleScript flag index vs IMAP $MailFlagBit keywords), and notes color behavior on both routes. This exceeds a generic mutation statement, though it does not address auth or error conditions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four focused segments (Use when, Returns, Do not use when, Note) with no filler; every sentence provides actionable information. The structure makes it easy to scan and quickly extract key facts.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple 2-parameter operation, the description covers purpose, usage boundaries, return value, and a subtle implementation detail. The presence of an output schema further reduces the need to describe return structure, making this complete for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds meaning to the 'id' parameter by directing the user to search-messages/list-messages to obtain it. The color parameter is fully described in the schema with an enum and detailed explanation of its effect. Schema coverage is 50%, so the description partially compensates for the undocumented 'id' property.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states 'flagging a single message (by id), optionally with a color', which is a specific verb+resource and immediately distinguishes from batch flagging (batch-flag-messages) and unflagging (unflag-message). The color options are enumerated, leaving no ambiguity about the tool's scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Offers explicit use-when and do-not-use-when guidance, naming batch-flag-messages and unflag-message as alternatives. It also instructs the user to obtain the id from search-messages or list-messages first, providing a clear workflow context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
forward-messageA
Use when: forwarding an existing message (by id) to new recipients (to is an array), with an optional body to prepend. Set send=false to save as a draft. Returns: a confirmation that the message was forwarded or saved as a draft. Do not use when: replying to the sender/recipients (use reply-to-message) or composing a new message (use send-email / create-draft). Safety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and any prepended body, or pass send=false to let the user review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| to | Yes | ||
| body | No | Optional message to prepend | |
| send | No | Send immediately (false = save as draft) |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | |
| sent | No | |
| recipients | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It prominently warns that default send=true sends real email immediately, cannot be unsent, and requires explicit user confirmation—or recommends send=false for review. It also states the return value, covering key side effects and safety.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with labeled sections (Use when, Do not use when, Returns, Safety). Every sentence serves a purpose, front-loaded with the primary use case, and no unnecessary verbosity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a potentially irreversible send operation, the description covers usage, alternatives, return value, safety, and key parameter semantics. The output schema exists, so return details are not burdensome. This is a complete and self-contained description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% (id and to lack descriptions), but the description compensates by clarifying 'to is an array', 'by id', and the purpose of the prepended body. It doesn't explain how to obtain id, but the schema provides a pattern and sibling tools imply the source. This adds meaningful value over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: forwarding an existing message by id to new recipients, with an optional prepended body. It also distinguishes from sibling tools like reply-to-message and send-email/create-draft, making the tool's unique purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly provides 'Use when' and 'Do not use when' sections, naming alternative tools (reply-to-message, send-email, create-draft) and specifying the condition 'forwarding an existing message'. This is exemplary usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-mail-statsA
Use when: you want aggregate mailbox statistics — total and unread message counts, recently-received counts (last 24h/7d/30d), and (for the all-accounts path) a per-account breakdown. Returns: totals, unread counts, recent-activity counts, and per-account figures. Do not use when: you only need a single unread number (use get-unread-count) or want to list the messages themselves (use list-messages / search-messages).
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Limit to one account; uses fast IMAP STATUS if that account is IMAP-configured |
Output Schema
| Name | Required | Description |
|---|---|---|
| recent | No | |
| account | No | |
| partial | No | |
| accounts | No | |
| perMailbox | No | |
| queueWaitMs | No | |
| totalUnread | No | |
| totalMessages | No | |
| failedAccounts | No | |
| recentlyReceived | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the fast IMAP STATUS optimization and the all-accounts path behavior. However, it does not explicitly state that it is read-only or has no side effects, though this is strongly implied by the purpose.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is tightly structured with 'Use when', 'Returns', and 'Do not use when' sections. Every sentence earns its place, is concise, and key information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one optional parameter, no annotations) and the presence of an output schema, the description covers the essentials: when to use, what it returns, and when not to use. No critical information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already fully describes the account parameter (100% coverage). The description adds value by clarifying the 'all-accounts path' when the parameter is omitted, which is not explicit in the schema and helps the agent correctly choose whether to pass the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: aggregate mailbox statistics including total/unread counts, recent activity counts, and per-account breakdown. It uses a specific verb and resource, and distinguishes itself from sibling tools like get-unread-count and list-messages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Do not use when' sections provide clear context and explicitly name alternative tools (get-unread-count, list-messages, search-messages). This gives the agent precise decision criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-messageA
Use when: reading the full body of one message whose id you already have (numeric or imap:…); set preferHtml to get the HTML body instead of plain text. Returns: the message subject, body (plain text by default, HTML when preferHtml is true), and its stable RFC Message-ID (rfcMessageId) for dedup/threading. Tip: pass the mailbox+account you got the id from (e.g. from search-messages) to fetch it directly — required for reliable reads of large folders like "Sent Items", which otherwise time out. Do not use when: you don't yet have an id (use search-messages or list-messages first), or you want the whole conversation (use get-thread).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| account | No | Account that holds the message. Pair with `mailbox` for a direct, scan-free fetch. | |
| mailbox | No | Mailbox that holds the message (e.g. "Sent Items"). Numeric ids are unique per mailbox; supplying this (with account) opens that mailbox directly instead of scanning every mailbox, which is required to read large folders like Sent Items without timing out. | |
| preferHtml | No | Return the HTML body (extracted from the message source) instead of plain text |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| body | No | |
| isHtml | No | |
| subject | No | |
| rfcMessageId | No | Stable RFC 5322 Message-ID (angle brackets stripped); empty when the message has none |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden and does so thoroughly. It discloses return contents (subject, body, rfcMessageId), the effect of preferHtml, and a significant behavioral trait: timeouts when scanning large folders, plus the mitigation strategy. This goes well beyond what schema or annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured into labeled sections (Use when, Returns, Tip, Do not use when). Every sentence earns its place; it is informative without being verbose. The front-loaded use case makes it easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param tool with no annotations but with output schema, the description is complete: it covers purpose, usage context, return values, failure modes, and alternatives. The tip about large folders and the rfcMessageId for dedup/threading show deep contextual understanding.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75% (3 of 4 params have descriptions). The description adds value by explaining why to pass mailbox+account ('required for reliable reads of large folders'), which goes beyond the schema descriptions. For the 'id' param, it restates the pattern (numeric or imap) but doesn't add new semantics, hence not a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'reading the full body of one message whose id you already have'. It specifies the resource (message) and the action (read/get full body), and explicitly distinguishes from siblings via 'Do not use when: you don't yet have an id (use search-messages or list-messages first), or you want the whole conversation (use get-thread)'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Excellent guidance with explicit 'Use when', 'Do not use when', and a 'Tip' section. It tells the agent exactly when to invoke this tool vs alternatives (search-messages, list-messages, get-thread), and provides a performance tip about supplying mailbox+account for large folders like 'Sent Items' to avoid timeouts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-sync-statusA
Use when: checking whether Mail.app is running and actively syncing, e.g. to explain why new mail hasn't appeared yet. Returns: whether Mail.app is running and whether sync activity was detected. Do not use when: you need message counts (use get-mail-stats) or a full setup diagnosis (use doctor).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| syncDetected | No | |
| pendingUpload | No | |
| recentActivity | No | |
| secondsSinceLastChange | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of disclosing behavioral traits. It states that the tool returns whether Mail.app is running and whether sync activity is detected, but it does not explicitly disclose whether the operation is read-only, has side effects, or could trigger a sync. This leaves safety and interference aspects unaddressed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is optimally concise with three labeled sentences: 'Use when', 'Returns', and 'Do not use when'. It is front-loaded, every sentence provides distinct value, and there is no redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple parameterless status-check tool with an output schema. The description provides sufficient context to select and invoke the tool: it states the purpose, return values, and exclusions. The existence of an output schema means detailed return format explanations are unnecessary.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema trivially covers all parameters. The baseline for 0 params is 4, and the description does not need to add parameter details since there are none.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose with a specific verb and resource: checking whether Mail.app is running and actively syncing. It explicitly lists what the tool returns, which distinguishes it from siblings like get-mail-stats and doctor.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly includes 'Use when' and 'Do not use when' sections, naming the exact conditions and pointing to specific alternative tools (get-mail-stats, doctor). This provides clear, actionable guidance for when to use this tool versus others.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-templateA
Use when: reading the full contents of one saved template by id — its name, subject, default to/cc, and body. Returns: the template's name, subject, default recipients, and body text. Do not use when: you don't have the id (use list-templates first) or want to apply the template into a draft (use use-template).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| cc | No | |
| id | No | |
| to | No | |
| body | No | |
| name | No | |
| subject | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description carries the full burden. It explicitly states this is a read operation ('reading') and enumerates the exact return fields. It does not discuss errors, permissions, or side effects, but for a simple get-by-id read, this is sufficient and adds value beyond the tool name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short, labeled sentences (Use when, Returns, Do not use when). It is front-loaded with the purpose and avoids any filler, making every sentence earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one parameter), the presence of an output schema, and rich sibling context, the description covers the essential use cases, exclusions, and return data. It is complete for an agent to select and invoke the tool correctly among many email-related siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The sole parameter id is explained as the template's identifier, and the description explicitly warns when you don't have the id. This adds meaningful context beyond the raw schema field, which only specifies a string with minLength 1.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reads a saved template by id and lists the returned contents (name, subject, default to/cc, body). It distinguishes itself from list-templates and use-template by explicitly naming them, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' guidance, including alternatives (list-templates for missing id, use-template for applying a template to a draft). This fully covers when to use the tool vs alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-threadA
Use when: you have one message id and want the whole conversation it belongs to, oldest-first. With an imap: id it threads by References/Message-ID; otherwise it groups by normalized subject. Returns: the thread's normalized subject and its messages (id, date, subject, sender, read state). Do not use when: you only need the single message (use get-message) or are searching by arbitrary criteria (use search-messages).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | A message ID in the conversation (numeric or imap:…) | |
| limit | No | Max messages in the thread (default 50) | |
| account | No | Account to search (omit to search all) | |
| mailbox | No | Mailbox to search (omit to search all) |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| partial | No | |
| subject | No | |
| messages | No | |
| failedMailboxes | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It explains the threading algorithm difference for imap: IDs vs normalized subject grouping, states the return shape, and implies a read-only operation through 'get' and 'Returns'. It does not discuss edge cases like empty threads or pagination, but the core behavior is disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-organized into usage, return, and exclusion sections. Every sentence provides actionable guidance without redundant restating of the tool name or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-oriented conversation-retrieval tool, the description covers when to use it, how it behaves with different id formats, what it returns, and which sibling tools to use instead. Combined with a 100%-covered schema and an output schema, nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter already has a clear definition. The description adds meaningful context for the id parameter by explaining how imap: IDs trigger References/Message-ID threading while other IDs use normalized subject grouping, which is valuable beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves the whole conversation for a given message id, ordered oldest-first. It explicitly contrasts with get-message and search-messages, making the tool's scope easy to distinguish from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit 'Use when' condition (have one message id, want its conversation) and an explicit 'Do not use when' condition with named alternatives (get-message for single messages, search-messages for arbitrary criteria). This leaves little ambiguity about when to select this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-unread-countA
Use when: you only need the number of unread messages — INBOX by default, or scoped to one mailbox and/or account — without listing the messages themselves.
Returns: the unread count for the requested scope (INBOX when no mailbox is given). If a source cannot be read the result carries partial: true + failedAccounts, and a total AppleScript failure returns an ERROR — a plain count is never a disguised transport failure.
Do not use when: you need the actual unread messages and their ids (use list-messages with unreadOnly, or search-messages with isRead=false) or broader totals across every mailbox (use get-mail-stats).
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Account to check | |
| mailbox | No | Mailbox to check (default: INBOX) |
Output Schema
| Name | Required | Description |
|---|---|---|
| unread | No | |
| account | No | |
| mailbox | No | |
| partial | No | |
| failedAccounts | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses behavior: it returns a count, handles partial failures with `partial: true` and `failedAccounts`, and distinguishes a total AppleScript failure returning an ERROR from a disguised transport failure. This is rich behavioral context beyond simple tool purpose.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized into three labeled sections: 'Use when', 'Returns', and 'Do not use when'. Every sentence provides useful information with no fluff or repetition, and the structure makes it easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's core purpose, edge cases (partial failures, errors), and clearly delineates when not to use it. Given that the output schema is present and the tool is simple, this description fully equips an agent to decide when and how to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (both account and mailbox have descriptions), so the baseline is 3. The description adds meaning by clarifying that the parameters can be used individually or together ('one mailbox and/or account'), which is not explicit in the schema. It also reiterates the INBOX default, reinforcing schema info but adding slight combination semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a very specific purpose: returning the number of unread messages, with INBOX as default or scoped to one mailbox and/or account. It explicitly notes what the tool does NOT do ('without listing the messages themselves'), which sharply distinguishes it from sibling tools like list-messages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' sections. It names concrete alternatives (list-messages with unreadOnly, search-messages with isRead=false, get-mail-stats) and clarifies the exact scenarios for which this tool is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
health-checkA
Use when: doing a quick check that Mail.app is reachable and the server's basic checks pass. Returns: an overall healthy/unhealthy status with a pass/fail line per check. Do not use when: you need detailed permission/account/IMAP/SMTP diagnostics with remediation steps (use doctor).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| checks | No | |
| healthy | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It does describe the return format ('overall healthy/unhealthy status with a pass/fail line per check') and implies it is non-invasive, but it does not explicitly state whether it has side effects, requires permissions, or if checks are read-only. For a health-check tool, this is adequate but leaves some ambiguity about potential network or system impacts.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short, targeted sentences: 'Use when: ...', 'Returns: ...', and 'Do not use when: ...'. Every sentence provides essential guidance with no fluff or repetition, making it highly concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no parameters and a simple health-check function, the description covers the essential context: when to use it, what it returns, and when to avoid it. The output schema likely details the checks further, so the description is complete enough for this low-complexity tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the schema is empty. The baseline for 0 parameters is 4, and the description adds context by explaining what the tool checks (Mail.app reachability and basic server checks). This is sufficient since there is no parameter detail to compensate for.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'a quick check that Mail.app is reachable and the server's basic checks pass.' It uses a specific verb ('check') and resource (Mail.app/server), and distinguishes itself from the more detailed 'doctor' tool by emphasizing 'quick check' versus 'detailed diagnostics.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use and when-not-to-use guidance is given: 'Use when: doing a quick check...' and 'Do not use when: you need detailed permission/account/IMAP/SMTP diagnostics with remediation steps (use doctor).' This clearly directs the agent to an alternative tool, satisfying the criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-accountsA
Use when: discovering the configured Mail accounts (e.g. iCloud, Gmail) so you can pass an exact account name to other tools. Returns: the account names and a count. If the AppleScript transport fails (timeout / wedged Mail / missing Automation grant) this returns an ERROR rather than an empty list — an empty list always means Mail really has no accounts. Do not use when: you want the folders within an account (use list-mailboxes) or messages (use list-messages / search-messages).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| error | No | |
| partial | No | |
| accounts | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description fully carries the burden. It discloses an important error behavior: if AppleScript transport fails, it returns an ERROR rather than an empty list, and an empty list always means truly no accounts. This goes beyond basic listing semantics and adds valuable transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four concise sentences with clear structure: Use when, Returns, error caveat, Do not use when. Every sentence contributes useful information with no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple zero-parameter tool, the description fully covers purpose, usage, error behavior, and exclusions. The output schema likely handles return structure, and the description adds the critical distinction between an error and an empty list, making it complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4 per the rubric. The description adds context about the output (account names and count) and emphasizes passing an 'exact account name' to other tools, but there is no parameter detail to add. It appropriately does not invent unnecessary info.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it lists configured Mail accounts (like iCloud, Gmail) and the purpose is to get an exact account name for other tools. It explicitly distinguishes from list-mailboxes (folders) and list-messages/search-messages (messages).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' sections, including named alternatives (list-mailboxes, list-messages, search-messages). This gives clear context for when to invoke this tool vs siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-attachmentsA
Use when: enumerating a message's attachments (by id) to discover their names, MIME types, and sizes — typically before saving or fetching one. Returns: each attachment's name, MIME type, and size, plus a count. Do not use when: you want the bytes (use fetch-attachment for inline base64, or save-attachment to write to disk). Get the message id from search-messages or list-messages first.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| attachments | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral transparency burden. It discloses the returned fields (name, MIME type, size, count) and explicitly notes it does not return bytes, which sets accurate expectations for follow-up actions. It does not cover errors or permissions, but for a read-only enumeration tool this is acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four short sentences, each with a distinct role: when to use, what it returns, when not to use, and prerequisite. It is front-loaded with the core purpose and contains no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a single parameter, an output schema, and clear usage guidance, the description covers purpose, return values, alternatives, and prerequisite in a compact form. There are no significant gaps for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the schema only provides a regex pattern, but the description clarifies that the sole 'id' parameter is the message id and tells the agent how to obtain it. The description compensates for the lack of schema-level semantic detail by tying the parameter to its real-world use.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it enumerates a message's attachments by id to discover their names, MIME types, and sizes. It distinguishes itself from sibling tools by explicitly noting that fetch-attachment and save-attachment handle byte content, while this tool does not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides explicit 'Use when' and 'Do not use when' guidance, naming fetch-attachment and save-attachment as alternatives for byte retrieval. It also instructs the agent to obtain the message id from search-messages or list-messages first, giving a clear prerequisite for correct usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-mailboxesA
Use when: discovering the mailbox/folder paths (and unread/message counts) available in an account, e.g. before moving messages or searching a specific mailbox.
Returns: each mailbox's canonical account-relative path in name, unread/message counts, and a total count. Use the full path for nested mailboxes (for example Archive/Inbox); a top-level Inbox remains Inbox. A source that could not be read is NAMED — the result carries partial: true + failedAccounts and the list is a floor, not the complete set — and a listing Mail refused outright (e.g. an account that does not exist) returns an ERROR naming the accounts that do exist, never an empty list.
Do not use when: you want the messages inside a mailbox (use list-messages or search-messages) or the list of accounts (use list-accounts).
Note: Mail's local "On My Mac" mailboxes are not part of any account, so they are reported under the synthetic account label "On My Mac" — an unscoped call includes them, and account: "On My Mac" lists only them. They will not appear in list-accounts, which reports real accounts only.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Account to list mailboxes from |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| partial | No | |
| mailboxes | No | |
| failedAccounts | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It thoroughly covers edge cases: partial results with `partial: true` and `failedAccounts`, errors for nonexistent accounts (naming existing ones, never empty), and the synthetic 'On My Mac' account. It also explains the return format (canonical paths, counts, total count). This is exemplary transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with clear sections ('Use when', 'Returns', 'Do not use when', a note). It is front-loaded with the primary purpose, each sentence provides distinct and useful information, and there is no redundancy. Although longer than typical, every part earns its place given the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for the tool's complexity. It explains return values (counts, paths), edge cases (partial results, errors), the synthetic account handling, and usage context. An output schema exists, so detailed return format isn't needed here. An agent has everything required to call this tool correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema describes `account` as 'Account to list mailboxes from' (100% coverage). The description adds meaningful nuance beyond the schema: it specifies that `account: "On My Mac"` lists only On My Mac mailboxes, and an unscoped call includes them. This is valuable parameter-specific behavior not present in the schema, bringing the score above the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: discovering mailbox/folder paths and unread/message counts in an account. It names the specific resource (mailboxes) and the operation (list), and distinguishes it from siblings like list-messages, search-messages, and list-accounts by explicitly stating what it is not for. The context 'before moving messages or searching a specific mailbox' further clarifies its role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' sections, naming alternative tools (list-messages, search-messages, list-accounts) and the conditions that select them. It also explains the 'On My Mac' special case and when an unscoped call vs. a scoped call is appropriate. This leaves nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-messagesA
Use when: browsing a mailbox's recent messages (optionally filtered by sender or unread-only) with pagination via limit/offset, and you need their ids. Returns: messages with id, date, subject, and sender (plus partial-coverage diagnostics when some mailboxes were skipped). Do not use when: you have specific search criteria like subject/date/flags (use search-messages) or already have an id and want the body (use get-message). Like search-messages, use this to obtain the ids that read/mark/delete/move and batch tools require.
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | Filter by sender email address or name | |
| limit | No | Maximum number of messages (default: 50, max: 500) | |
| offset | No | Number of messages to skip (for pagination) | |
| account | No | Account to list messages from | |
| mailbox | No | Mailbox to list messages from. Omit to list from all mailboxes. | |
| unreadOnly | No | Only show unread messages |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| partial | No | |
| messages | No | |
| failedMailboxes | No | |
| timedOutAccounts | No | |
| notSearchedMailboxes | No | |
| skippedLargeMailboxes | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden. It explains that the tool returns message IDs plus selected fields and partial-coverage diagnostics when mailboxes are skipped. It does not explicitly state that the operation is read-only or describe ordering guarantees, but 'browsing' strongly implies a safe read operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear 'Use when', 'Returns', and 'Do not use when' sections. Every sentence serves a purpose, and the most important usage guidance is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a list tool with six parameters, an output schema, and many sibling tools, this description is complete. It covers purpose, exclusions, return shape, diagnostics, and downstream use cases without relying on the agent to infer anything critical.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents all six parameters with 100% coverage, so the description does not need to explain each one. It does add useful context by grouping parameters around sender filtering, unread-only filtering, and limit/offset pagination, but that is only marginal added meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action and resource: listing recent messages from a mailbox and retrieving their IDs. It clearly distinguishes itself from search-messages and get-message rather than merely restating the tool name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use the tool ('browsing a mailbox's recent messages... and you need their ids') and when not to use it, naming search-messages for specific criteria and get-message for retrieving a body. It also connects to batch/read/mark/delete/move tools, giving the agent strong routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-rulesA
Use when: discovering the Mail rules that exist and whether each is enabled or disabled, e.g. before enabling/disabling/deleting one. Returns: each rule's name and enabled/disabled state. Do not use when: you want to change a rule (use enable-rule / disable-rule / create-rule / delete-rule).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| rules | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It clearly states the return content ('each rule's name and enabled/disabled state') and implies a read-only operation through the 'Use when' vs 'Do not use when' distinction. However, it does not explicitly declare that the operation has no side effects, nor mention auth or error behavior, which is a minor gap for a tool with no annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short, clearly structured sentences with helpful labels ('Use when', 'Returns', 'Do not use when'). Every sentence adds value and there is no redundant information, making it highly concise and well front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-annotation, simple listing tool, the description fully covers when to use it, what it returns, and when not to use it. The existence of an output schema further reduces the burden, so the description is complete for its context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema documents 100% of them vacuously. Per guidelines, 0 params gives a baseline of 4. The description adds useful context about the output, but there are no parameter semantics to explain, so the baseline is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('discovering' / 'list') with a clear resource ('Mail rules') and scope ('whether each is enabled or disabled'). It distinguishes from sibling tools by explicitly naming enable-rule, disable-rule, create-rule, and delete-rule as alternatives for changes, so the purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states 'Use when: discovering the Mail rules...' and 'Do not use when: you want to change a rule (use enable-rule / disable-rule / create-rule / delete-rule)', giving clear context and naming alternative tools. This is exactly the level of guidance expected.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-smart-mailboxesA
Use when: listing Apple Mail smart mailboxes (criteria-based virtual views), including on German-localized macOS where AppleScript's smart-mailbox terms do not compile. Returns: each smart mailbox's name and a short criteria summary. Do not use when: listing real folders/mailboxes (use list-mailboxes).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| smartMailboxes | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral transparency burden. It discloses a notable edge case (German-localized macOS where AppleScript terms don't compile) and mentions the return content ('name and a short criteria summary'). While it doesn't explicitly state non-destructive intent, 'listing' implies read-only, and the edge case adds valuable behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise, with two clear sections ('Use when' and 'Returns') and a 'Do not use when' clause. Every sentence serves a purpose, and the most critical usage direction is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter list tool with an output schema, the description covers purpose, usage boundary, an important localization nuance, and return value summary. It is fully sufficient for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline for this dimension is 4 as per the rubric. The description doesn't need to add parameter semantics, and it correctly stays silent on parameters. The mention of 'criteria summary' is about the return value, not an input.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description specifies the exact action ('listing Apple Mail smart mailboxes') and clearly distinguishes it from the sibling tool by stating 'Do not use when: listing real folders/mailboxes (use list-mailboxes)'. This makes the purpose unambiguous and differentiates it from closely related tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' instructions, naming the alternative tool (list-mailboxes). This meets the highest standard for usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-templatesA
Use when: discovering the saved email templates and their ids, e.g. before using or editing one. Returns: each template's id, name, and subject. Do not use when: you want a single template's full body (use get-template) or want to apply one (use use-template).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| templates | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of behavioral disclosure. It discloses that the tool returns only id, name, and subject (not full body), and implies a read-only, non-mutating operation. It could add more context about potential errors or permission requirements, but for a simple list operation with zero parameters, the disclosure is reasonably complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise, using three short sentences that are front-loaded with the primary use case, followed by return details and exclusions. Every sentence earns its place with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (0 parameters) and has an output schema, so the description need not explain return values in depth. It fully covers when to use, what it returns, and when not to use, making it contextually complete for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description appropriately focuses on output and usage rather than parameter details, adding no unnecessary parameter-related text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool 'lists' saved email templates and their ids, with a specific verb and resource. It further distinguishes itself from siblings by explicitly stating it returns 'each template's id, name, and subject' and contrasts with get-template and use-template.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' guidance, naming alternative tools (get-template, use-template) for different use cases. This makes it very clear when to select this tool versus its siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mark-as-readA
Use when: marking a single message (by id) as read. Returns: a confirmation that the message was marked read. Do not use when: marking several at once (use batch-mark-as-read) or marking unread (use mark-as-unread). Get the id from search-messages or list-messages first.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It states the action (mark as read) and the return behavior (confirmation). This is adequate for a simple mutation tool, though it doesn't disclose behavior for invalid ids or other edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with 'Use when' and 'Returns'. Every sentence adds value with no redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with an output schema, the description covers purpose, usage, alternatives, and id sourcing, making it complete for an agent to select and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description adds meaning by explaining the id is a message id and where to obtain it ('from search-messages or list-messages first'). The schema's pattern provides format constraints, but the description provides practical usage semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: marking a single message by id as read. It distinguishes from siblings by explicitly naming batch-mark-as-read and mark-as-unread.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use ('Use when: marking a single message') and when-not-to-use ('Do not use when: marking several at once... or marking unread'), with named alternatives. It also instructs to get the id from search-messages or list-messages first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mark-as-unreadA
Use when: marking a single message (by id) as unread. Returns: a confirmation that the message was marked unread. Do not use when: marking several at once (use batch-mark-as-unread) or marking read (use mark-as-read). Get the id from search-messages or list-messages first.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It discloses the return value (a confirmation) and implies the mutation by stating the tool marks a message unread. However, it does not explicitly state permission requirements or reversibility, though these are less critical for this action.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-organized: starts with use case, then returns, then exclusions and prerequisites. Every sentence adds value, and it front-loads the most critical information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with an output schema, the description covers the core action, exclusions, return value, and id source. It is complete for the tool's complexity and leaves no significant gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains the id parameter's role ('by id') and tells the user where to obtain it, adding context beyond the bare schema pattern.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses specific verb+resource: 'marking a single message (by id) as unread'. It clearly distinguishes from sibling tools like mark-as-read and batch-mark-as-unread by explicitly naming them in the 'Do not use when' clause.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use, do-not-use scenarios with named alternative tools (batch-mark-as-unread, mark-as-read), and even notes the prerequisite to get the id from search-messages or list-messages first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
move-messageA
Use when: moving a single message (by id) into another mailbox/folder, e.g. archiving or filing. Returns: a confirmation naming the destination mailbox. Do not use when: moving several at once (use batch-move-messages) or deleting (use delete-message). Use list-mailboxes to confirm the destination name exists. Safety: moves a real message between folders — confirm the destination mailbox, and search-messages/list-messages first to confirm the id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| account | No | Account containing the destination mailbox | |
| mailbox | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | |
| mailbox | No | |
| countDelta | No | |
| verification | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the burden. It clearly discloses that the tool 'moves a real message between folders' and includes a safety warning. It also states the return value (a confirmation naming the destination mailbox). While it doesn't detail potential failure modes or permission requirements, it provides adequate transparency for a simple mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place. The description uses a clear 'Use when'/'Do not use when' structure, includes a return note, and ends with a safety caveat. It is concise (about 3 sentences) and front-loaded with the most critical information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simplicity of the tool (3 params, no nested objects) and the presence of an output schema, the description covers the essential aspects: when to use, alternatives, safety, and return value. It could mention error conditions or edge cases (e.g., what happens if the mailbox doesn't exist), but it preemptively advises to confirm the mailbox. This is complete enough for typical use, though not exhaustive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 33% (only 'account' has a description). The tool description clarifies that 'id' refers to the message id and 'mailbox' to the destination folder, adding meaning beyond the schema. However, 'account' is left to the schema's description, and no additional context is given for the id pattern or mailbox naming conventions. The description partially compensates for the low coverage but does not fully explain all parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'moving a single message (by id) into another mailbox/folder' with examples (archiving, filing). It distinguishes itself from batch-move-messages and delete-message, making the tool's unique scope explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Extremely explicit usage guidance: includes 'Use when' and 'Do not use when' with specific alternatives (batch-move-messages, delete-message). Also advises using list-mailboxes to verify destination and search-messages/list-messages to confirm id, providing a clear decision framework.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rename-mailboxA
Use when: renaming an existing mailbox/folder from oldName to newName within an account. Returns: a confirmation naming the old and new mailbox names. Do not use when: creating a new folder (use create-mailbox) or deleting one (use delete-mailbox). Use list-mailboxes to confirm the current name. Safety: renames a real folder in the mail account — confirm oldName matches exactly (case-sensitive) before calling.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Account containing the mailbox | |
| newName | Yes | ||
| oldName | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| newName | No | |
| oldName | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full transparency burden. It warns that the tool 'renames a real folder in the mail account' and stresses case-sensitivity and confirming oldName matches exactly. It also mentions the return value (a confirmation). However, it doesn't disclose potential side effects like whether existing links break or if the operation is reversible, which prevents a higher score.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured with labeled sections: 'Use when', 'Returns', 'Do not use when', and 'Safety'. Each sentence serves a purpose without redundancy, front-loading the primary action.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 3-parameter tool, the description covers purpose, usage boundaries, safety, and return value. It lacks details on error handling or edge cases (e.g., if the mailbox doesn't exist), but given the output schema exists and the operation is straightforward, it is fairly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 33%, so the description must compensate. It explains oldName and newName contextually (renaming from old to new) and notes case-sensitivity, adding value beyond the schema. However, it doesn't clarify the 'account' parameter's role or whether it's required, and it doesn't elaborate on format or constraints. Partial compensation but not thorough.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'renaming an existing mailbox/folder from oldName to newName within an account.' It uses a specific verb (rename) and resource (mailbox/folder), and distinguishes from create-mailbox and delete-mailbox by explicitly naming those alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use and when-not-to-use guidance: 'Use when: renaming...' and 'Do not use when: creating a new folder (use create-mailbox) or deleting one (use delete-mailbox).' It also recommends verifying the current name with list-mailboxes, which is practical context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reply-to-messageA
Use when: replying to an existing message by id, preserving its threading headers. Set replyAll for all recipients; set send=false to save as a draft instead of sending. Returns: a confirmation that the reply was sent or saved as a draft. Do not use when: composing a brand-new message (use send-email / create-draft) or forwarding to new recipients (use forward-message). Safety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and body, or pass send=false to let the user review.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| body | Yes | ||
| send | No | Send immediately (false = save as draft) | |
| replyAll | No | Reply to all recipients |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | |
| sent | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral disclosure. It warns that send=true sends real email immediately and cannot be unsent, requires explicit user confirmation, and mentions threading headers and draft behavior. This is exceptionally transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with labeled sections: 'Use when', 'Returns', 'Do not use when', and 'Safety'. It is concise yet information-dense, with every sentence contributing actionable guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for a tool of this complexity. It covers when to use, alternatives, return value, safety concerns, and parameter behavior, leaving no significant gaps even in the absence of annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50%, and the description compensates by explaining id as the existing message to reply to, replyAll as replying to all recipients, and send=false as saving a draft. It adds meaning to the parameters beyond the schema, though body semantics are only implicitly covered through the safety note.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: replying to an existing message by id while preserving threading headers. It distinguishes from siblings by explicitly naming send-email/create-draft for new messages and forward-message for forwarding.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' guidance with named alternative tools. Also explains when to set replyAll and send=false, giving clear decision criteria for usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve-message-idA
Use when: you have imap: message id(s) and genuinely need the numeric Mail.app id(s) — e.g. for reply-to-message/forward-message, which are numeric-id only. NOTE: as of 2.10.0 you no longer need this to apply a flag COLOR — flag-message/batch-flag-messages write the color over IMAP directly via Mail.app's $MailFlagBit0/1/2 keywords, so a smart mailbox keyed on flag color matches an IMAP-flagged message. Each imap: id is resolved via its RFC822 Message-ID.
Returns: for each input id, its numericId (the AppleScript id) or null when it can't be resolved, plus the messageId used; and a resolvedCount.
Do not use when: your ids are already numeric (they pass straight through), or you don't need a color — flag/move/mark tools operate on imap: ids directly.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| resolved | No | |
| resolvedCount | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full transparency burden. It explains how resolution works (via RFC822 Message-ID), what each input yields (numericId or null, plus messageId and resolvedCount), and includes a version note about flag coloring behavior. It stops short of explicitly stating non-destructiveness or edge-case behavior, but the disclosed behavior is substantive and above average.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with 'Use when', 'Returns', and 'Do not use when' sections, and it leads with the main use case. It is slightly verbose due to the version note, but every sentence adds information and the structure akes it easy to scan. A more compact phrasing might be possible, but the length is justified.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given this is a simple one-parameter tool with an output schema, the description fully covers when to use it, how it behaves, what it returns, and how it differs from alternative tools. The version note adds important contextual information. No critical gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must explain the parameter. It clarifies the `ids` format (either numeric or `imap:` prefixed) and what happens to each form (numeric pass through, `imap:` resolved). This goes well beyond the raw JSON schema pattern and provides essential semantic context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that this tool resolves `imap:` message IDs into numeric Mail.app IDs, specifically needed for reply-to-message/forward-message. It distinguishes itself from sibling tools by noting that flag/move/mark tools work directly with `imap:` IDs, making this tool's unique purpose explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' guidance, including concrete examples (reply-to-message/forward-message) and exclusions (numeric IDs already pass through, flag/move/mark operate directly). It also notes a version-specific change (2.10.0) that affects when this tool is needed for flag colors, showing strong awareness of alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save-attachmentA
Use when: writing one of a message's attachments to disk, by message id and attachmentName, into the savePath directory (saved as savePath/attachmentName). Returns: a confirmation of the saved file path. Do not use when: you don't know the attachment name (use list-attachments first) or want the bytes inline rather than on disk (use fetch-attachment). Safety: writes a file to disk — savePath must be a directory inside the configured allowed roots, and attachmentName may not contain path separators or '..'; calls outside those constraints are rejected.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| savePath | Yes | ||
| attachmentName | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| savedPath | No | |
| attachmentName | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description transparently discloses that the tool writes a file to disk (destructive side effect), enforces path safety constraints on savePath and attachmentName, and returns a confirmation of the saved path. It does not mention overwrite behavior or permissions, but the disclosed constraints substantially cover the behavioral profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is tightly organized into labeled sections (Use when, Returns, Do not use when, Safety). Each sentence delivers distinct information without redundancy, and the structure front-loads the primary use case.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity and the presence of an output schema, the description covers purpose, usage guidelines, return behavior, and safety constraints. Minor gaps such as overwrite semantics prevent a perfect score, but the description is highly usable for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides no property descriptions (0% coverage). The description compensates by defining all three parameters: id as message id, attachmentName as the attachment name, savePath as the destination directory, and the resulting file path as savePath/attachmentName. It also adds validation rules for attachmentName.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the tool's action: writing a message attachment to disk using message id and attachmentName into savePath. It names the exact output file path format and distinguishes from sibling tools by mentioning fetch-attachment for inline bytes and list-attachments for unknown names.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Use when' and 'Do not use when' guidance, naming alternatives (list-attachments, fetch-attachment). This clearly instructs the agent on appropriate conditions and exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save-templateA
Use when: creating a reusable email template (name, subject, body, optional default to/cc), or updating one by passing its existing id. Subject/body may contain placeholders for later use. Returns: the saved template's name and id (reuse the id with use-template / get-template / delete-template). Do not use when: composing a one-off message (use create-draft / send-email) or filling in a template to send (use use-template). Safety: writes the template to the on-disk templates store (APPLE_MAIL_MCP_TEMPLATES_FILE) and persists across restarts; passing an existing id overwrites that template.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | Default CC recipients | |
| id | No | Template ID (for updating existing template) | |
| to | No | Default recipients | |
| body | Yes | ||
| name | Yes | ||
| subject | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No | |
| name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the burden. It discloses that templates are written to an on-disk store, persist across restarts, and that passing an existing id overwrites. It also mentions the return value (name and id). This is strong coverage, though it doesn't address permissions or error conditions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a structured paragraph with labeled sections (Use when, Returns, Do not use when, Safety). Every sentence adds value, though it is slightly verbose. It remains efficient and scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers creation, update, return values, persistence/overwrite behavior, and exclusions. With an output schema noted, it fully equips an agent to call the tool correctly. No critical gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 50%, but the description compensates by explaining the role of core parameters: name, subject, body, optional to/cc, and id for updating. It clarifies that id distinguishes update from creation, which the schema alone does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates or updates reusable email templates, naming the key fields (name, subject, body, to/cc). It also distinguishes itself from siblings by mentioning updating via id and explicitly contrasting with use-template, create-draft, and send-email.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' sections, naming alternative tools (create-draft, send-email, use-template) for other scenarios. This leaves no ambiguity about when to select this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search-contactsA
Use when: looking up a person in Contacts by name, organization, nickname, or email to find their email address(es)/phone(s) before composing or sending mail. Reads the macOS Contacts database directly (needs Full Disk Access; does NOT require Contacts.app to be running or an Automation / Apple-Events grant). Returns: matching contacts with their names, email addresses, and phone numbers. Do not use when: searching email messages (use search-messages) — this queries Contacts, not the mailbox.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| contacts | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden and does well by disclosing that it reads the macOS Contacts database directly, requires Full Disk Access, and does not require Contacts.app or Apple-Events grant. It also states return fields. Minor gaps: doesn't mention whether it is read-only explicitly or handle errors, but overall clearly describes behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with clear 'Use when', 'Reads...', 'Returns...', and 'Do not use when' segments. Every sentence adds valuable information, no fluff, and it is appropriately sized for the tool's simplicity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple search tool with one parameter and an output schema, the description covers all essential aspects: use case, when not to use, access method, prerequisites, and return values. There is no ambiguity about the tool's function or limitations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter 'query' is given meaning by the description: it can be a name, organization, nickname, or email. This goes beyond the schema's generic 'string' definition and fully compensates for the 0% schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States clearly what it does: looking up a person in Contacts by name, organization, nickname, or email to find email addresses and phone numbers. It uses a specific verb ('search') and resource ('Contacts'), and explicitly distinguishes from sibling tool search-messages by saying 'Do not use when: searching email messages...'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Do not use when' sections provide clear guidance on when to choose this tool over alternatives, including naming the alternative (search-messages). It also gives prerequisites (Full Disk Access, no need for Contacts.app running), which helps agent decide when this tool is viable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search-messagesA
Use when: finding messages by query/sender/subject/date/read/flag filters and you need their ids for follow-up operations. Returns: matching messages with id, date, subject, sender, and read state (plus partial-coverage diagnostics when some mailboxes were skipped). Do not use when: you want a plain mailbox listing without filters (use list-messages), already have an id and want the body (use get-message), or want a whole conversation (use get-thread). Prefer this first to obtain the message ids that get-message/mark-as-read/delete-message/move-message and the batch tools require.
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | Filter by sender (substring match against the full sender string, i.e. display name + address — not an exact address match) | |
| limit | No | Maximum number of results (default: 50, max: 500) | |
| query | No | Text to search for in subject, sender, or content | |
| dateTo | No | End date filter (e.g., 'March 1, 2026') | |
| isRead | No | Filter by read status | |
| account | No | Account to search in (omit to search all accounts) | |
| mailbox | No | Mailbox to search in (e.g., 'INBOX'). Omit to search all mailboxes. | |
| subject | No | Filter by subject line (substring match) | |
| dateFrom | No | Start date filter (e.g., 'January 1, 2026') | |
| isFlagged | No | Filter by flagged status |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| partial | No | |
| messages | No | |
| failedMailboxes | No | |
| timedOutAccounts | No | |
| notSearchedMailboxes | No | |
| skippedLargeMailboxes | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations, so the description carries the full burden for behavioral disclosure. It does disclose return contents and partial-coverage diagnostics, but it does not explicitly state that the operation is read-only or describe any side effects, permissions, or failure behavior. For a search operation the lack of side-effect warnings is less critical, but without annotations the description could still be more explicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is tightly structured with labeled sections: use when, returns, do not use when, and preference guidance. Every sentence serves a functional purpose, and the most actionable guidance is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers what results look like, including diagnostic caveats, explicitly routes the agent away from inappropriate uses, and points to the dependent operations. With an output schema present and all parameters fully documented, nothing essential is missing for an agent to invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 10 parameters. The description adds a high-level summary of filter categories but no additional semantic detail beyond what the schema provides, so a baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('finding messages by query/sender/subject/date/read/flag filters') and clearly identifies the resource and the follow-up purpose (obtaining ids). It differentiates itself from list-messages, get-message, and get-thread, so an agent can tell it apart from its siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Do not use when' sections name the alternative tools (list-messages, get-message, get-thread) and the conditions that make them preferable. It also instructs the agent to prefer this tool first to obtain ids required by other operations, leaving no ambiguity about when to select it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send-emailA
Use when: the user has explicitly confirmed they want to send a single email now to the given recipients (to/cc/bcc are arrays), optionally with attachments and a chosen transport. Returns: a confirmation naming the recipients and attachment count. Do not use when: the user wants to review first (use create-draft), is replying to or forwarding an existing message (use reply-to-message / forward-message), or wants per-recipient personalized copies (use send-serial-email). Safety: this SENDS real email immediately and it cannot be unsent — require explicit user confirmation of the exact recipients, subject, and body before calling. Prefer create-draft when there is any doubt.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | CC recipients | |
| to | Yes | ||
| bcc | No | BCC recipients | |
| body | Yes | ||
| account | No | Account to send from | |
| subject | Yes | ||
| transport | No | Send transport. 'smtp' submits clean MIME directly via SMTP, avoiding the macOS 15+ Mail.app <blockquote> wrapping (issue #12); requires APPLE_MAIL_MCP_SMTP_* env config. 'applescript' sends through Mail.app. If omitted, SMTP is used automatically when APPLE_MAIL_MCP_SMTP_* is configured, otherwise AppleScript. | |
| attachments | No | Files to attach: absolute paths in the configured attachment read roots (e.g. '/Users/me/Documents/report.pdf') and/or inline {filename, contentBase64} objects up to 25 MiB decoded each. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| transport | No | |
| recipients | No | |
| attachmentCount | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses that the tool 'SENDS real email immediately and it cannot be unsent', requiring explicit user confirmation. It also mentions the default transport selection logic, which is critical operational context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured into clear sections (Use when, Returns, Do not use when, Safety) and every sentence provides value—alternatives, safety, and return information. It is detailed yet economical, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 8 parameters and significant side effects, the description covers all essential context: when to use, alternatives, safety, and return info. It is complete for an agent to make correct invocation decisions, especially given the presence of an output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 63%, and the description adds little beyond the schema—it reiterates that recipients are arrays and mentions attachments, but these are already in the schema. The transport default is also already described in the schema, so the description does not significantly enhance parameter understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the specific action: 'send a single email now to the given recipients' with optional attachments and transport. It clearly distinguishes from siblings like create-draft, reply-to-message, and send-serial-email by explicitly naming them as alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' conditions, including specific alternatives for review (create-draft), replying (reply-to-message), and personalized copies (send-serial-email). This leaves no ambiguity about when to invoke the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send-serial-emailA
Use when: the user has confirmed a mail-merge — sending individually personalized copies to many recipients (max 100), with {{Key}} placeholders in subject/body replaced per-recipient from each recipient's variables. Recipients do not see each other. Returns: a per-recipient sent/failed report with counts. Do not use when: sending one message to a shared recipient list (use send-email) or saving for review (use create-draft). Safety: this SENDS many real emails immediately and they cannot be unsent — require explicit user confirmation of the recipient list, the subject/body template, and the placeholder substitutions before calling.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Email body — use {{Key}} for placeholders | |
| account | No | Account to send from | |
| delayMs | No | Delay between sends in ms (default: 500, max: 10000) | |
| subject | Yes | Subject line — use {{Key}} for placeholders | |
| recipients | Yes | List of recipients with personalization variables (max 100) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | |
| sent | No | |
| failed | No | |
| results | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It discloses that emails are sent immediately, cannot be unsent, require explicit user confirmation, and that recipients do not see each other. It also states the return value (per-recipient report), exceeding what annotations would provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short, front-loaded sentences organized logically (Use when, Returns, Do not use, Safety). Every sentence adds critical information with no waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema and 100% parameter coverage, the description covers selection, exclusions, safety, and return behavior. It is fully sufficient for an agent to decide when and how to invoke this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters are already well-documented. The description adds context about placeholder replacement and per-recipient variables, but does not deeply elaborate on each parameter beyond what the schema already says. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('sending individually personalized copies') and clearly identifies the resource (mail-merge to many recipients with placeholder substitution). It also distinguishes itself from siblings by naming send-email and create-draft as alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides explicit when-to-use conditions ('user has confirmed a mail-merge', max 100 recipients) and explicit when-not-to-use with named alternatives ('use send-email', 'use create-draft'). This is clear, actionable guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unflag-messageA
Use when: removing the flag from a single message (by id). Returns: a confirmation that the message was unflagged. Do not use when: unflagging several at once (use batch-unflag-messages) or adding a flag (use flag-message). Get the id from search-messages or list-messages first.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description mentions that the tool returns a confirmation, which adds some behavioral context. However, with no annotations present, it does not disclose what happens when the message is already unflagged, whether the operation is idempotent, or any error conditions. This leaves some ambiguity for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (three sentences) and front-loaded with the primary usage condition. Every sentence adds value: use case, return value, exclusions, and id sourcing. No redundant or filler content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with an output schema, the description covers all essential guidance: when to use, when not to use, how to obtain the parameter, and what to expect as a return value. It is fully sufficient for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It explains the single parameter 'id' by saying 'by id' and instructs the user to get the id from search-messages or list-messages first. This provides practical guidance beyond the raw schema pattern and helps the agent understand the param's provenance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb ('removing'), the resource ('flag from a single message'), and the scope ('by id'). It also differentiates from sibling tools by specifying 'single' versus batch operations and removal versus adding a flag.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Use when' and 'Do not use when' sections directly state the appropriate usage and name alternatives (batch-unflag-messages, flag-message). Additionally, it tells the user to obtain the id via search-messages or list-messages first, providing clear operational context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
use-templateA
Use when: composing a new draft from a saved template (by id), optionally overriding the recipients, subject, or body. Creates a draft in Mail.app for the user to review and send. Returns: a confirmation that a draft was created from the template. Do not use when: you want to inspect the template without composing (use get-template) or send immediately without a draft (use send-email).
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | Override CC recipients | |
| id | Yes | ||
| to | No | Override recipients | |
| body | No | Override body | |
| subject | No | Override subject |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | |
| ok | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of disclosing behavior. It states that the tool creates a draft in Mail.app for review/send, not an immediate send, and returns a confirmation. It does not mention potential side effects on the template, but the core behavior is well disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with a direct 'Use when' statement. Every sentence adds value, clearly stating purpose, return value, and exclusions without unnecessary detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 5 params and an output schema, the description covers the essential use case, return value, and alternatives. It is sufficiently complete given the simplicity of the operation and the presence of an output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 80%, so baseline is 3. The description adds meaning by explaining the id is a template id and that recipients/subject/body are optional overrides. This clarifies the workflow beyond the schema, especially for the undocumented id parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool composes a new draft from a saved template by id, with optional overrides for recipients, subject, or body. It explicitly distinguishes itself from get-template and send-email, naming these sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use when' and 'Do not use when' guidance with named alternatives (get-template, send-email). This makes the appropriate context and exclusions unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Every tool has a clearly distinct purpose, with explicit 'Do not use when' guidance preventing overlap. Single and batch variants are cleanly separated, and even the diagnostics tools (health-check, doctor, get-mail-stats, get-unread-count, get-sync-status) are precisely scoped.
The vast majority follow a consistent snake_case verb_noun pattern (move-message, list-mailboxes, create-rule), with a uniform 'batch-' prefix for multi-item operations. However, 'doctor' and 'health-check' break the verb-first convention, though they remain semantically clear.
At 50 tools, the surface is far beyond the typical well-scoped server. While the breadth covers many email subdomains, the sheer number—including 6 batch variants—makes the set feel heavy and harder to navigate.
The set covers the full lifecycle of messages, attachments, mailboxes, smart mailboxes, rules, templates, contacts, and diagnostics. A notable gap is the absence of a 'send-draft' tool, so drafts created via create-draft/use-template cannot be sent programmatically without re-specifying content.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Email inboxes for AI agents: send, receive, reply, search, and manage threaded email over MCP.
A MCP server for Gmail that lets you search, read, and draft emails and replies.
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that enables AI models to read, search, and send emails via IMAP and SMTP protocols. It supports various providers like Gmail and Outlook, allowing for tasks such as retrieving unread messages, searching by sender, and managing mailbox folders.
- AlicenseAqualityAmaintenanceAn MCP server for Apple Mail that enables Claude to read, search, manage, and compose emails via AppleScript.203001MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that gives AI assistants comprehensive access to Apple Mail accounts, enabling email discovery, reading, flag management, and server-side message retrieval.MIT
- AlicenseAqualityAmaintenanceAn MCP server that provides programmatic access to Apple Mail, enabling AI assistants like Claude to read, send, search, and manage emails on macOS.25MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sweetrb/apple-mail-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server