che-apple-mail-mcp
Provides comprehensive integration with Apple Mail, enabling management of mail accounts, mailboxes, emails, and actions such as searching, composing, replying, forwarding, flagging, moving, copying, deleting, and exporting messages 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., "@che-apple-mail-mcpSearch my mailbox for emails from Jane about the quarterly report"
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.
che-apple-mail-mcp
The most comprehensive Apple Mail MCP server - 53 tools with SQLite-powered millisecond search across 250K+ emails.
Why che-apple-mail-mcp?
Feature | Other MCPs | che-apple-mail-mcp |
Total Tools | ~20 | 53 |
Language | Python | Swift (Native) |
Search Speed | Seconds (AppleScript) | Milliseconds (SQLite) |
Search Fields | Subject/Sender | Subject/Sender/Recipient/Date |
Batch Operations | No | Up to 50 emails per call |
Mailbox Management | Basic | Full CRUD |
Email Colors | No | 7 flag colors + background |
VIP Management | No | Yes |
Rule Management | Partial | Full CRUD |
Signatures | No | Yes |
Raw Headers/Source | No | Yes |
Related MCP server: apple-mail-mcp
Quick Start
Install the plugin. It brings the signed binary, the /archive-mail command
family, the safety rules, and the staleness hook as one unit:
claude plugin marketplace add PsychQuant/che-apple-mail-mcp
claude plugin install che-apple-mail-mcp@che-apple-mail-mcpThen grant permissions — the setup window shows live status and links straight to the right System Settings pane:
~/bin/CheAppleMailMCP --setup💡 Full Disk Access is what makes the fast SQLite read path and
batch_export_emails_markdownwork. Without it the tools still run but read little or nothing, which is easy to mistake for a bug rather than a permission. macOS does not let an app request FDA programmatically — it has to be ticked by hand — which is exactly what the setup window is there to make quick.
Plugin vs MCP-only
Registering the MCP server by itself is a supported advanced path, but it is a strictly smaller install. Choose it knowingly — nothing at runtime will tell you these are missing (#353):
Shipped by the plugin | Present with MCP-only |
All 53 MCP tools | ✅ yes |
| ❌ the archiving SOP does not exist |
| ⚠️ background: since #304 the wrapper is structurally impossible, so this rule now explains the six refusal reasons and their recipes rather than guarding against a silent fallback |
| ❌ no confirmation discipline on destructive operations |
| ❌ a session can keep running a stale binary after an upgrade |
Developer ID signed + notarized binary | ❌ a self-built binary is ad-hoc signed; on macOS 26 TCC cannot reliably hold FDA/Automation for it, so permissions appear to be granted and then stop working (#211) |
Version sidecar → | ❌ no sidecar next to a hand-built binary, so that check is permanently silent |
git clone https://github.com/PsychQuant/che-apple-mail-mcp.git
cd che-apple-mail-mcp
swift build -c release
# --scope user : available across all projects (stored in ~/.claude.json)
# --transport stdio: local binary execution via stdin/stdout
# -- : separator between claude options and the command
mkdir -p ~/bin
cp .build/release/CheAppleMailMCP ~/bin/
claude mcp add --scope user --transport stdio che-apple-mail-mcp -- ~/bin/CheAppleMailMCPInstall the binary to a local directory like ~/bin/. Avoid cloud-synced
folders (Dropbox, iCloud, OneDrive) — sync activity causes MCP connection
timeouts.
For a self-built binary to hold TCC permissions across rebuilds, sign it with a Developer ID; see Signing & Notarization. Otherwise expect to re-grant permissions after every build.
Recent Releases
For full details see CHANGELOG.md.
v2.7.2 (2026-05-10) — attachmentFragment cluster + fallback parity
Hardened
attachmentFragmentindent across all 3 callers + removed deadMailController.attachmentScripthelper that bypassed v2.7.0's race-mitigation delays (#61, #62)Attachment count cap (50) + env-configurable delays via
CHE_MAIL_ATTACHMENT_DELAY_BETWEEN/_TRAILING(#63, #64)get_email_metadataSQLite path now falls back to AppleScript on error — last read-tool gap closed; all 8 SQLite-first read tools now have parity fallback (#71)
v2.7.1 (2026-05-09) — base64 fix + .partial.emlx + observability
Critical: RFC822 header/body split was returning a relative array index instead of an absolute
Dataindex, causinghtml_bodyto begin with"sion: 1.0\n\n<base64>"for some Android Gmail messages — raw base64 leaked into LLM context and triggered AUP false-positives downstream (#72)save_attachmentnow reads fromAttachments/<rowId>/<part_id>/<filename>cache when.partial.emlxbody is empty — no more silent 0-byte writes for IMAP messages with stripped binaries (#66)SQLite fast-path failures now log to stderr (
SQLite ... fast path failed for rowId=...; falling through to AppleScript) (#69)
v2.7.0 (2026-05-04) — Mail.app race mitigation
Multi-attachment AppleScript paced with 0.3s between + 0.5s trailing delays to mitigate Mail.app silently dropping attachments under fast IPC (#60)
v2.6.0 (2026-05-03) — Security & validation hardening (8 PRs, 16 issues)
forward_emailplain mode now embeds RFC 3676>quoted original (parity withreply_email's #43 fix) (#44)Hard-fail on tool param type mismatch —
bool/[String]no longer silently coerced (#35)Recipient email validation rejects header injection (control chars, missing/multiple
@) (#41)cc_additionaldeduplicates case-insensitively (#34)Attachment path deny-list (
~/.ssh, Keychains, TCC db, browser cookies) + symlink-resolved + newMAIL_MCP_ATTACHMENT_ROOTSenv allow-list (#38)All 17 id-taking tools hard-validate
idas Int at handler boundary — defeats AppleScript predicate injection (#50)Gated integration tests for
reply_emailruntime (#37, #45) + smoke matrix templates (#46, #47)
v2.5.0 (2026-04-17) — Composing format parameter
All 4 composing tools (
compose_email/create_draft/reply_email/forward_email) gainformat: "plain" | "markdown" | "html"param (closes #14, #15)New
message-compositioncapability spec
All 53 Tools
Tool | Description |
| List all mail accounts |
| Get account details |
Tool | Description |
| List all mailboxes (folders) |
| Create a new mailbox |
| Delete a mailbox |
| Get special mailbox names (inbox, drafts, sent, trash, junk, outbox) |
Tool | Description |
| List emails in a mailbox |
| Get full email content |
| Search by subject/content |
| Get unread count |
| Get all email headers |
| Get raw email source |
| Get metadata (forwarded, replied, size) |
Tool | Description |
| Mark as read/unread |
| Flag/unflag email |
| Set flag color (7 colors) |
| Set email background color |
| Mark as junk/not junk |
| Move to another mailbox |
| Copy to another mailbox |
| Delete email (to trash) |
Tool | Description |
| Send new email (supports cc/bcc/attachments; |
| Reply to email. Optional: |
| Forward email. Optional |
| Redirect email (keeps original sender) |
| Open mailto URL |
Reply-as-draft example (v2.4.0+)
Reply to a thread, add extra CC, attach files, and save as a draft for human review before sending:
reply_email(
id="<message id from search_emails>",
mailbox="INBOX",
account_name="iCloud",
body="Reply text",
cc_additional=["x@y.com"],
attachments=["/path/to/file.pdf"],
save_as_draft=true
)Tool | Description |
| List draft emails — each entry carries |
| Create a draft (supports attachments; optional |
| Replace an existing draft (upsert, #276): locate by |
Tool | Description |
| List email attachments |
| Save attachment to disk |
Tool | Description |
| List VIP senders |
Tool | Description |
| List mail rules |
| Get rule details |
| Create a new rule |
| Delete a rule |
| Enable/disable a rule |
Tool | Description |
| List email signatures |
| Get signature content |
Tool | Description |
| List SMTP servers |
Tool | Description |
| Check for new mail |
| Sync IMAP account |
Tool | Description |
| Get up to 50 emails in one call (per-item errors) |
| List attachments for up to 50 emails |
| Server-side bulk export to verbatim markdown + attachments (frozen frontmatter manifest; concurrency-serialized per output_dir — #193 / #236) |
| DEPRECATED — renamed to |
Tool | Description |
| Extract name from email address |
| Extract email from full address |
| Get Mail.app info |
| Import mailbox from file |
Tool | Description |
| Check Full Disk Access status (SQLite fast-path availability) |
| Check Accessibility permission (the compose/reply GUI paths; without it those tools refuse) |
| Check Automation permission (Apple Events to Mail) — non-prompting probe, four states with remediation (#293); the binary holds its OWN grant, osascript working ≠ binary authorized (#288) |
Response shape: search_emails / list_emails
Both tools return an envelope object { results, returned, limit, truncated } — not a bare array (changed in v2.14.0, #204). Read the matches from .results:
Field | Meaning |
| Array of result objects (per-object fields unchanged from the pre-envelope shape). |
| Number of objects in |
| Effective |
|
|
truncated is definitive on the SQLite fast path (it fetches limit + 1 internally); on the AppleScript fallback it is a best-effort returned == limit heuristic. Any "enumerate → batch process" consumer should check truncated before assuming it has the full set.
Installation
Start with Quick Start — installing the plugin is the supported path and gives you the commands, safety rules, staleness hook and a signed binary. Everything below is the advanced / development route: it registers the MCP server alone, which is a strictly smaller install (see Plugin vs MCP-only for what is missing, since nothing at runtime will tell you).
Requirements
macOS 13.0+
Xcode Command Line Tools (for the build-it-yourself route below)
Apple Mail with at least one account configured
Step 1: Build
git clone https://github.com/PsychQuant/che-apple-mail-mcp.git
cd che-apple-mail-mcp
swift build -c releaseStep 2: Configure
For Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"che-apple-mail-mcp": {
"command": "/full/path/to/che-apple-mail-mcp/.build/release/CheAppleMailMCP"
}
}
}For Claude Code (CLI)
# Copy to ~/bin and register (user scope = available in all projects)
mkdir -p ~/bin
cp .build/release/CheAppleMailMCP ~/bin/
claude mcp add --scope user --transport stdio che-apple-mail-mcp -- ~/bin/CheAppleMailMCPStep 3: Grant Permissions
The fastest route is the setup window, which shows live Full Disk Access / Automation / Accessibility status, re-checks as you grant, and opens the right System Settings pane for you:
~/bin/CheAppleMailMCP --setupTo do it by hand instead:
Automation (control Mail.app):
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation"Find CheAppleMailMCP and enable permission for Mail.app
If using Claude Code, also add Terminal or iTerm
Full Disk Access (the SQLite fast path + export_emails_markdown read ~/Library/Mail):
open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"macOS grants Full Disk Access to the responsible process — the app that launched this server — not to the binary itself. For an MCP server run by Claude Code inside a terminal, that responsible process is the terminal (Ghostty / Terminal / iTerm), so add your terminal app here and enable it. One grant on the terminal covers every MCP server it launches. (If you instead run the binary directly, or use the Claude Desktop bundle, add that binary — ~/bin/CheAppleMailMCP — since it is then its own responsible process.) The FDA-denied error message names these candidates for you — it does not auto-resolve the one exact app, because macOS exposes no reliable in-process API for that (#214). Without Full Disk Access, read tools silently fall back to the slower AppleScript path and SQLite-only features (projection, export_emails_markdown) fail. For the direct-launch path, a Developer ID-signed build makes the grant survive version bumps — see Signing & Notarization.
Guided setup (#213) — instead of the manual steps above, the binary ships setup helpers:
CheAppleMailMCP --setupopens a small window with live Full Disk Access status (re-checked on a timer, flips to "Ready ✅" the moment you grant) plus an on-demand Automation check, and "Open Full Disk Access settings" / "Copy binary path" buttons.CheAppleMailMCP --check-fdaprints the status headlessly (and opens the pane when access is denied) — handy from a terminal or script.The
check_fdaMCP tool reports the same status to Claude on demand (call it when a SQLite-only feature errors).
None of these can remove the single manual toggle (Apple puts FDA in the manual-only bucket alongside Accessibility / Screen Recording), but they make "what do I do?" obvious and give live feedback the instant you flip it on.
Accessibility (compose, #175/#304) — a separate, optional grant from Full Disk Access. Mail.app wraps any AppleScript-injected outgoing-message body in <blockquote type="cite">, which some mobile clients render as a quotation of your own text — and which the sender cannot see locally, because the wrapper's inline style has no border. Since #304 the code that produces it no longer exists: every composing tool takes its body from Mail's own editor — a mailto: hand-off for compose_email / create_draft, the native reply/forward verb plus paste for reply_email / forward_email — and drives save/send/attach with keyboard shortcuts, which needs Accessibility (System Settings → Privacy & Security → Accessibility), granted to the same responsible process as FDA (your terminal / Claude Desktop). The check_accessibility MCP tool and the --setup window's Accessibility row report the status. Without it these tools now FAIL rather than fall back — there is no second path to fall back to, so a call that cannot run cleanly returns a named error and creates nothing. The error points at open_mailto, which needs no TCC grant at all (it cannot carry attachments; you save or send the window yourself). Exactly six conditions refuse a call: a non-plain format; an empty subject; Accessibility not granted; a from_address that is not a bare addr-spec; an attachment path containing non-ASCII characters (#220); and a recipient carrying a display name that this path cannot fill (cc/bcc always; to on a send — a draft's to display name is filled through the GUI, #277). For a clean body from a non-default account, pass from_address: the GUI selects it in Mail's From popup and reads the selection back, aborting rather than risk the wrong sender (#219). Removed with the legacy path: format: "markdown" / "html" — no path shipped today delivers rich text without the body assignment that was deleted. That is what exists, not a proof of impossibility (#310): the paste path (#218) is a second wrapper-free route and NSPasteboard can carry rich flavors, but the MIME it produces is unverified — #306 settles it; #308 / #309 are alternatives, the require_wrapper_free and sanitize_links parameters, and the CHE_MAIL_DISABLE_MAILTO_COMPOSE / CHE_MAIL_DISABLE_PASTE_REPLY escape hatches. Two capabilities go with them, stated plainly: composing without a visible window (the hatches' original purpose) is no longer possible, and compose_email can no longer send to Name <addr> — use create_draft and send the draft yourself.
Automation TCC (-1743) and the zero-TCC escape hatch
If AppleScript-backed tools fail with AppleScript error (-1743): Not authorized to send Apple events to Mail, the Automation permission is missing for this binary. The
signed MCP binary holds its OWN Automation grant — its TCC identity is keyed to the
binary's signing identity (the #211 FDA lesson, Automation axis), separate from your
terminal's. Empirically verified: osascript controlling Mail from your shell does NOT
mean the binary is authorized. Grant it under System Settings → Privacy & Security →
Automation — find the entry for the binary / its host (Claude Desktop extension:
under Claude.app) and enable Mail. If no entry exists, a previous denial is being
remembered and macOS will not re-prompt: run tccutil reset AppleEvents, then retry a
Mail tool to retrigger the prompt. Grants are per-install, and a binary update can
invalidate the entry (#211).
Until the grant is in place, open_mailto still works: it goes through LaunchServices
(zero TCC, #287) and opens a cite-block-free compose window in the system default mail
client. mailto cannot carry attachments (RFC 6068) — drag files in manually.
Step 4: Restart Claude
# For Claude Desktop
osascript -e 'quit app "Claude"' && sleep 2 && open -a "Claude"
# For Claude Code - start a new session
claudeUsage Examples
Natural Language (Claude Desktop)
"List all my mail accounts"
"Show unread emails in Gmail inbox"
"Search for emails about 'quarterly report'"
"Send an email to john@example.com about the meeting"
"Flag important emails in red"
"Create a rule to move newsletters to a folder"Direct Tool Calls (Claude Code)
"Use list_accounts to show my accounts"
"Use search_emails to find emails containing 'invoice'"
"Use set_flag_color to mark email ID 12345 as blue"
"Use check_for_new_mail to refresh"Flag & Background Colors
Flag Colors (set_flag_color)
Index | Color |
0 | Red |
1 | Orange |
2 | Yellow |
3 | Green |
4 | Blue |
5 | Purple |
6 | Gray |
-1 | Clear |
Background Colors (set_background_color)
blue, gray, green, none, orange, purple, red, yellow
Performance & Storage
SQLite + .emlx fast path
Most read tools prefer Apple Mail's local Envelope Index (SQLite) and on-disk .emlx message files over AppleScript IPC, with transparent AppleScript fallback when the SQLite path can't satisfy a request:
Tool | SQLite/.emlx path | AppleScript fallback |
| ✓ | ✓ on any error |
| ✓ (per item) | ✓ (per item) |
| ✓ | ✓ on any error |
| ✓ | ✓ on any error |
| ✓ | ✓ when reader unavailable |
| ✓ | ✓ on any error |
| ✓ | ✓ on any error |
| ✓ | ✓ on any error (since #71) |
For save_attachment's read path the fast path is 10–100× faster than AppleScript (per #12 measurements). Other tools' speedup ratios depend on request shape; in general, large bulk reads see the biggest gain.
The fast path requires:
Full Disk Access granted to the host process (System Settings → Privacy & Security → Full Disk Access)
Apple Mail's local store at
~/Library/Mail/V10/...Message has been synced to local
.emlxstorage
EWS / Exchange accounts intentionally bypass the fast path
Exchange (EWS) accounts in Apple Mail do not materialize .emlx files — message bodies live on the server and are fetched on demand. For these accounts, all 8 read tools (including get_email_metadata since #71) transparently degrade to AppleScript IPC (which is correct but slower). Symptoms:
A bulk fetch of 500 EWS messages will be noticeably slower than 500 IMAP/Gmail messages
This is not a bug — it's an Apple Mail storage architecture constraint (see #9)
Diagnosing fast-path bypass
When the fast path fails for a non-EWS account, the failure is logged to stderr (since #69). Run the binary in a terminal and watch stderr to distinguish:
EnvelopeIndexReader init failed: ...— DB unreachable (commonly: Full Disk Access missing)SQLite get_email fast path failed for rowId=N: ...— per-message failure (e.g.,.partial.emlxonly, malformed MIME, file not yet synced)
Both cases transparently fall through to AppleScript with ... falling through to AppleScript in the log line, so behavior is preserved while observability is restored.
Troubleshooting
Problem | Solution |
Server disconnected | Rebuild with |
Not allowed to send Apple events | Add permissions in System Settings > Automation |
Mail.app not responding | Ensure Mail.app is running with configured accounts |
Commands timing out | Large mailboxes take longer; try specific searches |
Bulk fetch slower than expected | Watch stderr for |
| Since #173 both errors come back with an actionable hint naming the failing reference (account / mailbox / message). Common causes: two Mail.app accounts share the same |
Account Disambiguation
Mail.app's AppleScript account "<display_name>" selector is not unique when two accounts share the same display_name — a common pattern when an iCloud catch-all alias forwards a Gmail address back to itself, or when Google Workspace + personal Gmail overlap. Any AppleScript-routed tool (save_attachment fallback, get_email, mark_read, etc.) will then non-deterministically pick the wrong account → -1728 / -1719 errors.
The fix: pass account_id (Mail.app's globally-unique UUID) alongside account_name. When provided, save_attachment uses Mail.app's account id "<UUID>" selector instead, bypassing the ambiguity:
// Tool call: save_attachment with account_id
{
"id": "273214",
"mailbox": "[Gmail]/全部郵件",
"account_name": "alice@example.com",
"account_id": "C38E0583-47F8-4468-BE70-43155C15549D", // ← disambiguates
"attachment_name": "report.pdf",
"save_path": "/tmp/report.pdf"
}Discovering account_id:
From
search_emailsresults — each object in theresultsarray (aSearchResult) carries anaccount_idfield alongsideaccount_name(populated by decoding the account UUID from the SQLitemailboxes.urlauthority viaMailboxURL.decode— Mail.app's storage convention encodes the account UUID in the mailbox URL authority; there is no directSELECT mailboxes.account_id). Recommended: pass it through directly.Manually — read
~/Library/Mail/V10/MailData/Signatures/AccountsMap.plist. The top-level keys are the UUIDs; theAccountURLvalue contains the matching email address percent-encoded in the authority.In AppleScript —
tell application "Mail" to get id of every accountreturns the UUID list.
Backward compatibility: account_id is optional. When omitted (or empty), tools fall back to the legacy account "<display_name>" path — behavior identical to pre-#101 — with one save_attachment exception (#173): when account_name contains @ (email-shaped, the form SQLite-path tools like search_emails emit), save_attachment first reverse-looks-it-up in AccountsMap and silently upgrades to the account id "<UUID>" selector (the upgrade is logged to stderr). Exactly one match → that UUID; several accounts behind one address (iCloud catch-all + Gmail) → an actionable error listing every candidate instead of a raw -1728; no match → the legacy display-name path, unchanged. Edge: a Mail account whose description legitimately contains @ and happens to equal another account's email now resolves in the email namespace first — pass account_id explicitly to pin the selector. Other tools keep the strict pre-#101 fallback (the cross-tool sweep is #176).
Scope: account_id is accepted across the AppleScript-routed tools that reference mail by account. It began with save_attachment (#101); the #104 sweep then added the 13 single-message / movement / relay / mailbox tools below:
save_attachment(#101) — the precursorPR-A — 5 single-message mutation tools:
mark_read,flag_email,set_flag_color,set_background_color,mark_as_junkPR-B — 3 movement/destruction tools:
move_email,copy_email,delete_emailPR-C — 3 message-relay tools:
reply_email,forward_email,redirect_emailPR-D — 2 mailbox CRUD tools:
create_mailbox,delete_mailbox
The surface has since expanded beyond the #104 set:
#176 — generalized the email→UUID
resolveAccountIdForToolchokepoint across all 14 AppleScript-routed write handlers (so an email-formaccount_nameresolves to the UUID selector, not just an acceptedaccount_id).#180 — threaded
account_idthrough the read-tool AppleScript fallbacks (list_emails/search_emails/get_email/ headers / source / metadata / attachments /get_unread_count) viaresolveMailboxRef/resolveMsgRef(the PR-E that was previously deferred is now done).#179 —
get_special_mailboxesacceptsaccount_id/account_namefor per-account special-mailbox real names.#191 — the account-level action tools
check_for_new_mailandsynchronize_accountgained theaccount_idescape hatch (synchronize_accountacceptsaccount_idalone).
Still not covered by account_id (tracked): get_account_info / list_mailboxes (#202).
compose_email / create_draft do not exhibit the display_name-collision defect — they make new outgoing message rather than referencing existing mail by account, so they never emit an account "<display_name>" selector. Multi-account sender selection is now available via the optional from_address parameter (#131) — pass any one of your configured Mail.app email addresses ("alice@example.com" or RFC 5322 form "Alice <alice@example.com>") to set the sender of the outgoing message; omit to use Mail.app's default account. Use list_accounts to discover the addresses configured on the running Mac.
Cross-account move/copy is not supported via account_id (#129 — from #127 verify). move_email and copy_email accept a single account_id, which is threaded through both the source msgRef and the destination mailboxRef. The architectural choice is correct (movement stays within one account, because Mail.app's AppleScript verb move msg to <mailboxRef> requires the destination mailbox to be expressed relative to a single account context). Mail.app's UI permits cross-account move via drag-and-drop, but the AppleScript-routed move_email / copy_email tools cannot replicate that — calling move_email with account_id of one account while expecting the destination to_mailbox to be resolved against a different account silently picks the wrong account's mailbox of that name (if both accounts happen to have one) or raises -1719 "Invalid mailbox index". If you need a copy of the message's contents under a different account, you can manually rebuild it via save_attachment + compose_email — note this is not a true move/copy: original metadata (Message-ID, received-date, flags, labels) and message identity are not preserved.
Technical Details
Framework: MCP Swift SDK v0.10.0
Read path: SQLite (Envelope Index) +
.emlxfile parser, with AppleScript fallback for EWS / unparseable.emlxWrite/state path: AppleScript via
NSAppleScriptTransport: stdio
Platform: macOS 13.0+ (Ventura and later)
Signing & Notarization
The distributed binary is Developer ID-signed and notarized, and that is not cosmetic. The fast read path needs Full Disk Access (FDA), and macOS TCC keys an FDA grant to the binary's designated requirement. For an ad-hoc binary that requirement is the cdhash, so every version bump invalidated the grant and you had to re-add the binary to the Full Disk Access list after each release. A stable Developer ID signature keys the grant to the signing identity instead, so it survives version bumps (#211) — that signature, not notarization, is what delivers the persistence.
Notarization matters for quarantined-launch paths: a browser download or the .mcpb (Claude Desktop) install, where Gatekeeper assesses the binary on first launch. The plugin wrapper's curl + exec path sets no quarantine attribute, so Gatekeeper never fires there. We notarize anyway so the published release asset is safe to run by any means.
The first grant is still manual. FDA (
kTCCServiceSystemPolicyAllFiles) has no programmatic request API — an app can only deep-link you to the settings pane. Signing makes that first grant permanent, not automatic.
One-time setup (maintainers)
# 1. Developer ID Application cert in your login keychain (needs an Apple Developer account)
security find-identity -p codesigning -v # find your identity
# 2. notarytool keychain profile (prompts for an app-specific password — never pass it on the CLI)
xcrun notarytool store-credentials <profile-name> \
--apple-id <your-apple-id> --team-id <your-team-id>
# 3. Export both for the signed targets
export DEVELOPER_ID='Developer ID Application: Your Name (TEAMID)'
export NOTARY_PROFILE='<profile-name>'Dev install on your own machine (fast — no notarization)
make install-signed # build + Developer ID sign + copy to ~/binUse this to get a stable FDA grant on your own Mac without waiting for Apple notarization: your own cert launches fine locally, and the grant survives future rebuilds. Grant Full Disk Access once to ~/bin/CheAppleMailMCP and you are done.
Distribution release (signed + notarized + published)
make release-signed VERSION=vX.Y.Z # wraps scripts/release.sh with REQUIRE_CODESIGN=1This builds a universal (arm64 + x86_64) binary, signs it, notarizes it (1–15 min Apple round-trip), and uploads it to the GitHub release. Forks without certs can still cut an unsigned dev release with SKIP_CODESIGN=1 ./scripts/release.sh vX.Y.Z.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE for details.
Author
Created by Che Cheng (@kiki830621)
If you find this useful, please consider giving it a star!
This server cannot be installed
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 Servers
- AlicenseAqualityAmaintenanceEnables AI assistants to interact with Apple Mail through natural language, providing comprehensive email management including reading, searching, composing, organizing, and analyzing emails across all configured accounts. Includes an expert skill system that teaches intelligent email workflows and productivity strategies.26193MIT
- AlicenseAqualityAmaintenanceEnables AI assistants to read, send, search, and manage emails in Apple Mail on macOS.2599MIT
- AlicenseNot gradedqualityCmaintenanceEnables unified email management across Gmail, Outlook, iCloud, and IMAP providers with tools for search, send, organize, and batch operations via natural language.58MIT
- AlicenseNot gradedqualityAmaintenanceEnables using Apple Mail accounts to search, read, manage, draft, and send messages from Codex or Claude Code locally.MIT
Related MCP Connectors
Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.
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/PsychQuant/che-apple-mail-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server