icloud-mcp

icloud-mcp

Unified Apple/iCloud MCP server for Calendar, Contacts, and Mail using CalDAV, CardDAV, IMAP, and SMTP protocols with app-specific passwords.

Category
访问服务器

README

icloud-mcp

CI Release License: MIT

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.

Quick start

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 (never the main Apple Account password).
  2. Export a minimal environment (recommended first deploy: Calendar read-only):
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
  1. Register command = absolute path to icloud-mcp and this env in your MCP host (YAML, JSON, TOML, UI, or orchestrator; format is host-specific).
  2. 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):

# 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):

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

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. Host wiring examples: docs/agent-hosts.md. Product roadmap: 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; no os/exec, telemetry, or disk write after boot.
  • Audit: mutations log domain, resourceType, process-local HMAC resourceToken only (never raw paths, UIDs, mailboxes, recipients).
  • Residual risk: one process holds every enabled domain's credentials; feature flags do not remove compiled code. Prefer read-only, least domains, dedicated Mail password, or separate processes when stronger isolation is required.

Full policy: SECURITY.md, docs/security.md. Architecture: docs/architecture.md.

Limits (summary)

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
Mail 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.

Supported scope

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.

Dependencies

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

Build and test

make build        # local host binary, VERSION defaults to dev
make test         # go test ./... -race -cover
make lint         # go vet + pinned golangci-lint
make release VERSION=v0.4.0      # packaged linux/arm64, digest-pinned Go 1.25.12 image
make release-all VERSION=v0.4.0  # packaged linux/amd64, linux/arm64, darwin/arm64 (host Go)
make install      # host-compatible build to INSTALL_DIR (default ~/.local/bin)

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.

Attribution

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.

Contributing

See CONTRIBUTING.md. Run gofmt, make test, and make lint before opening a pull request.

License

MIT. See LICENSE and third-party notices.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选