Skip to main content

A Model Context Protocol server for iCloud mail and calendar, with macOS Keychain credential storage.

Project description

icloud-mcp

PyPI Python License: MIT

A Model Context Protocol server that gives AI assistants read-only access to your iCloud mail and calendar over IMAP and CalDAV. Credentials live in your OS keyring (macOS Keychain by default) — never in a config file or the repo.

Defaults target iCloud, but every endpoint is overridable, so it works against any standard IMAP/CalDAV provider.

Status

Read-only by default; writes are strictly opt-in. Mail, calendar, and contacts can be listed, searched, and read with no ability to change anything: the IMAP connection is opened read-only and bodies are fetched with BODY.PEEK[], so messages are never even marked as read.

Mutating tools span mail (send_mail, reply_mail, forward_mail), calendar (create_event, update_event, delete_event), and contacts (create_contact, update_contact, delete_contact) — but all are disabled unless you set ICLOUD_ENABLE_WRITES=1, and even then every write requires an interactive confirmation (MCP elicitation) before it runs. See Writes (opt-in).

Writes (opt-in)

Mutations are gated two ways:

  1. Operator switch — write tools refuse with an explanatory error unless ICLOUD_ENABLE_WRITES=1 is set in the server's environment.
  2. Per-action confirmation — when enabled, each write tool calls back to the client to confirm the exact action before executing. Destructive operations (delete event / contact) are gated identically — no extra force flag, just the same confirmation.

