Skip to main content
Glama
epinethrone

icloud-mcp

by epinethrone

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-->  iCloud

Apple 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 (/outbox)

SEND_REQUIRES_APPROVAL=true (turn off only if you accept the risk)

Agent emails invitations to strangers

Attendee changes are blocked

ALLOW_CALENDAR_INVITES=false

Agent mails arbitrary addresses

Any address, max 25 per message

SEND_ALLOWLIST, MAX_RECIPIENTS

Agent destroys mail

Delete moves to Trash; permanent delete is off

ALLOW_PERMANENT_DELETE=false

Agent changes anything

Everything writable

READ_ONLY=true for a read-only connector

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_list_folders, mail_search, mail_find_correspondent, mail_get_message, mail_get_thread, mail_get_attachment

Mail, write

mail_send, mail_reply (incl. reply-all), mail_forward, mail_mark, mail_move, mail_delete (to Trash), mail_create_folder

Calendar

calendar_list_calendars, calendar_list_events, calendar_get_event, calendar_create_event, calendar_update_event, calendar_delete_event

Contacts

contacts_search, contacts_get, contacts_create, contacts_update, contacts_delete (notes and photos are never returned)

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=true saves 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: false so 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_search offers similar-sounding names (similar / did_you_mean) when nothing matches exactly, and mail_find_correspondent finds 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> or mailto: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 .env

MCP_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 only

To 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

ICLOUD_USERNAME

required

Apple Account you sign in with

ICLOUD_APP_PASSWORD

required

App-specific password

ICLOUD_EMAIL_ADDRESS

username

From address (your iCloud address or alias)

ICLOUD_DISPLAY_NAME, EMAIL_SIGNATURE

empty

Sender name; plain-text signature appended to sent mail (\n = newline)

IMAP_HOST/PORT/SECURITY/USERNAME

imap.mail.me.com, 993, ssl, username

IMAP

SMTP_HOST/PORT/SECURITY/USERNAME

smtp.mail.me.com, 587, starttls, username

SMTP

CALDAV_URL, CALDAV_USERNAME, CALDAV_REQUIRE_TLS

https://caldav.icloud.com, username, true

CalDAV

CARDDAV_URL, CARDDAV_USERNAME

https://contacts.icloud.com, username

CardDAV

DEFAULT_TIMEZONE, DEFAULT_CALENDAR

UTC, auto

Timezone for times without an offset; calendar for new events (else "Calendar"/"Home", else the first)

ENABLE_MAIL, ENABLE_CALENDAR, ENABLE_CONTACTS

true

Switch whole areas off

READ_ONLY

false

No sending, moving, deleting, calendar changes, or contact changes

ALLOW_SEND

true

false = agents can only save drafts

SEND_REQUIRES_APPROVAL

true

Queue outgoing mail for browser approval

OUTBOX_TTL_SECONDS, OUTBOX_MAX

86400, 20

Queue lifetime and size

ALLOW_CALENDAR_INVITES

false

Allow attendees (iCloud then emails invitations, updates, cancellations)

SEND_ALLOWLIST

empty

Only these addresses/domains may receive mail (@example.org,friend@example.com)

MAX_RECIPIENTS

25

Per message

ALLOW_PERMANENT_DELETE

false

Allow deleting from Trash

SAVE_SENT_COPY

true

Append sent mail to Sent (iCloud does not do it itself)

MAX_BODY_CHARS, MAX_ATTACHMENT_BYTES

30000, 5 MiB

Result size caps

MCP_PUBLIC_URL, MCP_OWNER_PASSWORD

required

Public https address; owner password (12+ chars)

MCP_HOST, MCP_PORT, MCP_EXTRA_ALLOWED_HOSTS

0.0.0.0, 8000, empty

Bind address and extra allowed Host headers

MCP_STATELESS

true

No server-side MCP sessions, so restarting the server never breaks a connected client ("Missing session ID")

TOOL_TIMEOUT_SECONDS

90

A tool call running longer is abandoned with an error instead of hanging

DATA_DIR

./data (/data in Docker)

OAuth state and the outbox

OAUTH_ALLOWED_REDIRECT_HOSTS

claude.ai,claude.com,localhost,127.0.0.1

Clients that may register

ACCESS_TOKEN_TTL, REFRESH_TOKEN_TTL

3600, 30 days

Token lifetimes (refresh tokens rotate)

LOG_LEVEL

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 Host and Origin. 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 the EMAIL parameter.

  • IMAP has no MOVE. Moving and deleting use COPY, flag \Deleted, then UID EXPUNGE of exactly those messages (never a plain EXPUNGE). 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.EMAIL properties with labels in itemN.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 Radicale

dev/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.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    MCP server that enables email management (send, read, search, delete, etc.) via IMAP/SMTP, compatible with Gmail, Outlook, Yahoo, iCloud, and other standard mail servers.
    11
    MIT
  • F
    license
    B
    quality
    C
    maintenance
    MCP server that connects Claude to iCloud Mail, enabling reading, searching, sending, and organizing emails via IMAP/SMTP.
    14
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server for iCloud integration, providing tools for managing calendars, contacts, and email.
    7
    MIT