mcpField
A
Apple Calendar

Apple Calendar

本地服务
github.com生产力322 天前更新

关于 Apple Calendar

Apple Calendar 是面向 macOS 的 MCP 服务,通过 EventKit 提供日历与事件操作,适用于日程管理工作流。它支持安全模式、日历范围限制,并在特定情况下提供自动化读取回退。

主要功能

  1. 01发现并列出日历
  2. 02创建、读取、更新和删除事件
  3. 03提供今日资源与规划提示词
  4. 04日历访问健康检查与权限恢复
  5. 05支持安全模式和日历允许列表

适用场景

  1. 01查询会议和预约安排
  2. 02创建或修改日程事件
  3. 03限制 Agent 可访问或写入的日历

MCP 相关

该 MCP 服务向 MCP 客户端提供日历、事件及相关资源和提示词。默认使用 stdio,也可配置为 Streamable HTTP。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库
安装包
pypiapple-calendar-mcp1.1.4
mcpbapple-calendar-1.1.4.mcpb1.1.4

工具

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 上安装

快速开始(uvx,通过 PyPI 安装)

安装好 uv 后:

uvx apple-calendar-mcp

无需克隆,也无需管理虚拟环境。

从克隆的仓库安装
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_readonly
  • safe_manage
  • full_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 中提供详细报告和根因分析。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。