icloud-mcp
Provides access to iCloud Mail, Calendar, and Contacts, enabling agents to read, search and send emails, manage calendar events, and create, update and search contacts through iCloud's IMAP, SMTP, CalDAV, and CardDAV interfaces.
Click on "Deploy 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., "@icloud-mcpDo I have any calendar events tomorrow?"
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.
icloud-mcp
A self-hosted MCP server that gives Claude (or any MCP client) access to your iCloud Mail, Calendar and Contacts through one connector.
Claude --OAuth + MCP over HTTPS--> icloud-mcp (your server) --IMAP / SMTP / CalDAV / CardDAV--> iCloudApple offers no OAuth for these protocols, so the server logs in with an app-specific password that lives only in the server's environment. Claude never sees it. Claude connects to your server through the server's own single-owner OAuth login.
Not affiliated with Apple. iCloud is a trademark of Apple Inc. This is an independent project that speaks the standard IMAP, SMTP, CalDAV and CardDAV protocols.
Read this first
An MCP connector that can read mail and act on your behalf is a prompt-injection target: a hostile email or calendar invite can contain text that tries to steer the agent. The server marks all mail, calendar and contact content as untrusted and its instructions tell agents to treat it as data, but that is a request to a language model, not a guarantee. What actually protects you is configuration:
Risk | Default | Setting |
Agent sends mail on injected instructions | Sending only queues a message; you approve it in a browser with your owner password ( |
|
Agent emails invitations to strangers | Attendee changes are blocked |
|
Agent mails arbitrary addresses | Any address, max 25 per message |
|
Agent destroys mail | Delete moves to Trash; permanent delete is off |
|
Agent changes anything | Everything writable |
|
In Claude you can additionally set the send, reply, forward and delete tools to "ask before use". Anyone who obtains the app-specific password has full mail, calendar and contact access (Apple offers no narrower scope), so protect the server and its .env accordingly.
Related MCP server: imail-mcp
Tools (24)
Area | Tools |
Mail, read |
|
Mail, write |
|
Calendar |
|
Contacts |
|
Behaviour worth knowing:
Replies keep the
Re:subject,In-Reply-To/References, the right recipients and the quoted original in plain text and HTML. Sent mail is copied to Sent and the original is flagged Answered (forwards get$Forwarded).draft=truesaves to Drafts instead of sending.Reading a message does not mark it read. Bcc recipients receive the mail but the header is stripped on the wire.
Calendar: multiple calendars, recurring events expanded when listing, all-day events, reminders, links, notes, attendees (invitations are emailed by iCloud itself, see the security table). Editing a recurring event changes the whole series.
Contacts are fetched whole, cached, and searched locally (name, nickname, company, email, phone; accent-insensitive). A contact with no email is returned with
has_email: falseso an agent asks instead of guessing. When the connector is writable, agents can create and update contacts; updates retain fields outside the changed subset and use ETags to refuse stale overwrites.Misspelled names are handled.
contacts_searchoffers similar-sounding names (similar/did_you_mean) when nothing matches exactly, andmail_find_correspondentfinds people you have emailed with by approximate name, address or company, reading only message headers. Approximate matches are labelled, and the agent instructions require asking you to confirm before sending, inviting or editing on one.Recipients and attendees accept
a@b.com,Name <a@b.com>ormailto:a@b.com. Anything else is rejected with an actionable error and never silently dropped.
Requirements
Docker with the compose plugin (or Python 3.11+)
An Apple Account with two-factor authentication, and an app-specific password (account.apple.com > Sign-In and Security > App-Specific Passwords)
A public HTTPS address for the server. Claude connects from Anthropic's cloud, so a VPN or LAN address does not work. A Cloudflare Tunnel is the simplest option (outbound only, no port forwarding). Do not put Cloudflare Access or any login wall in front of it: Claude's servers cannot pass an interactive login, and the server has its own OAuth.
A Claude plan that supports custom connectors
Quick start
git clone <this repository> && cd icloud-mcp
cp .env.example .env # then fill in ICLOUD_USERNAME, ICLOUD_APP_PASSWORD, ICLOUD_DISPLAY_NAME,
# MCP_PUBLIC_URL (your https address, no trailing slash), MCP_OWNER_PASSWORD
chmod 600 .envMCP_OWNER_PASSWORD is a new random password (12+ characters) that you type when approving a client and in the outbox page. It is not your Apple password. ./configure.sh is an optional helper that asks for the secrets with silent prompts.
Check your credentials against real iCloud before exposing anything:
docker build -t icloud-mcp:local .
docker run --rm --env-file .env icloud-mcp:local python -m icloud_mcp.selftest # IMAP + SMTP login, CalDAV, CardDAV; sends nothing
docker run --rm --env-file .env icloud-mcp:local python -m icloud_mcp.selftest --probe-sent you@example.com # sends ONE test mail (see below)If a login fails, the login name is the usual cause: set IMAP_USERNAME, SMTP_USERNAME, CALDAV_USERNAME or CARDDAV_USERNAME separately.
Run it:
docker compose up -d --build # listens on 127.0.0.1:8000 onlyTo use the bundled Cloudflare Tunnel: create a tunnel, point its public hostname (the host in MCP_PUBLIC_URL) at http://icloud-mcp:8000, put the tunnel token in .tunnel.env as TUNNEL_TOKEN=..., and start with docker compose --profile tunnel up -d --build. Any TLS front (Caddy, nginx) works too as long as the Host header is preserved. MCP_PUBLIC_URL must match the public address exactly.
Connect Claude: Settings > Connectors > Add custom connector > https://<your-host>/mcp. Your server shows an approval page; enter the owner password. Reconnect the connector in Claude whenever you change tools or settings, because Claude caches tool definitions.
To revoke every connected client, delete oauth_state.json in the data volume and restart.
Approving outgoing mail
With the default SEND_REQUIRES_APPROVAL=true, mail_send, mail_reply and mail_forward return queued_for_owner_approval and nothing leaves. Open https://<your-host>/outbox (bookmark it, and only type the password there, never on a link an agent gives you), enter the owner password, review the exact recipients and text, then approve or discard. Queued messages expire (OUTBOX_TTL_SECONDS, default 24 h) and are released at most once.
Configuration
Everything is an environment variable; see .env.example for comments.
Variable | Default | Meaning |
| required | Apple Account you sign in with |
| required | App-specific password |
| username | From address (your iCloud address or alias) |
| empty | Sender name; plain-text signature appended to sent mail ( |
|
| IMAP |
|
| SMTP |
|
| CalDAV |
|
| CardDAV |
|
| Timezone for times without an offset; calendar for new events (else "Calendar"/"Home", else the first) |
| true | Switch whole areas off |
| false | No sending, moving, deleting, calendar changes, or contact changes |
| true | false = agents can only save drafts |
| true | Queue outgoing mail for browser approval |
| 86400, 20 | Queue lifetime and size |
| false | Allow attendees (iCloud then emails invitations, updates, cancellations) |
| empty | Only these addresses/domains may receive mail ( |
| 25 | Per message |
| false | Allow deleting from Trash |
| true | Append sent mail to Sent (iCloud does not do it itself) |
| 30000, 5 MiB | Result size caps |
| required | Public https address; owner password (12+ chars) |
| 0.0.0.0, 8000, empty | Bind address and extra allowed Host headers |
| true | No server-side MCP sessions, so restarting the server never breaks a connected client ("Missing session ID") |
| 90 | A tool call running longer is abandoned with an error instead of hanging |
|
| OAuth state and the outbox |
|
| Clients that may register |
| 3600, 30 days | Token lifetimes (refresh tokens rotate) |
| INFO |
Security model
iCloud credentials exist only in the server environment. Clients hold short-lived bearer tokens for this server.
Clients may register dynamically, but nothing is authorized without the owner password. Redirect hosts are restricted. Tokens are stored as SHA-256 hashes (file mode 600). The approval and outbox pages lock after 10 wrong passwords in 15 minutes (server-wide; existing tokens keep working).
The MCP endpoint validates
HostandOrigin. Tool results carry an untrusted-content notice. HTTP-client request logging is disabled so account identifiers do not reach the logs.This is a single-owner design: one deployment serves one iCloud account. It is not multi-tenant, and storing other people's app-specific passwords is deliberately out of scope.
iCloud quirks this project works around
These only showed up against the real service, not against local test servers:
CalDAV rejects UID-filtered queries (
412), so events are fetched by their resource name with a scan fallback. An attendee who is the account owner is rewritten to an internal path with the address in theEMAILparameter.IMAP has no
MOVE. Moving and deleting use COPY, flag\Deleted, thenUID EXPUNGEof exactly those messages (never a plainEXPUNGE). iCloud does not file sent mail by itself.CardDAV discovery ends on a different host than the one you start on (follow the returned links), returns the whole address book in one request, and stores about half of all emails in grouped
itemN.EMAILproperties with labels initemN.X-ABLabel.
Limits
Reminders, Notes and iCloud Drive are not reachable over these protocols. Contact photos and notes are deliberately not exposed to agents; contact deletion is permanent.
One identity; aliases as From are not supported. Attachments other than text return base64 and are size-capped.
Each tool call opens a fresh connection (about 1.5 to 5 seconds per call against iCloud).
Claude currently shows no custom icon for custom connectors, whatever the server advertises (open request). Optional icon files placed in
src/icloud_mcp/static/are served and advertised anyway; none ship with the source.
Development
python -m venv .venv && . .venv/bin/activate
pip install -e ".[test]"
pytest tests --ignore=tests/integration # offline tests, no network
sudo apt install dovecot-imapd && dev/start_local_stack.sh
pytest tests # also runs the integration tests against local Dovecot, an SMTP sink and Radicaledev/e2e_http.py drives a running server over HTTP (OAuth plus tool calls). Local test servers accept things iCloud does not (see the quirks above), so treat selftest and a manual run against a real account as part of testing any change.
License
MIT, see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
A Remote MCP Server that checks every email before your agent acts on it. Connect via MCP protocol, pay per use with Skyfire.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
An MCP server that provides email capabilities, hosted on Alpic platform
An MCP server that provides email capabilities, hosted on Alpic platform
Related MCP Servers
- AlicenseAqualityBmaintenanceMCP server that enables email management (send, read, search, delete, etc.) via IMAP/SMTP, compatible with Gmail, Outlook, Yahoo, iCloud, and other standard mail servers.11MIT
- FlicenseBqualityCmaintenanceMCP server that connects Claude to iCloud Mail, enabling reading, searching, sending, and organizing emails via IMAP/SMTP.14-
- AlicenseNot gradedqualityDmaintenanceMCP server for iCloud integration, providing tools for managing calendars, contacts, and email.7MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for iCloud integration, enabling management of calendars (CalDAV), contacts (CardDAV), and email (IMAP/SMTP) through natural language.MIT