关于 iCloud Calendar (CalDAV)
iCloud Calendar (CalDAV) 是供 MCP 客户端管理 iCloud 日历的 MCP 服务,支持 Linux、macOS 和 Windows。它通过 iCloud CalDAV 列出和编辑事件,并可选择只读模式。
主要功能
- 01列出日历及日期范围内的事件
- 02创建和更新事件
- 03在日历间移动事件
- 04按标识符删除事件
- 05可选只读模式
适用场景
- 01查看多个 iCloud 日历中的事件
- 02创建或修改日历条目
- 03将事件移至其他日历
- 04让客户端只读访问日历
MCP 相关
该服务通过 stdio 向 MCP 客户端提供日历和事件工具,以及日历列表资源。只读模式会移除创建、更新和删除事件的工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx mcp-icloud-caldavICLOUD_USERNAMEApple ID email addressICLOUD_PASSWORD密钥App-specific password from appleid.apple.com (not the Apple ID password)MCP_ICAL_READ_ONLYSet to true to leave out the create, update and delete toolsMCP_ICAL_LOG_LEVELLog level on stderr: TRACE, DEBUG, INFO, WARNING or ERROR本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
6收录的工具列表 · 更新于 3 周前
此工具无需参数。
详细介绍
iCloud Calendar MCP 服务
一个 Model Context Protocol 服务,让 MCP 客户端能够通过 CalDAV 访问 iCloud Calendar:列出日历、读取、创建、更新、移动和删除事件。它可在 Linux、macOS 和 Windows 上运行,因为它直接与 iCloud 通信,而不是通过 macOS Calendar 应用。
这是 zwrong/iCalendar 的维护分支,而后者源自 macOS 的 mcp-ical 服务。请参阅此分支中的更改。
工具
| 工具 | 说明 |
|---|---|
list_calendars | 可用日历的名称 |
list_events | 指定日期范围内的事件,可选指定一个日历,并按开始时间排序 |
create_event | 新建事件:标题、时间、全天、地点、备注、URL、提醒、重复规则 |
update_event | 更改上述任意字段,或将事件移动到其他日历 |
delete_event | 按标识符删除事件 |
debug_calendar_connection | 检查连接:列出日历及过去 7 天的事件数量 |
calendars://list 资源也会列出日历。设置 MCP_ICAL_READ_ONLY=true 后,三个写入工具将不会注册。
要求
- Python 3.12 或更高版本,以及 uv
- 已启用 iCloud Calendar 的 Apple ID
- 该 Apple ID 的专用 App 密码
专用 App 密码
- 登录 appleid.apple.com,打开登录与安全,然后选择专用 App 密码。
- 生成一个密码,例如命名为
mcp-icloud-caldav。
用户名是你的 Apple ID 地址,不一定是 @icloud.com 地址。
专用 App 密码可用于访问 iCloud CalDAV、CardDAV 和 IMAP:请勿将其纳入版本控制;如果密码泄露,请撤销。
安装
此软件包以 mcp-icloud-caldav 的名称发布在 PyPI 上。使用 uv 时,MCP 客户端可以直接启动它,无需单独安装:
uvx mcp-icloud-caldav
首次使用时,uvx 会将软件包下载到缓存的隔离环境中。如需永久安装:
uv tool install mcp-icloud-caldav(或 pipx install mcp-icloud-caldav)。
从源代码安装:
git clone https://github.com/Glob0x17/mcp-icloud-caldav.git mcp-icloud-caldav
cd mcp-icloud-caldav
uv sync --no-dev
uv run mcp-icloud-caldav
配置
凭据按以下顺序读取:
-
环境变量(推荐)
变量 必需 默认值 ICLOUD_USERNAME是 ICLOUD_PASSWORD是 CALDAV_SERVER_URL否 https://caldav.icloud.com/ -
MCP_ICAL_CONFIG:JSON 文件的路径,其结构如config.json.example -
仓库根目录下的
config_private.json,然后是config.json(为保持兼容而保留)
其他设置:
| 变量 | 默认值 | 作用 |
|---|---|---|
MCP_ICAL_READ_ONLY | false | 设为 true 时,不包含 create_event、update_event 和 delete_event |
MCP_ICAL_LOG_LEVEL | INFO | TRACE、DEBUG、INFO、WARNING 或 ERROR。日志输出到 stderr |
该服务通过 stdio 使用 MCP,并由客户端启动。要手动检查:
[email protected] ICLOUD_PASSWORD=xxxx-xxxx-xxxx-xxxx uvx mcp-icloud-caldav
它会等待 stdin 输入,且不会向 stdout 输出任何内容。
客户端设置
如果客户端找不到 uvx,请使用它的绝对路径(which uvx):客户端通常会在不包含你 shell PATH 的环境中启动服务,因此会出现 spawn uvx ENOENT。常见路径:
| 安装方式 | 路径 |
|---|---|
| uv 安装程序(Linux、macOS) | ~/.local/bin/uvx |
| Apple 芯片上的 Homebrew | /opt/homebrew/bin/uvx |
| Intel Mac 上的 Homebrew | /usr/local/bin/uvx |
命令和参数是分开的字段:命令是 uvx(或它的路径),而 mcp-icloud-caldav 是参数。如果配置中的命令是单个字符串 "uvx mcp-icloud-caldav",就会因 ENOENT 而失败,因为客户端会查找名称完全相同(包括空格)的程序。
避免在客户端配置中明文保存密码
大多数客户端会将 env 值以明文形式存储在配置文件中。使用一个读取环境变量文件的小型包装脚本即可避免这种情况:
mkdir -p ~/.config/mcp-icloud-caldav && chmod 700 ~/.config/mcp-icloud-caldav
cat > ~/.config/mcp-icloud-caldav/env <<'EOF'
[email protected]
ICLOUD_PASSWORD=xxxx-xxxx-xxxx-xxxx
MCP_ICAL_READ_ONLY=true
EOF
chmod 600 ~/.config/mcp-icloud-caldav/env
cat > ~/.local/bin/mcp-icloud-caldav-run <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
set -a; source "$HOME/.config/mcp-icloud-caldav/env"; set +a
exec /absolute/path/to/uvx mcp-icloud-caldav
EOF
chmod +x ~/.local/bin/mcp-icloud-caldav-run
然后让客户端指向 ~/.local/bin/mcp-icloud-caldav-run。先以只读模式启动,确认读取正常后再切换为 false,是个稳妥的第一步。
Claude Desktop
在 claude_desktop_config.json 中配置(Settings、Developer、Edit Config)。在 macOS 上,文件路径为
~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"icloud-calendar": {
"command": "uvx",
"args": ["mcp-icloud-caldav"],
"env": {
"ICLOUD_USERNAME": "[email protected]",
"ICLOUD_PASSWORD": "xxxx-xxxx-xxxx-xxxx"
}
}
}
}
或者,使用包装脚本时,设置 "command": "/home/you/.local/bin/mcp-icloud-caldav-run",且不设置 env。编辑后,请完全退出 Claude Desktop 并重新启动。在 macOS 上,服务日志位于
~/Library/Logs/Claude/mcp-server-icloud-calendar.log。
Claude Code
claude mcp add --scope user icloud-calendar \
-e [email protected] -e ICLOUD_PASSWORD=xxxx-xxxx-xxxx-xxxx \
-- uvx mcp-icloud-caldav
或者,使用包装脚本时,运行 claude mcp add --scope user icloud-calendar -- ~/.local/bin/mcp-icloud-caldav-run。
不要给 -- 后面的内容加引号:-- uvx mcp-icloud-caldav 会将 uvx 注册为命令,并将 mcp-icloud-caldav 注册为参数;而 -- "uvx mcp-icloud-caldav" 会将两者注册为一个程序名,并因 ENOENT 而失败。要修复已有条目,请运行 claude mcp remove icloud-calendar --scope user 将其移除,然后重新添加。
在会话中运行 /mcp 可查看服务状态及其工具;运行 claude mcp get icloud-calendar 可查看已注册的命令和参数。
其他客户端
任何能够启动 stdio 服务的 MCP 客户端都可使用:运行 uvx mcp-icloud-caldav,并设置上述环境变量。该服务也已列入 MCP Registry,名称为
io.github.Glob0x17/mcp-icloud-caldav。
需要了解的行为
- 时间。 事件时间以 UTC 写入。带有时区偏移的时间(
2030-01-07T09:30:00+01:00)会进行转换,不带偏移的时间则视为机器的本地时间。显示时间时会使用机器的时区。全天事件以日期形式写入,并按照 iCalendar 标准将结束日期设为不包含在内。 - 在日历之间移动。 iCloud 不允许同一个事件 UID 出现在两个日历中,因此移动不能采用“先复制再删除”的方式。
update_event使用calendar_name时会执行 WebDAVMOVE,这在服务端是原子操作:如果操作失败,事件仍保留在原处。不进行其他更改的移动会保留原始 iCalendar 数据不变。 - 查找事件。 列表操作会填充一个内存索引(UID 到 URL 的映射),该索引的生命周期与服务进程相同。之后查找会直接访问事件;如果找不到,则会回退到 iCloud 用于大多数事件的
<calendar>/<UID>.icsURL,最后才扫描所有日历。iCloud 不支持 CalDAV UID 搜索。 - 数量。 iCloud 每次请求返回的事件数量不限。实际限制在于客户端:许多客户端会将工具结果限制在约 25,000 个 token,也就是此服务输出中的约 300 个事件,因此较长的时间范围应分开查询。
- 范围。 只能查看托管在 iCloud 上的日历。通过设备上的 Calendar 应用添加的 Exchange、Google 或其他账户无法通过 iCloud CalDAV 访问,订阅的只读(ICS)日历也无法访问。
隐私与安全
- 唯一的网络目标是已配置的 CalDAV 服务;不会收集遥测数据。
- 密码绝不会出现在任何级别的日志中,也不会出现在配置对象的
repr中。 - 日志仅写入 stderr,因为 stdout 用于 MCP 协议。事件内容(标题、备注)仅在
DEBUG或更低级别记录;在INFO级别,仅记录标识符。有些客户端会将服务的 stderr 保存到磁盘,因此排查问题时请使用DEBUG。 - 依赖项已锁定在
uv.lock中,且仅从官方 PyPI 索引解析。
故障排除
| 症状 | 可能原因 |
|---|---|
401 Unauthorized | 使用了普通 Apple ID 密码,而不是专用密码,或者专用密码已被撤销 |
spawn uvx ENOENT 或 ENOENT | 客户端的 PATH 中没有 uvx(请使用其绝对路径),或者命令和参数被注册成了一个字符串(参见客户端配置) |
| 未返回事件 | 日期范围错误、事件位于非 iCloud 日历或订阅日历中,或者时区混用 |
| 服务没有响应 | 有内容写入 stdout,破坏了 stdio 协议 |
Calendar 'X' not found | 日历名称区分大小写:请检查 list_calendars |
debug_calendar_connection 和 MCP_ICAL_LOG_LEVEL=DEBUG 有助于缩小问题范围。
开发
uv sync
uv run pytest -m "not integration" # unit tests, CalDAV client mocked, no network
uv run ruff check .
集成测试会对真实账户执行只读操作,且仅在设置了凭据时运行:
ICLOUD_USERNAME=... ICLOUD_PASSWORD=... uv run pytest -m integration
项目结构:
mcp_icloud_caldav/
├── server.py # MCP server, tool registration, logging setup
├── caldav_client.py # CalDAV access: search, create, update, move, delete, event index
├── ical.py # Thin calendar manager used by the server
├── models.py # Event and request models, iCalendar parsing
└── config.py # Configuration loading
tests/ # Unit tests
tests/integration/ # Read-only tests against a real account
此分支中的更改
0.2.1:仅更新文档(uvx 路径、ENOENT 原因、macOS 上的客户端路径)。
0.2.0,与 zwrong/iCalendar 0.1.0 相比:
- 依赖项。 从官方 PyPI 索引重新生成锁文件(之前通过纯 HTTP 的第三方镜像解析软件包)。升级到
mcp2.x(FastMCP更名为MCPServer)和caldav3.x;原始代码已无法在当前版本上启动。 - 配置。 支持环境变量、
MCP_ICAL_CONFIG、只读模式、可配置的日志级别,并且在高于DEBUG的级别下不记录事件内容。 - 修复。
- 创建带时区偏移的事件时会失败(
Unable to guess TZID);全天事件和重复事件结束日期的写入也不正确。 - 闹钟从未被读回。
- 更新不含位置、备注或 URL 的事件时会失败;修改事件时间会生成无效的 iCalendar 数据。
- 移动事件时,会在保存副本前删除原事件,因此保存失败会导致事件丢失。
- 新事件的 UID 中包含空格和机器的主机名。
- 创建带时区偏移的事件时会失败(
- 行为。 按开始时间对事件排序;输出精简,不含空字段;使用内存中的事件索引。
- 测试。 为配置、只读模式、日志记录、iCalendar 输出、移动操作和查找添加单元测试。
- 打包。 以
mcp-icloud-caldav的名称发布到 PyPI,并列入 MCP Registry。Python 软件包和命令从mcp_ical/mcp-ical更名,以避免与原始 macOS 项目冲突。移除了未使用的mcp[cli]extra。
致谢与许可证
MIT,详见 LICENSE。
- 原始 macOS
mcp-ical服务(Omar D.),其版权声明保留在LICENSE中 - zwrong/iCalendar,此分支基于该 iCloud CalDAV 移植版本构建
- python-caldav 和 Model Context Protocol Python SDK
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。