paulo-amaral

applemail-mcp-server

Community paulo-amaral
Updated

Local MCP server giving Claude read access to macOS Mail.app, plus optional opt-in writes to Apple Calendar — via JXA, no OAuth, no API keys, nothing leaves your machine.

applemail-mcp-server

A local MCP server that gives Claude access to macOS Mail.app through JXA (JavaScript forAutomation). Every account already configured in Mail — iCloud, Gmail, Outlook/Exchange, IMAP —becomes visible, with no OAuth, no API keys, and no data leaving the machine.

Read-only by default. There is no send tool, by design.

Tools

Tool Writes? What it does
apple_mail_list_accounts no Account names, types, addresses. Start here.
apple_mail_list_mailboxes no Mailboxes + unread counts (names are case-sensitive and localised).
apple_mail_unread_summary no Unread counts per account/mailbox. Reads counters only — fast on huge mailboxes.
apple_mail_search_messages no Header search with filters; returns opaque per-message handles.
apple_mail_get_message no Full headers, recipients, attachment names and body for one handle.
apple_mail_set_message_status yes Mark read/unread/flagged. Disabled unless you opt in.
apple_mail_compose_draft yes Opens a pre-filled compose window. Never sends — you click Send.
apple_calendar_list_calendars no Calendar names + writable flag. Call before creating an event.
apple_calendar_create_event yes Create one event in Apple Calendar only. Disabled unless you opt in. Skips duplicates.

Requirements

  • macOS with Mail.app configured (at least one account)
  • Node.js 18+

Build

npm install
npm run build
node dist/index.js --doctor   # verifies Mail.app is reachable and permissions are granted

Configure Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "apple-mail": {
      "command": "/ABSOLUTE/PATH/TO/node",
      "args": ["/ABSOLUTE/PATH/TO/applemail-mcp-server/dist/index.js"]
    }
  }
}

Use the absolute path to both node (which node) and dist/index.js — Claude Desktoplaunches the server with a stripped environment, so a bare node often will not resolve.

Then quit Claude with Cmd+Q — closing the window is not enough, the config is only read atstartup — and reopen it. If the server does not appear, check ~/Library/Logs/Claude/mcp*.log.

Configure Claude Code

claude mcp add --transport stdio --scope user apple-mail -- node /ABSOLUTE/PATH/TO/dist/index.js

macOS permissions

The first call triggers a system prompt to let the host app control Mail. If you dismissed it, goto System Settings → Privacy & Security → Automation and enable Mail under Claude (orClaude Code / Terminal, whichever launched the server). Re-launch the host app afterwards.

Environment variables

Variable Default Effect
APPLE_MAIL_MCP_ALLOW_STATUS_WRITES off Set to 1 to register the read/flag tool.
APPLE_MAIL_MCP_ALLOW_COMPOSE on Set to 0 to remove the compose-window tool.
APPLE_MAIL_MCP_ALLOW_CALENDAR_WRITES off Set to 1 to register apple_calendar_create_event.
APPLE_MAIL_MCP_TIMEOUT_MS 90000 Per-operation timeout.

For the strictest posture, leave status and calendar writes off and set APPLE_MAIL_MCP_ALLOW_COMPOSE=0.The server is then incapable of modifying anything.

Design notes

Apple Events are the bottleneck. Each property access is an IPC round-trip, so the server neverloops over messages individually — it uses bulk getters (spec.subject() returns the whole columnin one event) and pushes filters down into Mail.app via whose. since_days defaults to 30 andsearch_messages refuses rather than hangs when more than max_scan (default 400) messagesmatch, returning an error that tells the agent how to narrow the query.

Handles, not IDs. Search returns an opaque base64 handle encoding account + mailbox + Mail'sinternal row id, so a follow-up read is a direct lookup rather than a re-scan. Handles go stale ifthe message is moved or deleted; the error says so and tells you to search again.

No string interpolation into script source. Parameters are passed to osascript as a singleJSON argv entry and parsed inside the script, so mailbox names and search terms cannot inject code.

Body search is not supported. query matches subject and sender only — searching bodies overApple Events on a large mailbox is pathologically slow. Use Mail's own search for that.

Calendar writes go to Apple Calendar only. apple_calendar_create_event never touches GoogleCalendar, Outlook, or any other service — it calls Calendar.app the same way compose_draft callsMail.app. It skips (rather than duplicates) an event when one with the same title already existson the same day in the same calendar, so a daily scan can be re-run safely. Date/time extractionfrom message text is left to the calling agent, not done with regex inside this server — AppleEvents give no reliable way to validate a guessed date, so a wrong guess would silently create abad event.

Daily mail-to-calendar automation

This server never runs on its own — an agent decides when to scan mail and whether a messagedescribes something calendar-worthy, then calls apple_calendar_create_event. To get a dailyscan, schedule a Claude Code routine (see the schedule skill) that runs once a day with a promptalong these lines:

Call apple_mail_search_messages (since_days: 1) across all accounts, read anything that looks
like a meeting, appointment, or deadline with apple_mail_get_message, then call
apple_calendar_list_calendars and apple_calendar_create_event to add each one to the right Apple
Calendar. Never invent a date. Report what was created and what was skipped.

Requires APPLE_MAIL_MCP_ALLOW_CALENDAR_WRITES=1, and Mail.app / Calendar.app must both bereachable when the routine fires (the host machine needs to be on and unlocked).

Security

This server reads your entire mailbox. Two things worth keeping in mind:

  1. Email bodies are untrusted input. A message can contain text aimed at the model rather thanat you. The get_message description tells the model to treat message contents as data andnever as instructions, but a read-only configuration is what actually bounds the blast radius —keep the write tools off unless you need them.
  2. Scope matters more than trust. If the mailbox holds client, government or UN correspondence,consider pointing searches at a specific account or archive mailbox rather than letting theserver roam every account.

Limitations (v0.1)

  • No send, move, delete, or attachment extraction
  • No true threading — search by subject or sender to group a conversation
  • Plain-text bodies only (Mail returns the text part; HTML markup is not preserved)
  • macOS only

License

MIT

MCP Server · Populars

MCP Server · New

    jonashertner

    OpenCaseLaw

    Open Swiss legal corpus + MCP server: 1M+ court decisions (1875–today), 21k laws, 10M-edge citation graph, 42 MCP tools. CC0 data, MIT code. Live at mcp.opencaselaw.ch

    Community jonashertner
    SystemCraftsman

    Strimzi Kafka CLI

    Command Line Interface for the Strimzi Kafka Operator

    Community SystemCraftsman
    DROOdotFOO

    Raxol

    Write one app, render it to a terminal, a browser, or as agent tools. The terminal for your Gundam.

    Community DROOdotFOO
    morluto

    REA: Reverse Engineer Anything

    Reverse engineer anything with agents, from app behavior down to native binaries.

    Community morluto
    nedlir

    MCPwner

    Model Context Protocol server for autonomous vulnerability discovery

    Community nedlir