1. 为什么我要给 AI 装上一本真实的日历
AI 能写代码、能查资料、能读本地文件,但每次让它「帮我看看明天下午有没有空」的时候,它只能干瞪眼——因为日历数据在 iCloud 里,而大模型本身碰不到。这个缺口就是 MCP(Model Context Protocol)要补的位置:它给模型一套标准化的工具调用协议,让模型能通过你写好的 Server 去操作外部系统。
我做的这个 iCloud Calendar MCP,就是用 TypeScript 写的一个 MCP Server,底层走 CalDAV 协议直连 Apple iCloud Calendar。接进支持 MCP 的客户端之后,你可以直接用自然语言说「查一下我明天的日程」「明天上午十点建一个 30 分钟的项目讨论」「检查周五下午有没有冲突」,模型会把这些话翻译成对日历的真实读写操作。
它适合谁?如果你是用 Codex、Claude Desktop、Cursor 这类客户端、又希望 AI 助手能真正管理日程的开发者,这套东西就是给你准备的。它不依赖 macOS、不依赖 AppleScript、不依赖 Calendar.app,只要有 Node.js 环境,npx一条命令就能跑起来。下面我把服务端配置骨架、TaoToken 统一 Key 的接入方式,以及用 CalDAV 验证增删改查的完整步骤拆开讲。
2. TaoToken 前置:一把 Key 打通模型通道
MCP Server 负责「操作日历」,但模型本身得有个稳定的调用通道。我这边统一用 TaoToken 来做模型接入层,原因是它把多家模型的 Key 收敛成一套 API 通道,MCP 客户端里不用为每个模型单独配环境变量,换模型只改一个 model 字段。
官网入口在这里:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api (这个地址不加 UTM 参数,直接填进客户端即可)。
你需要先拿到一把 API Key。进控制台创建:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,然后在 API Keys 页面生成:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。生成的 Key 形如sk-开头的一串字符,复制下来,后面配置里会用到。
注意:TaoToken 的 Key 和 iCloud 的应用专用密码是两回事。前者是模型通道凭证,后者是日历访问凭证,两个都要配,但用途完全不同,别混在一个变量里。
如果你打算长期跑编码类或 Agent 类任务,可以看下 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,它更适合高频调用的场景。只是想先验证模型能不能正常对话,用模型对话页试一下就行:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
3. 可复制配置:MCP 服务端骨架与客户端接入
3.1 准备 iCloud 应用专用密码
这一步是整条链路里最容易卡住的地方。iCloud 不接受你的 Apple 账户主密码做第三方 CalDAV 登录,必须生成「应用专用密码」。
打开 Apple ID 账户管理页面,找到「登录与安全」里的「应用专用密码」,生成一个。系统会给你一串形如xxxx-xxxx-xxxx-xxxx的密码,只显示一次,立刻记下来。用户名填你的完整 Apple 账户邮箱,比如you@example.com。
3.2 MCP 客户端配置
在支持 MCP 的客户端里加上这段配置。以通用mcpServers结构为例:
{ "mcpServers": { "icloud-calendar": { "command": "npx", "args": ["-y", "icloud-calendar-mcp"], "env": { "ICLOUD_USERNAME": "you@example.com", "ICLOUD_APP_PASSWORD": "xxxx-xxxx-xxxx-xxxx" } } } }command用npx,args里-y表示自动确认安装,icloud-calendar-mcp就是 npm 上的包名。两个环境变量分别对应 Apple 账户邮箱和应用专用密码。保存后重启客户端,MCP Server 会以 stdio 模式启动。
3.3 模型通道配置
MCP 客户端本身如果支持自定义模型端点,把 TaoToken 的 API 基址和 Key 填进去:
{ "model": "claude-sonnet-4-20250514", "apiKey": "sk-你的TaoToken密钥", "baseURL": "https://taotoken.net/api" }baseURL指向 TaoToken 的 API 通道,apiKey填刚才在控制台生成的 Key。这样模型调用和日历操作就各走各的通道,互不干扰。想换模型只改model字段,Key 不用动。
3.4 项目本身的关键设计
这个 Server 不是简单包一层 CalDAV。日历写入最容易踩的坑是重复创建和并发覆盖,所以项目里做了几件事:用request_id和稳定 UID 降低重复创建风险;用If-None-Match、If-Match和 ETag 做并发控制;本地请求日志和可跨进程复用的事件 handle;超时、指数退避、Retry-After和写后读取;对密码、Authorization、敏感 URL 和事件内容做脱敏。
时区、夏令时、全天事件的语义也单独处理过。对于无法安全完成的重复事件修改,它会返回明确错误,而不是静默把整个系列改错——这点在 RRULE 场景里特别重要。
4. 验证请求:用 CalDAV 跑通日历增删改查
配置好之后,先别急着让 AI 操作,用命令行直接验证 CalDAV 通道是否通。下面用curl走一遍。
4.1 查询日历列表
curl -X PROPFIND https://caldav.icloud.com/ \ -u "you@example.com:xxxx-xxxx-xxxx-xxxx" \ -H "Depth: 1" \ -H "Content-Type: application/xml" \ --data '<?xml version="1.0"?> <d:propfind xmlns:d="DAV:"> <d:prop> <d:displayname/> <d:resourcetype/> </d:prop> </d:propfind>'返回的 XML 里会列出你账户下的所有日历集合,每个日历有一个 URL,形如https://caldav.icloud.com/12345678/calendars/home/。记下你要操作的那个。
4.2 创建一个事件
curl -X PUT "https://caldav.icloud.com/12345678/calendars/home/test-event.ics" \ -u "you@example.com:xxxx-xxxx-xxxx-xxxx" \ -H "Content-Type: text/calendar; charset=utf-8" \ -H "If-None-Match: *" \ --data 'BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Test//Test//EN BEGIN:VEVENT UID:test-event-001 DTSTAMP:20250601T000000Z DTSTART:20250602T020000Z DTEND:20250602T023000Z SUMMARY:项目讨论 END:VEVENT END:VCALENDAR'If-None-Match: *是关键,它保证只有资源不存在时才创建,避免重复写入。返回201 Created就说明事件建好了。
4.3 查询事件
curl -X REPORT "https://caldav.icloud.com/12345678/calendars/home/" \ -u "you@example.com:xxxx-xxxx-xxxx-xxxx" \ -H "Depth: 1" \ -H "Content-Type: application/xml" \ --data '<?xml version="1.0"?> <c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav"> <d:prop> <d:getetag/> <c:calendar-data/> </d:prop> <c:filter> <c:comp-filter name="VCALENDAR"> <c:comp-filter name="VEVENT"/> </c:comp-filter> </c:filter> </c:calendar-query>'返回里能看到刚建的事件,同时带一个 ETag。这个 ETag 后面更新和删除都要用。
4.4 更新与删除
更新时带上If-Match和上一步拿到的 ETag:
curl -X PUT "https://caldav.icloud.com/12345678/calendars/home/test-event.ics" \ -u "you@example.com:xxxx-xxxx-xxxx-xxxx" \ -H "Content-Type: text/calendar; charset=utf-8" \ -H "If-Match: \"上一步的ETag值\"" \ --data '...更新后的ICS内容...'删除则用 DELETE,同样带If-Match:
curl -X DELETE "https://caldav.icloud.com/12345678/calendars/home/test-event.ics" \ -u "you@example.com:xxxx-xxxx-xxxx-xxxx" \ -H "If-Match: \"上一步的ETag值\""返回204 No Content就删掉了。这四步跑通,说明 CalDAV 通道完全可用,MCP Server 里的逻辑就是把这套流程封装成工具调用。
4.5 让 AI 真正操作
回到 MCP 客户端,重启后直接说「查一下我明天的日程」。模型会调用 Server 暴露的查询工具,走上面 REPORT 那套逻辑,把结果整理成自然语言返回。再说「明天上午十点创建一个 30 分钟的项目讨论」,它会走 PUT 逻辑建事件。整个过程你不需要碰 ICS 格式,模型帮你翻译。
5. 本篇常见错排查
401 Unauthorized:九成是密码问题。确认用的是应用专用密码而不是 Apple 账户主密码,且用户名是完整邮箱。应用专用密码生成后如果没记下来,只能重新生成一个。
403 Forbidden:通常是日历 URL 不对。iCloud 的日历集合 URL 里带一串数字 ID,必须从 PROPFIND 返回结果里取,不能自己拼。
412 Precondition Failed:ETag 不匹配。说明你手里的 ETag 过期了,资源在别处被改过。重新 REPORT 一次拿最新 ETag 再操作。
重复创建事件:检查 PUT 时有没有带If-None-Match: *。不带的话,同一个 UID 可能被写多次。
时区错乱:ICS 里的时间用 UTC(Z结尾),本地时间要自己换算。全天事件用VALUE=DATE格式,别混用。
MCP 客户端连不上 Server:先确认npx -y icloud-calendar-mcp能单独跑起来,再检查客户端配置里的env有没有正确传入。stdio 模式下 Server 的日志会打到 stderr,客户端一般能看到。
模型通道报错:检查 TaoToken 的 Key 和baseURL是否配对,baseURL结尾不要多加斜杠。接入文档在这里:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
6. 把日历交给 AI 之后
跑通这套之后,我日常的用法是早上让 AI 汇总当天日程,开会前让它检查冲突,临时改期直接说一句话。它不会替你决定日程,但把「查、建、改、删」这些机械操作接过去了。
如果你在排障或接入阶段卡住,先去 API Keys 页面确认 Key 状态:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,再对照接入文档核对参数:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。想先验证模型通道是否正常,用模型对话页发一条消息试试:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。长期跑编码或 Agent 任务的话,Coding Plan 更划算:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
项目已经发布到 npm 和 Official MCP Registry,npx -y icloud-calendar-mcp就能用。日历这种每天都要碰的东西,交给 AI 管起来之后,确实省心不少。