iCloud issues a single app-specific password covering IMAP, SMTP, CalDAV, and CardDAV — there is no scoped "write-only" credential — so write-safety is structural: mail is sent over a separate, fresh SMTP connection (the read path's IMAP client has no send capability), and the opt-in flag + confirmation guard every mutation.

Install

pip install icloud-mcp

Or run it without installing — handy for MCP clients that launch the server on demand:

uvx icloud-mcp

To install the latest unreleased code straight from GitHub:

pip install git+https://github.com/eodozzy/icloud-mcp

Or for local development:

git clone git@github.com:eodozzy/icloud-mcp
cd icloud-mcp
python3 -m venv .venv && .venv/bin/pip install -e ".[test]"

Requires Python 3.11+.

Credentials

Generate an app-specific password for your Apple ID (never use your main password), then store it in your keyring:

# macOS
security add-generic-password -a "you@icloud.com" -s "icloud-mcp" -w "xxxx-xxxx-xxxx-xxxx"

On other platforms, the cross-platform keyring library is used — keyring set icloud-mcp you@icloud.com also works anywhere.

The username comes from the ICLOUD_USERNAME environment variable. Resolution order for the password:

  1. OS keyring (ICLOUD_KEYRING_SERVICE, default icloud-mcp, + username)
  2. ICLOUD_APP_PASSWORD environment variable (fallback)

To reuse an existing keyring entry (e.g. one named my-icloud), set ICLOUD_KEYRING_SERVICE=my-icloud.

Configuration

Set ICLOUD_USERNAME (required). All else is optional — see .env.example for the full list of endpoint/timezone overrides.

Register with an MCP client

The server speaks MCP over stdio: a client launches the icloud-mcp command as a subprocess and talks to it over stdin/stdout. "Installing" it into a client just means telling that client which command to run and which env vars to pass — the password itself stays in the keyring, never in the client config.

If icloud-mcp isn't on your PATH (e.g. you installed into a virtualenv), use the absolute path to the launcher, e.g. /path/to/repo/.venv/bin/icloud-mcp.

Claude Code

claude mcp add icloud \
  --env ICLOUD_USERNAME=you@icloud.com \
  --env ICLOUD_KEYRING_SERVICE=icloud-mcp \
  -- icloud-mcp

Then claude mcp list to confirm. Add -s user to make it available across all projects rather than just the current one.

Claude Desktop

Add the server to Claude Desktop's config file. On macOS this is:

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

(On Windows: %APPDATA%\Claude\claude_desktop_config.json.)

The easiest way to open it is Settings → Developer → Edit Config. Add an mcpServers key alongside whatever is already in the file — do not paste a second top-level { ... } object, or the file becomes invalid JSON:

{
  "mcpServers": {
    "icloud": {
      "command": "icloud-mcp",
      "env": {
        "ICLOUD_USERNAME": "you@icloud.com",
        "ICLOUD_KEYRING_SERVICE": "icloud-mcp"
      }
    }
  }
}

If the file already contains other keys, merge mcpServers in as a sibling (remember the comma between keys):

{
  "someExistingSetting": "...",
  "mcpServers": { "icloud": { "...": "..." } }
}

Then fully quit Claude Desktop (⌘Q, not just closing the window) and reopen it. The server shows up as a Local MCP server and its tools become available.

Notes:

  • First call prompts for Keychain access. macOS asks whether icloud-mcp may read the keyring item; click Always Allow to avoid repeat prompts.
  • Claude Desktop may rewrite this file when it saves its own preferences, dropping hand-added keys it doesn't recognize. If the server disappears after you change other settings, just re-add the mcpServers block.

Tools & resources

Tools (model-invoked):

Tool Description
list_mail List a folder (default INBOX), newest first, with optional since_date
search_mail Full-text search the inbox (or a named folder)
list_folders List the available IMAP mailbox folder names
get_message Fetch one message by UID, with full body
list_events Calendar events in a date window
search_events Events whose title matches text, in a window
list_calendars Names of all calendars
list_contacts List address-book contacts (name, emails, phones, org)
search_contacts Find contacts matching text across name, org, and emails
send_mail ⚠️ Send a plain-text email
reply_mail ⚠️ Reply to a message by UID (quotes original; reply_all optional)
forward_mail ⚠️ Forward a message by UID to a new recipient
create_event ⚠️ Create a calendar event
update_event ⚠️ Edit an event by UID (only the fields you pass)
delete_event ⚠️ Delete an event by UID
create_contact ⚠️ Create a new contact
update_contact ⚠️ Edit a contact by UID (merges into the existing vCard)
delete_contact ⚠️ Delete a contact by UID

⚠️ Write tools require ICLOUD_ENABLE_WRITES=1 and confirm each action — see Writes (opt-in).

Resources (passive context):

URI Description
icloud://mail/inbox/recent Most recent inbox messages
icloud://calendar/today Today + tomorrow's events

Behavior notes

  • Empty/missing headers: messages whose Subject header is absent or present-but-blank render as (no subject); a blank/absent From renders as (unknown). (Some mail has an empty subject line rather than no subject line at all — both are normalized.)
  • Snippets prefer the text/plain part; for HTML-only mail, tags are stripped (<style>/<script>/<head> content discarded) so you still get a readable preview.
  • Double-wrapped bodies: some senders (e.g. USPS Informed Delivery) embed a redundant MIME header block at the top of the decoded body. A leading Content-*/MIME-Version header block is stripped so those headers don't leak into the snippet or body.
  • since_date is date-granular and evaluated in the IMAP server's timezone (UTC for iCloud), so a since_date of today can include late-yesterday messages in your local time.

Development

.venv/bin/pytest            # run the fixture-based test suite (no live account)
.venv/bin/mcp dev -m icloud_mcp.server   # interactive MCP Inspector

Security notes

  • The app-specific password lives in the OS keyring only — never in .env, never committed.
  • Read access (mail, calendar, contacts) cannot mutate anything; the IMAP session is opened read-only.
  • Writes are off by default. They require ICLOUD_ENABLE_WRITES=1 and an interactive confirmation per action, and mail is sent over a separate SMTP connection isolated from the read path.
  • An app-specific password can be revoked at any time from appleid.apple.com without affecting your Apple ID.

License

MIT — see LICENSE.


Not affiliated with, endorsed by, or sponsored by Apple Inc. iCloud is a trademark of Apple Inc.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

icloud_mcp-0.1.1.tar.gz (28.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

icloud_mcp-0.1.1-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

File details

Details for the file icloud_mcp-0.1.1.tar.gz.

File metadata

  • Download URL: icloud_mcp-0.1.1.tar.gz
  • Upload date:
  • Size: 28.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for icloud_mcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 95ecf8a4f32a829b5aeb926f790b4facd6602f044ef8423943cee5da12d8216d
MD5 decbf472f45348d4864f73bda0eaab48
BLAKE2b-256 603b9fbd0b016ceb25b0aa1658ed569c8caee66cfc23efe6314236340d863bbc

See more details on using hashes here.

File details

Details for the file icloud_mcp-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: icloud_mcp-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 24.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for icloud_mcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5ab81dd1965ac080219ee79883cc4f8a8a0980726214a9fed6e4ffa73214f06a
MD5 4d905a36a03bb9f13600a9047f39770f
BLAKE2b-256 2c98c513b7d187f3b02ff3775ff44fa391ebb536f076e0f330b7c8901fb027d9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page