stdio MCP for iCloud Calendar (CalDAV), with optional Contacts and Mail.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent — or use 1-click editor setup below.
💡 Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Unified Apple/iCloud MCP server for Calendar, Contacts, and Mail: one static Go binary, Model Context Protocol JSON-RPC on stdio.
Remote protocols only (CalDAV, CardDAV, IMAP, SMTP with app-specific
passwords). Not macOS EventKit, AppleScript, browser automation, or a private
Apple API. Runs headless on Linux and macOS; pure Go also builds for Windows
(CI smoke-builds windows/amd64; GitHub Release archives ship linux/amd64,
linux/arm64, and darwin/arm64). Suitable for agents and orchestration, not only
a desktop chat app.
Host-agnostic. Any MCP client that can spawn a child with an environment and
wire stdin/stdout works: personal agents, Hermes, OpenClaw, IDE bridges,
runners, or other stdio hosts. No preferred model vendor, chat product, or
reseller. Configuration is the process environment only; the binary does not
parse host-specific config files or .env.
| Domain | Protocol | Default |
|---|---|---|
| Calendar | CalDAV HTTPS | Always on (read + write unless global read-only) |
| Contacts | CardDAV HTTPS | Off until ICLOUD_MCP_ENABLE_CONTACTS |
| Mail read | IMAP TLS | Off until ICLOUD_MCP_ENABLE_MAIL |
| Mail mutation | IMAP | Off until Mail + ICLOUD_MCP_ENABLE_MAIL_WRITE |
| Mail send | SMTP STARTTLS | Off until Mail + ICLOUD_MCP_ENABLE_MAIL_SEND + recipient policy |
Reminders, Notes, Photos, Drive, Messages, and similar apps are out of scope until Apple documents a suitable remote third-party connector. Details: Supported scope.
icloud-mcp and this env in your
MCP host (YAML, JSON, TOML, UI, or orchestrator; format is host-specific).With that config the process exposes 7 tools (Calendar reads + local
helpers + icloud_capabilities). No Contacts or Mail client is constructed.
Optional domains (still host-agnostic export form):
Boot-only file:// secrets (regular files only, at most 4 KiB, mode 0600 or
stricter; never re-read after start):
See .env.example for the full 12-variable contract.
Maximum 23 tools. Disabled tools are absent from tools/list; disabled
domain clients are not constructed.
| Count | When |
|---|---|
| 10 | Default: Calendar read+write + icloud_capabilities |
| 7 | Global read-only, optional domains off (recommended first run) |
| 23 | Contacts + Mail read + mutation + send, read-only off |
ICLOUD_MCP_READ_ONLY=true removes every Calendar/Contacts write, every Mail
mutation, and Mail send. It does not enable a disabled read domain.
| Group | Tools |
|---|---|
| Global | icloud_capabilities |
| Calendar read | list_calendars, search_events, get_event, find_free_slots, validate_event, calendar_capabilities |
| Calendar write | create_event, update_event, delete_event |
| Contacts read | list_address_books, search_contacts, get_contact |
| Contacts write | create_contact, update_contact, delete_contact |
| Mail read | list_mailboxes, search_messages, get_message |
| Mail mutation | set_message_flags, move_message, trash_message |
| Mail send | send_message |
Highlights: occurrence-aware Calendar update/delete with strong If-Match;
Contacts opaque book IDs and vCard 3.0 writes; Mail identity
(mailbox, UIDVALIDITY, UID), PEEK reads, SMTP exact-recipient policy.
set_message_flags fails closed with protocol_error when CONDSTORE is
advertised and tagged MODIFIED cannot be observed (go-imap beta.8). Full
behavior notes: docs/caldav-compatibility.md,
docs/carddav-compatibility.md,
docs/mail-compatibility.md.
Idempotency: create_event / create_contact use server-side UID keys
(client_uid or alias idempotency_key): a repeat create conflicts if the UID
already exists (never silent overwrite). update_event / update_contact
optional idempotency_key is process-local only (in-memory cache, 15
minute TTL, cleared on process restart). Same key + same params returns the
cached success; same key + different params is conflict. Prefer combining
update keys with a strong etag. See docs/error-codes.md.
Exactly 12 product environment variables:
| Variable | Default | Contract |
|---|---|---|
ICLOUD_EMAIL | none | Required Calendar/Contacts identity. file:// supported (regular file, <=4 KiB, mode 0600+). |
ICLOUD_PASSWORD | none | Required app-specific password; Mail fallback. file:// as above. |
ICLOUD_MCP_READ_ONLY | false | Global mutation kill switch. |
ICLOUD_MCP_LOG_LEVEL | info | Stderr level; accepted forms are documented below. |
ICLOUD_MCP_DEFAULT_TZ | UTC | IANA zone for offset-less Calendar inputs and recurring-write fallback. |
ICLOUD_MCP_ENABLE_CONTACTS | false | Contacts tools; writes only if not read-only. |
ICLOUD_MCP_ENABLE_MAIL | false | Mail reads; requires Mail address/password. |
ICLOUD_MAIL_ADDRESS | none | Full IMAP/SMTP address when Mail is on. file:// as above. |
ICLOUD_MAIL_PASSWORD | ICLOUD_PASSWORD | Optional dedicated Mail app password. file:// as above. |
ICLOUD_MCP_ENABLE_MAIL_WRITE | false | Three IMAP mutation tools. |
ICLOUD_MCP_ENABLE_MAIL_SEND | false | send_message (independent of Mail write). |
ICLOUD_MCP_SMTP_ALLOWED_RECIPIENTS | none | Required if send requested: exact addresses, or literal * (boot warning; prefer exact). |
Booleans accept only unset, 0, false, 1, or true. Invalid values fail at
boot. Config is validated before any network access: Mail write/send without
Mail, Mail without address/password, or send without recipient policy are boot
errors (including under read-only for the send policy). Global read-only can
coexist with write/send flags but suppresses their registration.
Log levels are trimmed and case-insensitive: debug/-4, info,
warn/warning/2, and error/4. Unset or unrecognized values use info.
Flags: -version; optional -health 127.0.0.1:port (loopback-only /healthz
and /status JSON with domains and rate limits); optional
-audit-format=json|text (default json mutation audit on stderr).
start/end: RFC3339 with offset, or wall clock without
offset in ICLOUD_MCP_DEFAULT_TZ. Prefer no-offset for the user's local time.
Recurring or explicit-timezone creates write TZID + VTIMEZONE; non-recurring
timed defaults to UTC Z on the wire. All-day uses VALUE=DATE.ICLOUD_MCP_DEFAULT_TZ (never bare Z). All-day dates are
YYYY-MM-DD. See calendar_capabilities.outputFormat.YYYY-MM-DD only.since inclusive, before exclusive (YYYY-MM-DD).Agent error codes and retry policy: docs/error-codes.md. Host wiring examples: docs/agent-hosts.md. Product roadmap: ROADMAP.md.
Untrusted remote text can influence an LLM on the host; labels are not a boundary. A compromised model can call every registered tool. Same model for every host and vendor.
caldav.icloud.com / p[0-9]{1,3}-caldav.icloud.com:443;
Contacts matching contacts hosts; IMAP imap.mail.me.com:993; SMTP
smtp.mail.me.com:587 with mandatory STARTTLS. No configurable destinations,
no proxy env for DAV, TLS 1.2+ verified.file:// reads require mode 0600 or stricter; no os/exec, telemetry, or
disk write after boot.domain, resourceType, process-local HMAC
resourceToken only (never raw paths, UIDs, mailboxes, recipients).Full policy: SECURITY.md, docs/security.md. Architecture: docs/architecture.md.
| Tool deadline | 25s (DAV HTTP 30s) |
| Stdio / MCP result | 1 MiB frame; 256 KiB result; reflected protocol errors capped |
| Calendar | 366-day search; 400 returned / 2,500 per calendar / 10,000 multi-calendar materialization; 2,000 expansions / 100k steps per series / 250k steps per search; 60 read / 20 write per minute; concurrency 4 / 2 |
| Contacts | 100 books; 100 summaries; 2000 cards scanned; 60/20 per minute; concurrency 4 |
| 60 read / 20 mutation / 20 send per minute; semaphores 2 / 1 / 1; no mutation/send retry | |
| Writes | No automatic replay of Calendar PUT/DELETE, Contacts writes, IMAP mutations, or SMTP; ambiguous outcomes use outcome_unknown |
Lifecycle: eager Calendar discovery at boot; lazy Contacts discovery; fresh IMAP/SMTP session per call. Rates, XML/iCal/vCard/MIME budgets, and retry rules: docs/testing.md, docs/architecture.md.
| Data | Connector | Support |
|---|---|---|
| Calendar | CalDAV | Always |
| Contacts | CardDAV | Optional |
| Mail read / mutation / send | IMAP + SMTP | Optional, independently gated |
| Modern Reminders, Notes, Photos, Drive, Find My, Keychain, Messages, Home | No suitable official remote connector for this model | Excluded |
Modern Reminders are not treated as generic CalDAV VTODO. Apple's third-party documentation for this class of access covers Mail, Calendar, and Contacts.
Multi-account: one process holds one iCloud identity. Spawn separate
icloud-mcp processes (distinct env, optional distinct -health ports) and let
the MCP host multiplex them. See docs/agent-hosts.md.
Go 1.25.12 or newer, one module, exactly 10 direct dependencies. Adding another requires a written justification here.
| Dependency | Exact version | Justification |
|---|---|---|
github.com/emersion/go-webdav | v0.7.0 | CalDAV primitives; discovery and conditional ops stay hand-rolled |
github.com/emersion/go-ical | v0.0.0-20250609112844-439c63cef608 | iCalendar parse/encode |
github.com/mark3labs/mcp-go | v0.57.0 | MCP stdio, schemas, JSON-RPC |
github.com/teambition/rrule-go | v1.8.2 | Bounded recurrence with timezone preservation |
golang.org/x/time | v0.15.0 | Per-domain rate limiters |
github.com/emersion/go-vcard | v0.0.0-20260618161152-d854b7e0e2d3 | vCard 3.0/4.0 read, 3.0 write |
github.com/emersion/go-imap/v2 | v2.0.0-beta.8 | IMAP behind internal/mail/imapadapter |
github.com/emersion/go-message | v0.18.2 | MIME / plain-text bounds |
github.com/emersion/go-smtp | v0.24.0 | SMTP + STARTTLS |
github.com/emersion/go-sasl | v0.0.0-20241020182733-b788ff22d5a6 | SASL PLAIN after STARTTLS |
Release targets reject an unset or dev version. Archives contain the binary,
LICENSE, and THIRD_PARTY_NOTICES.md; dist/ also receives a SHA-256
checksum file. GitHub tag releases run make release-all only after CI and
gitleaks succeed on that tag, with Go pinned to 1.25.12 (check-latest
disabled). Local make release remains the digest-pinned container path for
linux/arm64. Cosign keyless signatures are attached to release blobs. -version
prefers the release ldflags value and falls back to Go module build information,
so go install ...@version reports that module version.
CI: race tests, coverage floors (78% aggregate + package floors including
cmd/icloud-mcp and internal/health), fuzz smoke, govulncheck, multi-arch
build (plus windows/amd64 smoke), egress/security AST guards, gitleaks, 20 MiB
binary budget, public-text policy on tree and new commits. Live iCloud tests use
the integration build tag, are opt-in, and never run in CI. See
docs/testing.md.
Calendar tool shape and several patterns were inspired by
github.com/roygabriel/mcp-icloud-calendar
(MIT, copyright 2026 Gabe). Code was rewritten, not copied. This server adds
hard per-domain egress, redaction, bounded parsers, conditional mutation,
Contacts, Mail, and no telemetry.
See CONTRIBUTING.md. Run gofmt, make test, and make lint
before opening a pull request.
MIT. See LICENSE and third-party notices.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/icloud-mcp-2)<a href="https://allmcps.com/mcp/icloud-mcp-2"><img src="https://allmcps.com/api/badge/icloud-mcp-2?style=directory" alt="Icloud Mcp on AllMCPs" /></a>