关于 Apple Calendar
Apple Calendar 是面向 macOS 的 MCP 服务,通过 EventKit 提供日历与事件操作,适用于日程管理工作流。它支持安全模式、日历范围限制,并在特定情况下提供自动化读取回退。
主要功能
- 01发现并列出日历
- 02创建、读取、更新和删除事件
- 03提供今日资源与规划提示词
- 04日历访问健康检查与权限恢复
- 05支持安全模式和日历允许列表
适用场景
- 01查询会议和预约安排
- 02创建或修改日程事件
- 03限制 Agent 可访问或写入的日历
MCP 相关
该 MCP 服务向 MCP 客户端提供日历、事件及相关资源和提示词。默认使用 stdio,也可配置为 Streamable HTTP。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
13收录的工具列表 · 更新于 1 天前
此工具无需参数。
详细介绍
Apple Calendar
适用于 macOS 上 Apple Calendar 的 MCP 服务。
通过 EventKit 访问日历和事件。让 Calendar 继续作为系统记录来源,同时支持 Agent 读取、创建、更新和删除事件。
适用场景
- 仅涉及日历的工作流
- 无需使用一体化服务,通过 EventKit 访问日历
- 更严格地按应用隔离日程安排
功能
- 发现并列出日历
- 创建、读取、更新和删除事件
- 为上下文受限的客户端提供工具发现辅助功能
search_tools和get_tool_info - 今日资源和规划提示词
- 健康检查可区分结果为空和访问受阻
- 在受支持的本地配置中,原生 EventKit 读取受阻时,可通过 Calendar.app 自动化回退读取
- 权限恢复:
calendar_permission_guide、calendar_recheck_permissions
在这台 Mac 上安装
从克隆的仓库安装
git clone https://github.com/JonathanRReed/Apple-MCPs.git
cd Apple-MCPs
uv sync --all-packages
这会构建一个工作区环境,其中包含每个服务的入口点,均位于 .venv/bin 中(例如 .venv/bin/apple-calendar-mcp)。你也可以将 Apple-Calendar-MCP/start.sh 指定给 MCP 客户端;该脚本优先使用 uv run,否则会回退到普通的虚拟环境引导方式(需要 Python 3.11 或更高版本)。
在 AI Agent 中安装
通用 MCP 客户端配置
{
"mcpServers": {
"apple-calendar": {
"command": "uvx",
"args": ["apple-calendar-mcp"],
"env": {
"APPLE_CALENDAR_MCP_SAFETY_MODE": "safe_manage"
}
}
}
}
如果是从克隆的仓库运行,请改用 /path/to/Apple-MCPs/Apple-Calendar-MCP/start.sh 作为命令,并将 args 留空。
Claude Code 示例
claude mcp add --transport stdio --scope user apple-calendar -- uvx apple-calendar-mcp
--scope user 会让该服务在每个项目中均可用。若要通过仓库的 .mcp.json 仅与一个仓库共享,请改用 --scope project。
选择日历和事件标识符
调用 calendar_list_calendars,根据显示的名称和来源选择目标日历,并将返回的 calendar_id 原样传递给 calendar_list_events、calendar_create_event,或作为 calendar_update_event 的目标日历。原生 EventKit 列表会返回原生标识符;自动化列表则使用日历名称作为标识符。EventKit 可以读取日历时,传递给 calendar_create_event 或 calendar_update_event 的日历名称会解析为对应的原生日历,不区分大小写并忽略多余空格,因此写入操作可完整支持提醒。如果多个日历名称相同,则会返回 AMBIGUOUS_CALENDAR 和候选项;请改为传递目标日历的 calendar_id。未知名称会返回 CALENDAR_NOT_FOUND,只读日历会返回 CALENDAR_READ_ONLY。无法原生读取日历时,名称仍通过自动化处理。
更改 Calendar 权限后,请重启 MCP 服务并再次调用 calendar_list_calendars,以刷新标识符。若要完整替换或清除提醒,请使用原生 calendar_id 列出事件,并将返回的原生 event_id 传递给 calendar_update_event。更改权限后,现有的 applescript:: 事件 ID 仍通过自动化处理。请将事件 ID 视为不透明值:重新列出事件以获取原生 ID,而不要改写现有令牌。日历可写性、安全模式和允许列表仍然适用。
桥接批量查询
内部的 Python CalendarBridge.get_events(event_ids) 方法会在不新增 MCP 工具的情况下批量执行原生查询。传入一个由非空字符串组成的序列,最多 10000 个输入 ID。重复的输入 ID 只会解析一次。请求会按精确的 32768 字节 UTF-8 JSON argv 预算进行分块,包括 JSON 转义;单个超大的 ID 会在任何查询之前被拒绝。
返回的映射区分以下情况:
- 事件值:针对所请求 ID 的经过验证的响应
- None:通过现有 single-get/JXA 回退确认的显式原生未命中,或在该回退路径上的确定性未命中
- 缺少键:未知,包括未应答、格式错误、相互矛盾、重复响应、不匹配或不支持的条目
JXA 发出的 ID 是不透明的版本化令牌,用于标识 Automation 后端、日历范围以及确切的 UID 或 id() 命名空间/值。不要解析或构造它们。无 UID 的事件保留其实际的带类型 id() 值;元数据相同但彼此不同的事件不再被合并。没有可用标识符的行,或重复的提供方身份,会获得仅供显示的弱令牌。弱令牌不能证明不存在,也不能授权写入。
版本化令牌通过经过验证、由服务端过滤的 JXA 查询直接解析。必须恰好匹配一个日历和一个事件;有歧义、不可用、格式错误或不匹配的查询结果仍为未知。不使用未过滤的事件目录扫描。查询快照上限为 1000 个日历和每次查询最多 1000 个返回匹配项,标识符上限为 32768 个字符。当旧式裸 UID/id 值的命名空间能明确标识同一事件时,它们仍可解析。旧式日历/开始时间/标题组合在唯一时仍可读取,但不能授权变更或确定性的批量不存在判定。含义相互冲突的、类似版本化令牌的旧式值会被拒绝。
旧式回退标识符(包括可能同时也是字面提供方 UID 的编码标识符)需要跨日历进行冲突检查。在大型日历存储上,这些精确查询可能超过 30 秒的回退截止时间。超时是显式错误,不构成不存在证明,也不允许变更。完整的原生 EventKit 访问可为原生标识符避免该回退查询:授予宿主应用完整的日历访问权限,再次列出事件以获取原生 ID,然后重试。现有的回退标识符保留其严格的冲突检查。
原生未命中会重试 single-get/JXA 路径。如果整个原生批量无法给出答案,则不透明原生 ID 的回退未命中仍为未知,因为 JXA 可能使用不同的标识符格式。经过验证的版本化 JXA 未命中可以证明不存在。权限失败或逐 ID 确认失败仍为未知;非回退的整个辅助程序传输失败仍为显式错误。有效的原生回复若带有不同的规范 ID,则需要单独进行一次 single-get 查询来确认该规范 ID。冲突或未经确认的别名仍为未知。不支持的旧式 uid: ID 在不进行查询的情况下仍为未知。调用方不得删除缺少对应键的映射。
JXA 的就地更新和删除需要强且唯一的身份,并在写入前拒绝过期的日历名称。明确不支持通过 JXA 回退进行日历移动,因为克隆无法安全保留每个事件字段。原生日历移动仍然可用。同样不支持通过版本化 JXA ID 进行重复事件更新。
原生批量命令本身仅报告 EventKit 的查询结果。合成 ID 会产生 UNSUPPORTED_IDENTIFIER;单独的原生 EVENT_NOT_FOUND 并不是跨两个后端的已确认不存在。
安全模式
safe_readonlysafe_managefull_access
日历白名单
在 MCP 客户端的配置中设置这些环境变量,然后重启服务:
| 变量 | 作用 |
|---|---|
APPLE_CALENDAR_MCP_ALLOWED_CALENDARS | 服务可以读取或修改的日历名称,以逗号分隔。日历列表、事件列表、事件详情和 Calendar 资源都受此范围限制。 |
APPLE_CALENDAR_MCP_WRITE_ALLOWED_CALENDARS | 服务可以在其中创建、更新或删除事件的额外日历名称,以逗号分隔。它不会隐藏其他可读取的日历。 |
对于允许读取日程、但只能写入专用日历的助手:
{
"APPLE_CALENDAR_MCP_SAFETY_MODE": "safe_manage",
"APPLE_CALENDAR_MCP_WRITE_ALLOWED_CALENDARS": "AI Planning"
}
任一白名单未设置或为空时,该列表不施加任何限制。如果同时设置了两个白名单,写入操作必须同时通过两者的限制;无论设置了哪个白名单,safe_readonly 都会阻止所有写入操作。移动事件时会检查源日历和目标日历。如果配置了白名单,目标日历未能确定的写入操作会被拒绝。
名称在去除配置中的空白字符后,会进行精确的区分大小写匹配。所有名称匹配的日历都会被纳入,因此安全敏感的范围请使用唯一的日历名称。calendar_health 会报告已配置的写入白名单。
这些策略由 Python MCP 服务强制执行,并非 macOS 沙盒。直接使用原生辅助程序或桥接库不会执行这些策略。macOS 权限仍然适用,而且 MCP 客户端可能会将返回的数据发送给其模型提供商。
传输方式
stdio 是默认且推荐的传输方式。设置 APPLE_CALENDAR_MCP_TRANSPORT=streamable-http(可选设置 APPLE_CALENDAR_MCP_HOST 和 APPLE_CALENDAR_MCP_PORT),即可改用 Streamable HTTP 提供服务。
macOS 权限
- 需要日历访问权限
calendar_health会报告原生access_status、读取权限和写入权限,不会尝试使用 AppleScript 回退机制或请求权限。明确发起的日历读取仍可使用现有的自动化回退机制。
启动检查清单
- 将
uvx apple-calendar-mcp(或克隆仓库中的Apple-Calendar-MCP/start.sh)添加到 MCP 客户端 - 重新加载或重新连接客户端,以便将 Calendar 工具集加载到上下文中
- 首先调用
calendar_health - 如果访问受阻或
access_status为not_determined,请调用calendar_permission_guide - 更改 macOS 权限后,请调用
calendar_recheck_permissions
提示词说明
tools/list会返回完整的 Calendar 工具集。受上下文限制的客户端可以先使用search_tools,再对所需的 Calendar 工具使用get_tool_info。- 创建事件前,请与用户确认日期、时间、时长和标题
- 使用 Calendar 安排时间段、会议和约会
相关项目
事件提醒
calendar_create_event 和 calendar_update_event 接受 alarms:一个由 { "minutes_before": 15 } 或 { "absolute_iso": "2030-10-11T10:00:00Z" } 对象组成的数组。绝对日期必须显式包含 Z 或 UTC 偏移量;不含时区的日期会被拒绝。相对偏移量必须是 0 到 525600 之间的整数分钟;每个事件最多接受 100 个提醒。更新时省略 alarms 可保留现有提醒,传入 [] 则会清除提醒。
事件详情和列表响应包含提醒元数据。EventKit 支持相对、绝对和位置提醒。完整替换和清除提醒需要原生 EventKit 访问权限。Calendar 脚本回退方式可以创建初始显示提醒,并读取 Calendar 脚本字典公开的提醒类型。如果编辑提醒需要移除现有提醒,或无法读取现有提醒集合,则会在更改任何事件字段之前返回 ALARM_EDIT_REQUIRES_NATIVE。更新其他字段时省略 alarms 可保留现有提醒。回退更新中,如果显式传入 alarms(包括 []),且标题、时间、位置、备注或全天字段中有任何一个非空,则需要原生 EventKit,即使该字段已经是提供的值也一样。未更改的 calendar_id 不算字段写入;不支持移动事件。仅更新提醒时,如果四个提醒集合均可读取且为空,则可以添加初始显示提醒;此时 [] 是无操作。所有可能失败的事件记录读取都会在插入之前完成。如果插入失败或操作超时,结果可能未知:不会删除任何单条提醒,重试前必须检查事件。回退方式的功能对齐仍在 issue #41 中跟踪。
calendar_health 会报告 alarm_edit_backend: "native_eventkit" 和 can_edit_existing_alarms,其值基于原生读取/写入权限。每次编辑仍须遵守日历可写性和服务安全规则。
感谢 LightSpeedSpirit 在 PR #26 中最初贡献事件提醒功能。
重复事件
重复事件的每个实例共用一个 event_id,因此 calendar_update_event 和 calendar_delete_event 会接受两个可选参数,用来指定写入操作涵盖哪些实例。calendar_list_events 会将这类事件标记为 recurring: true。
scope:"occurrence"表示单个实例,"following"表示该实例及之后的所有实例,"series"表示所有实例。occurrence_start_iso:用于"occurrence"和"following",值为该实例的start,必须与calendar_list_events返回的值完全一致。
未提供 scope 时,对重复事件的写入不会产生任何更改。如果客户端支持 MCP 表单(征询),且调用指定了某个实例,服务会询问用户要选择哪种范围:仅此实例、此实例及之后的所有实例,还是整个系列。否则,服务会返回 RECURRING_EVENT_SCOPE_REQUIRED,告知 Agent 询问用户后再调用。由用户而非模型做出选择,因此 Agent 无法通过猜测删除整个系列。用户拒绝回答时,会返回 CANCELLED_BY_USER。非重复事件的处理方式与之前完全相同。
单独编辑的实例会获得自己的 event_id;通过该 ID 进行的写入也接受相同的 scope。使用 "series" 时,新的 start_iso/end_iso 会让每个实例以相同幅度移动。响应中的 deleted 表示目标实例是否确实已删除。指定范围需要原生 EventKit 访问权限;Calendar 自动化会返回 UNSUPPORTED_OPERATION。
感谢 vlasovpe-sg 在 issue #79 中提供详细报告和根因分析。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。