stdio MCP server for iCloud Calendar (CalDAV), with optional Contacts (CardDAV) and Mail (IMAP/SMTP)
git clone https://github.com/ThomasCrouzet/icloud-mcp{
"mcpServers": {
"icloud-mcp": {
"command": "icloud-mcp",
"env": {
"ICLOUD_PASSWORD": "<icloud_password>",
"ICLOUD_MAIL_PASSWORD": "<icloud_mail_password>"
}
}
}
}ICLOUD_PASSWORDICLOUD_MAIL_PASSWORDMCP Servers overview
# icloud-mcp
[](https://github.com/ThomasCrouzet/icloud-mcp/actions/workflows/ci.yml)
[](https://github.com/ThomasCrouzet/icloud-mcp/releases)
[](LICENSE)
Unified **Apple/iCloud** MCP server for **Calendar, Contacts, and Mail**: one
static Go binary, [Model Context Protocol](https://modelcontextprotocol.io)
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](#supported-scope).
## Quick start
```bash
go install github.com/ThomasCrouzet/icloud-mcp/cmd/icloud-mcp@latest
# or: make build
# or: make release VERSION=v0.4.0
# or: make release-all VERSION=v0.4.0
```
1. Create an [app-specific password](https://appleid.apple.com) (never the main
Apple Account password).
2. Export a minimal environment (recommended first deploy: Calendar **read-only**):
```bash
export ICLOUD_EMAIL='you@icloud.com'
export ICLOUD_PASSWORD='your-app-specific-password'
export ICLOUD_MCP_READ_ONLY=true
export ICLOUD_MCP_DEFAULT_TZ=Europe/Paris # owner IANA zone; default UTC
```
3. Register **command** = absolute path to `icloud-mcp` and this **env** in your
MCP host (YAML, JSON, TOML, UI, or orchestrator; format is host-specific).
4. Stdio = JSON-RPC; **stderr** = logs and mutation audit. Reload the host after
env changes.
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):
```bash
# Contacts reads (writes also need ICLOUD_MCP_READ_ONLY=false)
export ICLOUD_MCP_ENABLE_CONTACTS=true
# Mail reads: IMAP identity may differ from ICLOUD_EMAIL (e.g. name@icloud.com)
export ICLOUD_MCP_ENABLE_MAIL=true
export ICLOUD_MAIL_ADDRESS='mailbox@icloud.com'
# export ICLOUD_MAIL_PASSWORD='...' # optional; else copy of ICLOUD_PASSWORD
# Mail mutation (flags / move / trash); independent of send
export ICLOUD_MCP_ENABLE_MAIL_WRITE=true
export ICLOUD_MCP_READ_ONLY=false
# Mail send: requires exact recipient allowlist even under global read-only
export ICLOUD_MCP_ENABLE_MAIL_SEND=true
export ICLOUD_MCP_SMTP_ALLOWED_RECIPIENTS='alice@example.com,bob@example.net'
```
Boot-only `file://` secrets (regular files only, at most 4 KiB, mode 0600 or
stricter; never re-read after start):
```bash
export ICLOUD_EMAIL='file:///run/secrets/icloud-email'
export ICLOUD_PASSWORD='file:///run/secrets/icloud-password'
export ICLOUD_MAIL_ADDRESS='file:///run/secrets/icloud-mail-address'
export ICLOUD_MAIL_PASSWORD='file:///run/secrets/icloud-mail-password'
```
See [.env.example](.env.example) for the full 12-variable contract.
## MCP tools
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/caldav-compatibility.md),
[docs/carddav-compatibility.md](docs/carddav-compatibility.md),
[docs/mail-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](docs/error-codes.md).
## Configuration
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).
### Dates
- Calendar **input** `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`.
- Calendar **output**: timed events always use RFC3339 with an explicit numeric
offset in `ICLOUD_MCP_DEFAULT_TZ` (never bare `Z`). All-day dates are
`YYYY-MM-DD`. See `calendar_capabilities.outputFormat`.
- Contacts birthdays: write `YYYY-MM-DD` only.
- Mail search: `since` inclusive, `before` exclusive (`YYYY-MM-DD`).
Agent error codes and retry policy: [docs/error-codes.md](docs/error-codes.md).
Host wiring examples: [docs/agent-hosts.md](docs/agent-hosts.md). Product roadmap:
[ROADMAP.md](ROADMAP.md).
## Security (summary)
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.
- **Egress fixed:** Calendar `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.
- **Isolation:** separate credentials, transports/dialers, limiters, semaphores,
and protocol stacks per domain; no union authenticated HTTP client.
- **Secrets:** redacted (including Basic and SASL PLAIN forms); boot-only
`file://` reads require mode 0600 or stricter;What people ask about icloud-mcp
What is ThomasCrouzet/icloud-mcp?
+
ThomasCrouzet/icloud-mcp is mcp servers for the Claude AI ecosystem. stdio MCP server for iCloud Calendar (CalDAV), with optional Contacts (CardDAV) and Mail (IMAP/SMTP) It has 1 GitHub stars and was last updated today.
How do I install icloud-mcp?
+
You can install icloud-mcp by cloning the repository (https://github.com/ThomasCrouzet/icloud-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is ThomasCrouzet/icloud-mcp safe to use?
+
ThomasCrouzet/icloud-mcp has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.
Who maintains ThomasCrouzet/icloud-mcp?
+
ThomasCrouzet/icloud-mcp is maintained by ThomasCrouzet. The last recorded GitHub activity is from today, with 0 open issues.
Are there alternatives to icloud-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy icloud-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/thomascrouzet-icloud-mcp)<a href="https://claudewave.com/repo/thomascrouzet-icloud-mcp"><img src="https://claudewave.com/api/badge/thomascrouzet-icloud-mcp" alt="Featured on ClaudeWave: ThomasCrouzet/icloud-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!