mcpField
M
macOS Calendar & Reminders

macOS Calendar & Reminders

本地服务
github.com/kiki830621生产力412 天前更新

关于 macOS Calendar & Reminders

che-ical-mcp 是基于 Swift 与 EventKit 构建的 macOS MCP 服务,让 Claude 直接操作系统日历与提醒事项。适合需要通过 AI 管理日程和待办的 macOS 用户,并提供冲突检测、批量操作与撤销重做。

主要功能

  1. 01日历事件的创建、查询、修改与删除
  2. 02提醒事项、标签与关键词搜索
  3. 03冲突检测与重复事件查找
  4. 04批量创建、移动与删除
  5. 05undo / redo 撤销重做历史

适用场景

  1. 01查询今日或本周日程并创建新事件
  2. 02检查新事件与已有安排是否冲突
  3. 03按标签整理并批量处理提醒事项

MCP 相关

作为 MCP 服务,向客户端暴露 29 个工具,用于读写 macOS 日历与提醒事项。

配置

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

暂未收录安装方式

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

代码仓库
安装包
mcpbche-ical-mcp.mcpb

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

che-ical-mcp

License: MIT macOS Swift MCP

让 Claude 原生控制 macOS 日历和提醒事项。 这是一个直接基于 EventKit 构建的 Swift MCP 服务,提供 29 个工具,用于管理事件、提醒事项、标签、批量操作、冲突检测以及撤销/重做。不仅能处理日历事件,也能管理提醒事项和任务。

English | 繁體中文


安装

Claude Code — 将此仓库注册为市场,然后安装插件。该插件包含 /today、/week、/quick-event、/remind 斜杠命令,以及一个 PreToolUse 钩子,可在每次写入事件时验证星期几:

claude plugin marketplace add PsychQuant/che-ical-mcp
claude plugin install che-ical-mcp@che-ical-mcp

Claude Desktop — 从 Releases 下载最新的 .mcpb,然后双击安装。

独立 MCP — 单独使用 29 个工具的服务,不含插件附加功能:

mkdir -p ~/bin
curl -L https://github.com/PsychQuant/che-ical-mcp/releases/latest/download/CheICalMCP -o ~/bin/CheICalMCP && chmod +x ~/bin/CheICalMCP
claude mcp add --scope user --transport stdio che-ical-mcp -- ~/bin/CheICalMCP

首次使用时,macOS 会请求访问日历和提醒事项的权限 — 点击允许。从源代码构建、就地升级,或在 SSH / launchd / VS Code 下运行?完整指南请参阅安装。


为什么选择 che-ical-mcp?

功能其他日历 MCPche-ical-mcp
日历事件是是
提醒事项/任务否是
提醒事项 #标签否是(MCP 级别)
多关键词搜索否是
重复项检测否是
冲突检测否是
批量操作否是
本地时区否是
来源消歧否是
创建日历部分支持是
删除日历部分支持是
事件提醒部分支持是
位置和 URL部分支持是
语言PythonSwift(原生)

全部 29 个工具

日历(4)
工具说明
list_calendars列出所有日历和提醒事项列表(包括 source_type)
create_calendar创建新日历
delete_calendar删除日历
update_calendar重命名日历或更改其颜色(v0.9.0)
事件(4)
工具说明
list_events按筛选条件/排序/数量限制列出事件(v1.0.0)
create_event创建事件(支持提醒、位置、URL、单个事件时区,以及带排除日期的重复规则)
update_event更新事件(包括时区、重复规则,以及重复事件的 span)
delete_event删除事件(支持重复事件的 occurrence)

重复规则排除项(#182):create_event(以及 create_events_batch 中的每个项目)接受 recurrence.excluded_occurrence_dates,可在创建时跳过重复系列中的特定日期 — 采用尽力而为的全有或全无语义(任何失败都会通过补偿性删除移除整个新系列;回滚失败会明确报告,绝不会悄无声息;无法排除首次发生的日期),一次 undo 即可移除整个系列及其排除项。被排除的日期是已移除的 occurrence,而非经过编辑的日期(仅在 iCloud 上检查,2026-10-05;未检查其他存储),因此不会阻止该次撤销;系列创建后单独编辑的 occurrence 则会阻止撤销(#236)。已知限制:幂等重试时,如果重复系列的所有请求日期都已不存在,则该系列会被标记为 skipped,但不会检测现有系列中超出请求范围的额外排除项。

提醒事项(8) | 工具 | 描述 | |------|-------------| | `list_reminders` | 列出提醒,支持筛选/排序/限制数量,以及提取标签(v1.0.0) | | `create_reminder` | 创建提醒并设置截止日期和标签(v1.3.0);仅包含日期的 `YYYY-MM-DD` 截止日期会使提醒成为仅日期提醒(#267),此时响应会附带 `date_sync`,其中的 `aligned` 根据已保存的提醒进行判断(#301) | | `update_reminder` | 更新提醒(包括标签、`clear_due_date`)(v1.3.0) | | `complete_reminder` | 将提醒标记为已完成/未完成 | | `delete_reminder` | 删除提醒 | | `search_reminders` | 按关键字或标签搜索提醒(v1.3.0) | | `list_reminder_tags` | 列出所有不重复的标签及其使用次数(v1.3.0) | | `cleanup_completed_reminders` | 一次调用即可删除所有已完成的提醒,默认先通过 dry_run 预览(v1.7.2);一次 `undo` 即可重新创建已删除的提醒(#243) |

重复提醒(#194): 列表/搜索结果包含 has_recurrence、完整的公开 recurrence_rules,以及精度感知型 due。完成操作会添加 operation(写入结果)和 next_occurrence(已确认/未知/不适用)。请使用 operation.status,而不要使用旧版的 is_completed:成功完成一次提醒后,下一个重复项仍可能处于未完成状态。后续项信息未知时,不得触发第二次写入。不同 ID 或无法确认的后续项会报告为 unknown,绝不会被报告为整个重复系列已结束。撤销重复提醒的完成操作时会进行身份校验(#204):一旦该标识符不再对应记录中的提醒项,系统会明确拒绝撤销并删除对应的历史记录,而不是卡住撤销栈。破坏性变更(#205): complete_reminder/list_reminders/search_reminders 中的 completed 必须是 JSON 布尔值——字符串和数字会被拒绝;省略该参数或设为 null 时,含义与之前相同。破坏性变更(#207,尚未发布): 同一规则现适用于所有布尔型工具参数(all_day、clear_*、include_completed、dry_run、delete_original)。请参阅响应约定与限制。

重新安排提醒(#227/#235/#237): Reminders.app 显示的是提醒最早的绝对日期闹钟的日期,因此,使用带时间的 due_date 调用 update_reminder 时,会同时移动开始日期以及所有绝对日期闹钟(仅日期的日期会改为仅日期提醒,见下文;旧截止日期不含时间时按日历日移动,否则按精确时间差移动)。clear_due_date 也会清除开始日期并移除绝对日期闹钟。移动时会保留已有的偏移量,因此,要修正闹钟与截止日期不一致的提醒,请传入 realign_to_due: true(与 due_date 一起传入,或单独传入以使用当前截止日期):最早的绝对日期闹钟会移至截止日期,后续闹钟会保留彼此间隔并排在其后;除非开始日期已与截止日期一致,否则开始日期会设为截止日期(仅日期截止日期对应日期当天的任意时间;带时间的截止日期则对应截止时间,或其所在日期的午夜,或不带时间)。响应会在 date_sync 中报告移动情况;date_sync.aligned 表示在已保存的提醒中,开始日期和最早的绝对日期闹钟是否与截止日期一致(有意设置为不同日期的闹钟也会显示 false)。写入浮动提醒的带时间截止日期(例如在 Reminders.app 中创建的仅日期提醒)会保留其明确指定的时区。撤销操作会恢复开始日期和闹钟,包括位置闹钟(#228)。 **仅日期提醒(#267):**将不带时间的日期(2026-10-18)作为 due_date 传给 create_reminder、create_reminders_batch 或 update_reminder,会创建仅日期提醒,也就是没有时间的日期提醒,效果与 Reminders.app 创建的相同;读取时,其 due.time 为 null。在 update_reminder 中,开始日期也会设为当天,即使开始日期原本与到期日期不同也一样;绝对日期闹钟会被移除,因为 Reminders.app 会显示最早的闹钟,并且会继续显示其时间(已在设备上验证);相对闹钟和位置闹钟会保留,date_sync.absolute_alarms_removed 会统计已移除的闹钟数量。为带时间的提醒指定仅日期时,时间会被移除。带时间的到期日期仍按原来的方式处理。对于不带时间的 create_reminder(以及 create_reminders_batch 创建的每一行),系统会重新读取已保存的提醒并返回 date_sync,与 update_reminder 一样:如果读取到的到期日期带有时间、读取时缺失,或无法重新读取提醒,则 date_sync.aligned 为 false(#301)。对于 update_reminder,如果写入的到期日期在读取时缺失,也会返回 aligned: false;此前这种情况下不会返回 aligned。在 list_reminders 中,仅日期提醒只有在其日期于主机时区结束后才会逾期;在 list_reminders 和 search_reminders 中,其 due_date / due_date_local 会显示为主机时区中当天的 00:00(#297)。

高级功能(10) ✨ v0.3.0+ 新增
工具描述
search_events按关键字搜索事件,支持 AND/OR 匹配
list_events_quick快捷方式:today、tomorrow、this_week、next_7_days 等
create_events_batch一次创建多个事件(每个事件可单独设置时区)
check_conflicts检查指定时间范围内是否存在重叠事件
copy_event将事件复制到另一个日历;delete_original 会像 move_events_batch 一样移动事件(不支持重复事件)
move_events_batch原位将事件移动到另一个日历,并保留重复设置和参与者;重复事件可使用 span / occurrence_dates(#226)
delete_events_batch按 ID 或日期范围删除事件,并提供试运行预览(v1.0.0)
find_duplicate_events查找跨日历的重复事件(v0.5.0)
create_reminders_batch一次创建多个提醒(v0.9.0)
delete_reminders_batch一次删除多个提醒(v0.9.0);一次 undo 即可重新创建这些提醒(#243)

**移动事件(#226):**移动操作会重新指定事件所属的日历,因此会保留重复设置、参与者和所有其他字段。在同一账户内,标识符保持不变;跨账户时则会改变(每个结果都会报告 id_changed 和 new_event_id)。对于重复事件,span: this(默认值)只移动 occurrence_dates 中指定的那次事件,并将其变为单次事件;span: all 会移动整个系列;未指定日期的重复事件不允许移动。如果原位移动失败,系统会复制事件并移除原事件,但包含重复设置或参与者的事件除外。每个结果都会报告 method(in_place / copied / split / unchanged)以及任何 not_carried_over 字段。

撤销/重做(3) ✨ v1.4.0 新增
工具描述
undo撤销最近一次日历/提醒操作
redo重做上一次撤销的操作。只有完成状态会再次写入;对于创建、删除、更新或移动操作,重做不会写入任何内容,而是返回 success: false 并指出要使用的工具,同时将该条目从重做历史中移除(#247)
undo_history列出可撤销的操作及其时间戳
撤销不会覆盖某人之后所做的更改(#236): 撤销创建、更新、移动或完成操作时,会先重新读取事件或提醒,并检查该操作之后是否有人更改了撤销操作将覆盖或删除的内容(移动操作检查日历;对于在此处创建的循环事件,还会检查首次发生后的最多四年内被单独编辑的各次发生;只要某次发生在任何已比较字段上与系列不同,就视为已编辑,包括提醒、时区、地点和忙闲状态;如果某次发生与系列的值相同,则不视为已编辑。只有当某次发生和系列都报告了忙闲状态时,才会比较该状态;因此,在只报告其中一方的存储中,不会检测到某次发生自身的忙闲状态)。如果某个字段已被改回撤销操作将写入的值,则不视为已更改。日历应用或服务自动进行的两种更改不视为编辑,因此绝不会阻止撤销,且更新操作的撤销会覆盖这些更改:提醒声音,以及为原本没有坐标的地点添加坐标。如果内容被更改,则不会写入任何内容,错误会列出已更改的字段,并且该条目会保留在 undo_history 中;进行更改的人应决定是将其改回后再次撤销,还是通过 undo + discard_id 放弃该次撤销。有三种创建操作的撤销会被拒绝,此时只能选择丢弃:被单独编辑过的各次发生(无法将其恢复到系列中);无法检查各次发生的系列(unchecked_occurrences,之后也无法再检查);以及规则被缩短的系列(recurrence;更新或删除某次发生及后续各次发生会导致这种情况),其被截断部分无法恢复。重做完成操作时,会对照撤销操作留下的状态进行相同检查。触及循环事件的 update_event(针对单次发生,跨度为 "future" 或 "all",或添加或移除规则)无法撤销:对此执行 undo 不会写入任何内容,会提示如果需要恢复更改,应在 Calendar 中还原,并会移除该条目,以便之前的条目仍可撤销(#262:此类撤销过去会删除系列的其余部分)。如果在撤销时,该事件已重复发生或已成为经过编辑的某次发生,那么较早对单次事件进行的更新或移动操作的撤销也会以相同方式被拒绝(包括移动已编辑的某次发生);因此,更新操作的撤销和针对单次事件移动操作的撤销绝不会写入循环事件(按设计,系列移动操作的撤销仍会将整个系列移回原处)。循环更新的安全还原方案见 #263。
**已删除 occurrence 的撤销与 availability(#244、#245):**撤销删除定期事件某个 occurrence 的 delete_event(范围为“this”)时,会在该 occurrence 的时间将其恢复为一次性事件,而不会放回原系列中(EventKit 无法将其放回);系列的绝对日期提醒则会变成在其开始时间触发的提醒(批量操作时,撤销文本只提及一次)。撤销范围为“future”的删除时,只有当删除从系列的第一个 occurrence 开始且移除了整个系列,才会重新创建该系列;否则(系列仍有部分保留、删除从最后一个 occurrence 开始,或 ID 指向已编辑的 occurrence),不会写入任何内容,而是提示在 Calendar 中恢复这些 occurrence,并移除该条记录。包含此类删除的 delete_events_batch 会在恢复任何事件之前被拒绝。撤销整个系列的删除(范围为“future”的上述情形,或范围为“all”)时,会根据规则重新创建系列,然后恢复扫描窗口内的例外(从第一个 occurrence 前一天到规则结束,最长四年):此前单独删除的 occurrence 仍保持删除;此前单独编辑的 occurrence 则会作为不再属于该系列的独立一次性事件恢复(#285);撤销文本会说明两类 occurrence 的数量。每个窗口边界之外的一年范围内也会列出 occurrence,并按其规则中的位置判定,因此,移出窗口的已编辑 occurrence 仍会作为一次性事件恢复(移出窗口超过一年的 occurrence 不会恢复,其规则位置会计为已删除;如果记录与重新创建的系列不匹配,则不会应用例外,文本会说明这一点)。系列的第一个 occurrence 永远不会被移除:如果它曾被单独编辑或删除,则会按规则保留,文本也会说明这一点。窗口之外的例外,以及删除时无法列出的系列的例外,只会按规则恢复,文本也会说明这一点。撤销较早前对某个已由恢复后的系列包含的 occurrence 的删除时,不会写入任何内容,并会说明这一点。undo_history 会将此类记录列为 Deleted event: <title> (undo recreates the series and its exceptions within the checked window: …);包含此类记录的 delete_events_batch 记录则列为 Batch (<N> operations; undo recreates <K> series and their exceptions within the checked window: …)(无法撤销的批次则显示 undo not available)。已在 iCloud 上使用 delete_event(范围为“future”)和 delete_events_batch(范围为“all”)进行验证。删除操作的撤销现在会在日历支持该值的情况下保留事件的 availability(free、busy 等),并与上述创建和更新检查进行比较。

批量删除作为一条记录撤销(#185、#243、#248):delete_events_batch、系列删除、delete_reminders_batch 和 cleanup_completed_reminders 各自只记录一条撤销记录,其中包含调用实际移除的项目,并将其设为最新记录。一次 undo 会在该次调用中逐项保存并恢复这些项目(清理操作最多包含 limit 项,默认 1000 项,或所有 reminder_ids 条目);每项都会使用新标识符以及撤销快照中记录的内容恢复;提醒的子任务不会被记录。首次写入前,会根据记录的标识符检查每项要恢复到的日历或列表(恢复时会按此标识符查找;其他账户中同名的列表不算);如果有任何日历或列表缺失或为只读(请求刷新后会再次检查),则不会写入任何内容,记录会完整保留,错误信息会说明有多少项对应的日历或列表仍然存在;使用 discard_id 放弃时会将它们全部丢弃(部分恢复见 #287)。如果保存仍然失败,记录中只会保留尚未恢复的项目,并使用相同 ID;失败的项目会移至最后执行,以便下一次 undo 先恢复其余项目,除非届时该失败项目对应的日历或列表已缺失或为只读,此时上述检查会拒绝操作。每次此类调用都会清除重做历史记录,且只保留最新的 50 条撤销记录。


安装

快速安装方式见本 README 顶部。这里提供完整参考,涵盖手动配置、从源代码构建、权限相关的特殊情况、原位升级和 CLI 模式。

要求
  • macOS 14.0+(Sonoma 或更高版本——自 v1.11.0 起,完整的 TCC 权限 API 要求此版本)
  • Xcode Command Line Tools(仅在从源代码构建时需要)
Claude Desktop

**一键安装(推荐):**从 Releases 下载最新的 che-ical-mcp-<version>.mcpb,双击,然后重启 Claude Desktop。

**手动配置:**下载二进制文件,然后将 claude_desktop_config.json 指向它。

curl -L https://github.com/PsychQuant/che-ical-mcp/releases/latest/download/CheICalMCP -o /usr/local/bin/che-ical-mcp
chmod +x /usr/local/bin/che-ical-mcp

编辑 ~/Library/Application Support/Claude/claude_desktop_config.json,然后重启 Claude Desktop:

{
  "mcpServers": {
    "che-ical-mcp": {
      "command": "/usr/local/bin/che-ical-mcp"
    }
  }
}
Claude Code — 插件(推荐)
claude plugin marketplace add PsychQuant/che-ical-mcp
claude plugin install che-ical-mcp@che-ical-mcp
  • 在 Claude Code 中,使用斜杠命令 /plugin marketplace add PsychQuant/che-ical-mcp 和 /plugin install che-ical-mcp@che-ical-mcp 效果相同。
  • 请通过其 Git 仓库(owner/repo)添加市场,而不是直接使用 marketplace.json URL——插件的 source 是同一仓库内的相对路径(./plugin),只有通过 Git 添加时才能解析。
  • 此插件也包含在 psychquant-claude-plugins 聚合包中(claude plugin install che-ical-mcp@psychquant-claude-plugins);两者使用相同的版本化二进制文件。
  • 如果二进制文件尚不存在,包装器会在首次使用时自动将其下载到 ~/bin/CheICalMCP。
Claude Code — 独立 MCP
mkdir -p ~/bin

# If upgrading, remove the old binary first. On macOS 26 the kernel can kill a
# fresh binary that inherits a stale code-signature cache from the old inode —
# one a running MCP process may still be holding open.
rm -f ~/bin/CheICalMCP

curl -L https://github.com/PsychQuant/che-ical-mcp/releases/latest/download/CheICalMCP -o ~/bin/CheICalMCP
chmod +x ~/bin/CheICalMCP

# --scope user: available in all projects  ·  --transport stdio: local stdin/stdout
claude mcp add --scope user --transport stdio che-ical-mcp -- ~/bin/CheICalMCP

**💡 提示:**将二进制文件放在 ~/bin/ 这样的本地目录中。云同步文件夹(Dropbox、iCloud、OneDrive)在同步文件时可能导致 MCP 连接超时。

从源代码构建(可选)
git clone https://github.com/PsychQuant/che-ical-mcp.git
cd che-ical-mcp
make release && make install
claude mcp add --scope user --transport stdio che-ical-mcp -- ~/bin/CheICalMCP

**⚠️ Swift 6 / Xcode 18 用户:**不要直接运行 swift build——上游 MCP SDK 存在并发错误(swift-sdk#214)。Makefile 会自动检测并切换到 Swift 5 语言模式。

授予权限

首次使用时,macOS 会请求访问日历和提醒事项的权限。请对两项都点击允许。

⚠️ macOS Sequoia (15.x) 注意:权限对话框会归属于启动 MCP 服务的父应用程序,而非二进制文件本身。这意味着:

环境权限归属
Claude DesktopClaude Desktop.app ✅(自动生效)
在 Terminal.app 中运行的 Claude CodeTerminal.app ✅(自动生效)
在 VS Code 中运行的 Claude CodeVS Code ❌(可能不会显示对话框)
在 iTerm2 中运行的 Claude CodeiTerm2 ✅(自动生效)

如果权限对话框没有出现(VS Code 中很常见),你需要将 NSCalendarsFullAccessUsageDescription 添加到 VS Code 的 Info.plist 中:

# 为 VS Code 添加日历使用说明
/usr/libexec/PlistBuddy -c "Add :NSCalendarsFullAccessUsageDescription string 'VS Code needs calendar access for MCP extensions.'" \
  "/Applications/Visual Studio Code.app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Add :NSRemindersFullAccessUsageDescription string 'VS Code needs reminders access for MCP extensions.'" \
  "/Applications/Visual Studio Code.app/Contents/Info.plist"

# 重新签署 VS Code(修改 Info.plist 后必须执行)
codesign -s - -f --deep "/Applications/Visual Studio Code.app"

# 重启 VS Code,随后会出现权限对话框

**注意:**VS Code 更新时会覆盖此修改。每次更新 VS Code 后,你都需要重新应用此修改。

升级现有安装

插件封装程序会在全新安装时自动下载,但不会替换现有二进制文件。要就地升级:

~/bin/CheICalMCP --self-update

此操作会查询 GitHub Releases,获取最新标签,下载新二进制文件,并将其与已发布的 SHA-256、维护者的 Developer ID 签名以及 Apple 公证进行校验;只有全部校验通过后,才会原子替换当前版本(任何校验失败都会保留原有安装)。如果它正作为 MCP 服务运行,请随后重启 MCP 主机(Claude Desktop / Claude Code),以启用新版本。手动备用方案:rm -f ~/bin/CheICalMCP && curl -L https://github.com/PsychQuant/che-ical-mcp/releases/latest/download/CheICalMCP -o ~/bin/CheICalMCP && chmod +x ~/bin/CheICalMCP。

CLI 模式(不使用 MCP 服务)

所有 29 个工具都可以直接从命令行调用,无需 MCP 服务:

# Flag-based: --key value pairs
CheICalMCP --cli list_events --start_date 2026-03-29 --end_date 2026-03-30

# JSON via stdin
echo '{"tool":"list_calendars","arguments":{}}' | CheICalMCP --cli

# From Claude Code via shell
claude -p "Run: ~/bin/CheICalMCP --cli list_events_quick --range today"

适用于 launchd 作业、Shell 脚本、CI 流水线,以及偏好使用子进程而非 MCP 协议的 Agent。TCC 权限仍然适用——如有需要,请先运行 CheICalMCP --setup。


v1.0.0 功能

灵活的日期解析

现在,所有日期参数均接受 4 种格式:

格式示例解释
完整 ISO8601"2026-02-06T14:00:00+08:00"精确日期和时间(保留时差)
不含时区"2026-02-06T14:00:00"使用提供的事件 timezone,否则使用系统时区
仅日期"2026-02-06"事件 timezone 或系统时区中的午夜;对于提醒 due_date,表示没有具体时间的仅日期提醒(#267,见“仅日期提醒”)
仅时间"14:00"今天的该时间
单个事件时区(v1.5.0)

为单个事件设置显示时区——这对涉及多个时区的旅行行程至关重要。

"Create a flight departure at 09:14 Berlin time"
→ create_event(title: "Flight LH123", start_time: "2026-04-08T09:14:00", timezone: "Europe/Berlin", ...)

"Update the hotel check-in to Dubai time"
→ update_event(event_id: "...", timezone: "Asia/Dubai")

"Remove the custom timezone from an event"
→ update_event(event_id: "...", clear_timezone: true)
  • timezone 参数接受 IANA 标识符(例如,Europe/Berlin、America/New_York、Asia/Taipei)
  • 提供 timezone 时,不带时差的日期时间会按该时区解析
  • 事件输出会在 timezone 字段中包含事件自身的时区,并据此格式化 start_date_local/end_date_local
  • create_event、update_event 和 create_events_batch 均支持此功能
  • 撤销/重做会保留单个事件的时区
参与者与组织者(只读)

如果有参与者信息,事件响应会包含这些信息。由于 EventKit 的限制,这些字段为只读——无法通过 MCP 设置或修改。

适用于:list_events、search_events、list_events_quick、check_conflicts

attendees(数组,可选)——事件有参与者时提供。每个参与者对象包含:

字段类型说明
name字符串或 null显示名称;如果不在通讯录中,则为 null
email字符串从参与者 URL 提取的电子邮件地址
role字符串以下之一:unknown、required、optional、chair、non_participant
status字符串以下之一:unknown、pending、accepted、declined、tentative、delegated、completed、in_process
type字符串以下之一:unknown、person、room、resource、group
is_current_user布尔值此参与者是否为当前用户

organizer(对象,可选)——事件有组织者时提供。包含:

字段类型说明
name字符串或 null显示名称
email字符串电子邮件地址
is_current_user布尔值组织者是否为当前用户

注意: 如果事件没有参与者或组织者(例如,没有邀请对象而创建的本地日历事件),则会省略这两个字段。

模糊匹配日历

现在,日历名称匹配时不区分大小写。如果找不到,错误消息会列出所有可用日历。

增强的列表/删除工具
  • list_events:filter(all/past/future/all_day)、sort(asc/desc)、limit
  • list_reminders:filter(all/incomplete/completed/overdue)、sort(due_date/creation_date/priority/title)、limit
  • delete_events_batch:日期范围模式(before_date/after_date)+ dry_run 预览

重大变更:list_events 和 list_reminders 现在返回 {events/reminders: [...], metadata: {...}},而不是普通数组。


使用示例

日历管理
"List all my calendars"
"What's on my schedule next week?"
"Create a meeting tomorrow at 2 PM titled 'Team Sync'"
"Add a dentist appointment on Friday at 10 AM with location '123 Main St'"
"Delete the meeting called 'Cancelled Meeting'"
提醒事项管理
"List my incomplete reminders"
"Show all reminders in my Shopping list"
"Add a reminder: Buy milk"
"Create a reminder to call mom tomorrow at 5 PM"
"Mark 'Buy milk' as completed"
"Delete the reminder about groceries"
提醒事项管理(v1.5.0)
"Remove the due date from 'Buy groceries'"
→ update_reminder(reminder_id: "...", clear_due_date: true)
高级功能(v0.3.0+)
"Search for events containing 'meeting'"
"Search for events with both 'project' AND 'review'"
"What do I have today?"
"Show me this week's schedule"
"Are there any conflicts if I schedule a meeting from 2-3 PM?"
"Create 3 weekly team meetings for the next 3 weeks"
"Copy the dentist appointment to my Work calendar"
"Move all events from 'Old Calendar' to 'New Calendar'"
"Delete all the cancelled events"
"Find duplicate events between 'IDOL' and 'Idol' calendars"
DX 改进(v1.0.0)
"Show my next 5 upcoming events"
→ list_events(start_date: "2026-02-06", end_date: "2026-12-31", filter: "future", sort: "asc", limit: 5)

"Show my overdue reminders"
→ list_reminders(filter: "overdue")

"Preview which events would be deleted from 'Old Calendar' before 2025"
→ delete_events_batch(calendar_name: "Old Calendar", before_date: "2025-01-01", dry_run: true)

"Create an event at 2 PM" (no need for full ISO8601!)
→ create_event(start_time: "14:00", end_time: "15:00", ...)

支持的日历来源

适用于与 macOS 日历应用同步的任何日历:

  • iCloud 日历
  • Google 日历
  • Microsoft Outlook/Exchange
  • CalDAV 日历
  • 本地日历
同名日历消歧(v0.6.0+)

如果不同来源中有同名日历(例如 iCloud 和 Google 中都有名为“Work”的日历),请使用 calendar_source 参数:

"Create an event in my iCloud Work calendar"
→ create_event(calendar_name: "Work", calendar_source: "iCloud", ...)

"Show events from my Google Work calendar"
→ list_events(calendar_name: "Work", calendar_source: "Google", ...)

如果检测到歧义,错误消息会列出所有可用来源。


故障排除

问题解决方案
服务已断开连接使用 make release && make install 重新构建
权限被拒绝在“系统设置”>“隐私与安全性”中授予日历/提醒事项访问权限
权限对话框始终不出现请参阅授予权限,了解 macOS Sequoia 的解决方法
通过 SSH 访问时权限被拒绝请参阅下文的 SSH 访问
在 launchd 下权限被拒绝请参阅下文的 launchd/自动化
某项服务被拒绝,但所有诊断结果均显示正常请参阅下文的 升级后无提示的永久拒绝
每次 Claude Code 更新后,日历/提醒事项都会再次失效请参阅下文的 Claude Code 更新会轮换主机端授权
未找到日历确保该日历在 macOS 日历应用中可见
提醒事项未同步在“系统设置”中检查 iCloud 同步
升级后无提示的永久拒绝(#154)

如果某项服务(通常是 Calendar)返回 access denied,而另一项服务正常,并且 --print-tcc-path 和系统设置都显示权限已获准,那么你很可能遇到了 #154 所描述的情况:由 v1.7.1 之前的版本(临时签名)创建的 TCC 记录绑定到了旧版本的代码哈希。升级后的 Developer ID 二进制文件永远无法与其匹配;在 macOS 26.5 及更高版本上,只有二进制文件带有匹配的 com.apple.security.personal-information.* 权限,操作系统才会允许通过重新提示来修复。

从 v1.14.0+ 开始,启动横幅会直接显示此问题——当 Security 框架检查能够确认 csreq 不匹配时,会显示 [drift] TCC.db <service> entry pins a code requirement this binary no longer satisfies 这一行(#155)。在此之前,所有状态 API 诊断(包括横幅)都会显示正常,这正是这类问题悄无声息的原因。如果你通过 Claude Desktop 的 .mcpb 安装遇到拒绝,现在拒绝消息会指出真正的阻碍和可行路径,而不再是无效的 --setup(#158)。

修复方法:升级到 v1.11.0 或更高版本(二进制文件现在包含这两项权限),重启宿主应用(Claude Desktop 中需要彻底退出,即完整执行 Cmd+Q),然后在首次访问 Calendar/Reminders 时批准弹出的权限对话框。批准后会将 TCC 记录改写为绑定到 Developer ID 要求,因此今后的所有升级都不会影响它。如果你不小心拒绝了该对话框,请在“系统设置”→“隐私与安全性”→“日历”或“提醒事项”中重新启用相应开关。

⚠️ 关于 #108 时期解决方法的勘误:tccutil reset Calendar com.checheng.CheICalMCP 对裸二进制文件(未打包)不起作用——它会因二进制文件没有 LaunchServices 注册而失败,并显示 OSStatus error -10814。并且,不要运行裸命令 tccutil reset Calendar(不带 bundle ID):它会清除这台机器上所有应用的 Calendar 授权;如果 CheICalMCP 使用的是尚未包含权限的二进制文件,它将永久无法再次请求权限。

Claude Code 更新会轮换主机端授权(#170)

在 v1.22.0(#343)中更改:当 macOS 报告的责任进程是 Claude Code(其位于 ~/.local/share/claude/versions/<ver> 下的原生可执行文件,或 ClaudeCode.app)时,二进制文件会在原位置重新执行,并将自身作为责任进程,因此 macOS 会检查 CheICalMCP 的授权,Claude Code 更新不再影响它。这适用于 MCP 服务、--cli、--print-tcc-path 和 --setup;--setup 在任何主机下都会重新执行。所有其他主机(Terminal、VS Code、Ghostty、ssh、cron、CI)均保留 v1.22.0 之前的行为:检查主机的授权,且不会重新执行。在 Claude Code 下升级后,请允许一次 CheICalMCP 提示,或在前台运行 ~/bin/CheICalMCP --setup;没有图形界面的后台会话无法显示提示。

权衡:在发生重新执行的情况下,macOS 会检查 CheICalMCP 的授权,因此一旦授权,Claude Code 启动的任何会执行此二进制文件的进程(包括 --cli)都可以在该授权下读取日历和提醒事项,无需单独同意;Claude Desktop 的 .mcpb 通过 disclaimer 也具有相同特性。CHE_ICAL_MCP_NO_DISCLAIM=1 会恢复主机归属;CHE_ICAL_MCP_FORCE_DISCLAIM=1 会在任何主机下重新执行(选择退出的设置优先)。

未经验证:CI 未覆盖通过新路径读取日历的情况,目前仅观察到 --setup 会显示提示;服务模式和 --cli 尚未确认。

本节其余内容适用于 v1.21.0 及更早版本、Claude Code 以外的主机,以及设置了 CHE_ICAL_MCP_NO_DISCLAIM=1 的情况。

在 Claude Code 原生安装中,实际可执行文件位于带版本号的路径(~/.local/share/claude/versions/<version>;~/.local/bin/claude 只是一个符号链接),macOS TCC 会将主机端的日历/提醒事项授权关联到该路径。每次 Claude Code 自动更新都会轮换路径,并悄无声息地使授权失效——典型症状是“昨天还好好的,更新后马上就坏了”,同时“系统设置”中不断累积过时的纯版本号条目(2.1.202、2.1.203,……)。

修复方法:通过 Claude Code 触发任意日历工具调用,让 macOS 再次显示提示(或重新创建条目),然后在“系统设置”→“隐私与安全性”→“日历”/“提醒事项”中将最新的版本号条目切换为开启。完整检查清单:troubleshoot-tcc 技能(/che-ical-mcp:check-tcc)。根本原因在上游(已在 #170 中跟踪——Claude Code 需要稳定的 TCC 标识);此仓库只能检测并记录这一问题。

SSH 访问

macOS TCC(透明度、同意与控制)按应用程序授予隐私权限。SSH 会话在 sshd 下运行,属于不同的安全上下文,因此在本机授予 Terminal 或 Claude Code 的权限不会延续到 SSH。

解决方法 A — 先在本机运行(推荐):

  1. 在目标 Mac 上本机(而非通过 SSH)运行一次 CheICalMCP
  2. 出现 TCC 对话框时,授予日历和提醒事项访问权限
  3. 此后 SSH 会话应能继承 CheICalMCP 二进制文件的授权

解决方法 B — 授予 sshd“完全磁盘访问权限”:

  1. 打开**“系统设置”→“隐私与安全性”→“完全磁盘访问权限”**
  2. 点击 +,按下 ⌘⇧G,输入 /usr/sbin/sshd 并将其添加
  3. 重新启动 SSH 会话

⚠️ 解决方法 B 会授予 sshd 广泛的文件访问权限——仅在你完全掌控的设备上使用。

launchd / 自动化

通过 launchd、cron 或其他非交互式自动化运行 CheICalMCP 时,macOS TCC 无法显示权限对话框。使用 --setup 预先授予权限:

# Step 1: Run once from Terminal (triggers TCC permission dialog)
CheICalMCP --setup

# Step 2: Grant Calendar & Reminders access in the dialog that appears
# Step 3: The binary now has permission — launchd jobs can use it

检测:CheICalMCP 会自动检测非交互式会话(缺少 TERM 环境变量或由 launchd 直接启动的子进程),并提供包含 --setup 说明的针对性错误消息。即使通过间接启动链(launchd → Claude Code → CheICalMCP)也能正常工作。

非交互式会话中的 --setup(#143):如果你在非交互式会话(没有 TERM / 由 launchd 直接启动的子进程)中运行 --setup,且权限仍未确定,--setup 现在会跳过请求并以非零状态码退出,而不是一直挂起——这时无法显示 TCC 对话框,因此程序会打印手动授予权限的说明,而不会阻塞。请在真正的终端中运行 --setup,以触发对话框。(如果二进制文件已获得权限,即使在非交互式会话中重新运行,也仍会报告成功。)

注意:如果 --setup 已授予权限,但 MCP 在 launchd 下仍然无法运行,TCC 可能已将权限关联到父进程。在这种情况下,请在系统设置 → 隐私与安全性 → 日历/提醒事项中手动添加 CheICalMCP。


技术详情

  • 当前版本:v1.22.0
  • 框架:MCP Swift SDK v0.12.0
  • 日历 API:EventKit(macOS 原生框架)
  • 传输方式:stdio
  • 平台:macOS 14.0+(Sonoma 及更高版本——根据 #119,在 1.10 后续版本系列中从 13.0 提升)
  • 工具:29 个工具,涵盖日历、事件、提醒事项、标签、撤销/重做、清理和高级操作

版本历史

版本变更
v1.22.0在 Claude Code 下,CheICalMCP 是其自身的负责进程 (#343):当 macOS 报告的负责进程是 Claude Code 时,二进制文件会原地重新执行,并带上 disclaim 属性,使系统检查的是 CheICalMCP 授权(Claude Code 更新也不会再使其失效);--setup 会在任何宿主下重新执行;其他所有宿主仍使用各自的授权。--print-tcc-path、启动横幅和访问被拒消息会显示 macOS 检查的进程。尚未验证:在 Claude Code 宿主下通过重新执行读取日历。迁移步骤和同一用户的权衡请参阅 CHANGELOG。
v1.21.0完整列出远期事件、含义明确的系列 ID、会议模块和按文件夹路由 (#285/#310/#325/#326/#335/#337/#338):超过四年的事件列表不再截断在约 1461 天;即使系列的首次发生已被删除,也可以再次移动、复制和删除该系列,并更新其发生项;无法使用的裸系列 ID 会说明原因(较早的发生项已编辑,或所有剩余发生项都单独编辑过);撤销整个系列的删除会在扫描窗口内恢复其例外项;make verify-release-ready 会与最新发布标签比较。插件外壳:会议日程会转换为一个全天总览事件,以及每个项目对应的一个定时事件;文件夹的 calendar_routing 规则会选择日历。
v1.20.0仅日期提醒、拒绝覆盖的撤销、读取时返回开始日期和闹钟 (#231/#235/#236/#243/#247/#262/#267/#297/#299/#301/#311):裸 YYYY-MM-DD due_date 会创建仅日期提醒,且仅日期提醒只有在当天结束后才算逾期;create_reminder / update_reminder 会报告 date_sync(含 aligned),update_reminder 新增 realign_to_due;list_reminders / search_reminders 会返回 start 和 alarms;无论区域设置如何,提醒日期都使用公历读取和写入;若操作后有其他位置所做的更改,undo / redo 会拒绝覆盖;涉及重复事件的 update_event 永不撤销;若新建系列中的某个发生项被单独编辑过(包括时间),则不会删除该系列;撤销会保留地点 / 电子邮件 / 绝对时间闹钟、重复规则、URL、可用性和列表;批量删除会记录撤销信息。破坏性变更(行为):裸日期 due_date、逾期规则、undo / redo 的拒绝行为,以及对非完成操作执行 redo 时不写入任何内容。
v1.19.0原地移动事件、同步提醒日期、经过验证的自更新 (#223/#225/#226/#227):move_events_batch 会重新分配日历,而不是复制后删除,并保留重复规则、参与者和所有字段(仅跨账户时标识符会改变;重复事件的 span / occurrence_dates;每个事件的 method / id_changed / not_carried_over;仅在受保护的回退路径中复制后删除);update_reminder 会随到期日期移动开始日期和绝对日期闹钟(Reminders.app 会显示闹钟日期),并报告 date_sync;clear_due_date 会清除这些日期,撤销时会恢复;--self-update 仅安装由 Developer ID 签名并经过公证的二进制文件,采用来自 che-mcp-kit-swift 0.2.x 的共享骨架。破坏性变更(行为):缺少 occurrence_date 的重复事件会被拒绝;copy_event 会拒绝移动重复事件;非字符串 event_ids 条目会被拒绝。
v1.18.0完整支持提醒的撤销/重做、显式 discard_id、全面严格校验布尔值 (#196/#197/#198/#199/#202/#203/#206/#207/#208/#209/#211/#212/#214/#215/#216):撤销会写回记录的 completion_date,重做会恢复保存的时刻,而非重新推断状态;重复完成会保留原始时刻;undo(discard_id) 会通过稳定的 undo_history ID 显式移除阻塞的栈顶记录(对于已删除的提醒或失效事件,未找到的目标不再卡住堆栈);事件移动会记录源发生项,因此撤销时会恢复到原日历;event_recurrence_rules / reminder_recurrence_rules 会区分两种格式(保留旧别名);每个工具注释都有明确且经过测试的策略,complete_reminder、更新工具和可选移动工具现在均为 destructiveHint: true。破坏性变更:所有布尔工具参数都必须是严格的 JSON 布尔值(字符串/数字会被拒绝,并返回 <key> must be a boolean)。内部改进:提醒列表/搜索筛选、排序和限制在 actor 的预快照内完成;list_reminder_tags 位于快照接口处;标签扫描改为线性扫描(无指数级回溯);提醒写入结果不可变且符合 Sendable;完成和重复历史方法移至专用 actor 扩展。
v1.17.0读取时提供提醒重复信息、明确的完成结果、基于身份校验的撤销、严格校验布尔值 completed (#194/#204/#205):list_reminders / search_reminders 会公开 has_recurrence、完整的 recurrence_rules(包括 frequency_raw_value)和 due 对象;complete_reminder 会将写入结果(operation)与保存的对象(observed)分开,并将后续发生项报告为 next_occurrence——保存后同步观测一次(设备端 iCloud:相同 ID 会原地推进,已完成的发生项会归档到新 ID 下),消息采用提醒自身的墙上时钟时间。重复完成操作的撤销/重做会进行身份校验:一旦该 ID 不再对应记录的发生项,就会明确拒绝并丢弃该条目,使较早的操作仍可撤销;未找到仍是暂时性状态 (#191)。破坏性变更:三个提醒工具中的 completed 必须是 JSON 布尔值(任何读取或写入前都会拒绝字符串/数字;省略/null 保持原有含义;--cli 中的 JSON null → 省略)。PR #195 进行了 3 轮 6-AI 验证,#200 / #201 也进行了验证;进行了两次设备端 stdio 探测。582 项测试。
v1.16.1类型安全和设备端验证修复 (#184/#190/#191):现在会拒绝非对象类型的 recurrence(之前会被静默丢弃);会拒绝 all_day 与 timezone 配对(之前会静默移除全天标记,导致跨日期变更线的排除项失效);删除重复系列后的撤销会根据值快照重建规则(修复 EKCADErrorDomain 1010),撤销/重做失败时也不再消耗该条目。529 项测试。
v1.16.0重复规则排除、完整撤销支持、archive-event 技能 (#182/#185/#180):在 create_event/batch 中支持 excluded_occurrence_dates(分两步创建后移除,并补偿性删除;首次发生项不可排除);批量/系列删除现在会记录撤销条目(一个 .batch 单位);撤销重复事件的创建操作现在会移除整个系列;新增 archive-event 技能——支持从源内容归档为事件、跟踪修正,并提供 .claude/.ical/ 项目配置。514 项测试。
v1.15.0--print-tcc-path 执行上下文 + 版本化宿主横幅信号。 TCC 诊断现在会打印父进程链(self → … → launchd),并提示其依赖上下文——授权状态取决于负责进程上下文 (#168),因此查询所处的宿主至关重要 (#169)。父进程链诊断优化:显示截断/循环标记、空 comm 关联、ps -ww、解码/退出失败报告和 NOTE 精度 (#173)。新增漂移检测信号:“版本化 Claude Code 宿主 + 未授权 EventKit”——在启动时主动说明 #170 中由更新轮换导致的问题,并在该情况下隐藏相互矛盾的 --setup 提示 (#175)。以上三项均通过 6-AI 跨模型集成验证;验证过程中发现的 CWE-150 终端转义缺口已在合并前修复。v1.14.2 插件发布导致的版本漂移已在全部五个版本位置统一 (#172)。490 项测试。
v1.14.2文档/技能层发布——双层 TCC 授权模型 (#168):troubleshoot-tcc 技能、/check-tcc、mcpb/README.md 和 plugin/CLAUDE.md 现在会说明宿主应用(负责进程)TCC 层、仅显示版本号的“系统设置”条目(2.1.202 = Claude Code 的版本化二进制文件),以及切换并观察的验证步骤。发布时二进制文件与 v1.14.1 完全逐字节相同(仅插件外壳有变化;源代码版本位置之后在 #172 中统一)。
v1.14.1元数据修正——工具数量一致性。 server.json 的 description 写着“24 个工具”,而 PROMOTION.md 写着“20 个工具”;服务器实际公开 29 个工具(与 mcpb/manifest.json 的 long_description 和 ManifestParityTests 工具一致性保护相符)。已将面向注册目录的 server.json、docs/COMPETITIVE_ANALYSIS.md 和 PROMOTION.md 修正为 29。代码和工具接口均无变更——功能上与 v1.14.0 完全相同;本次发布仅用于发布修正后的注册目录元数据(注册目录版本不可变)。
v1.14.0修复 Claude Desktop 工具注入丢失问题 (#166):mcpb/manifest.json 的 display_name 中包含字面量 &,导致 Desktop 1.18286.0 在每次对话中静默丢弃整个 29 工具服务器(Claude Code 不受影响);现已将 & 改为 and,并通过在故障安装上进行单变量干预以及添加 ManifestParityTests 回归保护予以确认。serverInfo.name 也已与 kebab 格式的清单 ID 统一(属于规范清理;实测已排除其为原因)。#154 配套批次:csreq 不匹配 TCC 漂移信号 (#155,通过 SecCodeCheckValidity 自检检测静默拒绝类别)、.mcpb 拒绝消息不再因已处于 .denied 状态的签名而卡在 --setup (#158)、macOS 标记从 13.0 升至 14.0 (#157)、swift-nio 从 2.96 升至 2.101 (#159)。454 项测试。
v1.13.0SwiftUI SetupWindow (#164):交互式 --setup 会在 #163 的前台 NSApplication 中显示实时状态窗口(每个实体都有授权按钮,并显示解析后的二进制文件路径)。修复 Desktop 日历拒绝问题 (#165):图形应用启动的服务器在 TERM == nil 时会错误触发 isNonInteractive,因此在 requestFullAccess 前就快速失败,导致 Claude Desktop 中始终不会出现首次授权对话框;现在改用 CGSession 图形会话信号。429 项测试。
v1.12.0前台 --setup (#163):交互式 --setup 现在会在前台 NSApplication 中运行,使 EventKit 的日历 TCC 模态窗口实际显示(此前在纯 CLI 异步上下文中会被静默拒绝)。拒绝消息和启动横幅会显示解析后的二进制文件路径,以及可复制粘贴的 "<path>" --setup 命令,用于访问隐藏的 .mcpb 二进制文件。
v1.11.1create_event 时间范围验证 (#160):与 update_event 保持一致——通过共享的 validateTimeRange 保护逻辑拒绝时间倒置/时长为零的定时事件。405 项测试。
v1.11.0解除 TCC 修复重提示的阻碍 (#154):Entitlements.plist 包含 personal-information.calendars + .reminders——macOS 26.5 上长期未升级的 v1.7.1 之前安装可能遭遇永久性静默日历拒绝(TCC 条目固定在旧 cdhash 上;由于二进制文件未声明权限,修复重提示被策略阻止,但所有诊断均显示正常);签名二进制发布门禁会验证这两个键。加强非交互式 EventKit (#131 / #143 / #144 + #146–#150)。破坏性变更:最低部署版本提升至 macOS 14.0 (#119)。401 项测试。
v1.10.0TCC 漂移检测器 + 启动横幅 (#122):MCP 服务启动时会向 stderr 输出一次性横幅,包含版本/路径/PID 和漂移信号(每项服务的 TCC.db 路径不匹配、过期进程);可通过 CHE_ICAL_MCP_NO_BANNER=1 禁用。修复子进程辅助程序中的管道死锁;针对所有插入横幅的值提供 CWE-117 stderr 注入防护。
v1.9.0TCC 访问门重构 (#108 第二阶段,关闭 #109):移除进程生命周期内的 has*Access 缓存反模式;通过新的 AuthorizationGate + AuthorizationStatusSource 接口(Apple TN3153 模式)在每次调用时执行 EKEventStore.authorizationStatus(for:)——状态变化会立即呈现,不再因授权状态过期而静默失败。新增 --print-tcc-path 诊断标志。
v1.8.1文档:mcpb/README.md 新增安装后/升级时的 TCC 权限设置指南 (#108 第一阶段)。
v1.8.0线格式一致性改进 + 响应形状参数 (#101 相关问题——3 天内关闭 5 个问题,均采用 Refs #N IDD 和 6-AI 集成验证)。事件列表响应形状参数 (#47 / #101):detail_level(summary/standard)、fields 允许列表、display_timezone(严格遵循 IANA)、limit(上限 10000)——用于调整大模型输出详细程度。统一封装结构 (#102 / #107,破坏性线格式变更):移除 list_events.metadata.returned + list_reminders.metadata.returned;所有 5 个列表/搜索封装结构都使用顶层 <entity>_count,并采用限制前的语义;search_reminders.result_count → reminder_count;search_reminders 新增 limit 参数(与 search_events 一致)。读取 metadata.returned 或 result_count 的 MCP 客户端必须更新。加强验证器 (#101 F1–F3):requireOptionalInt 使用 Int(exactly:),避免 Int.max 导致的 DoS 陷阱;detail_level / display_timezone 验证器会区分参数缺失与非字符串(不会静默强制转换)。以运行时为依据的漂移检测 (#103,加强 #101 M3):现在通过 EventFormattingSource 接口 + FakeFormattableEvent 测试 formatEventDict 与 validEventFields 之间的偏差。CHANGELOG 分类调整 (#106):根据 Keep a Changelog 1.1.0,将线格式重命名从 Fixed 移至 Changed。发布流水线修复:打包前防护检查现在会从 DEVELOPER_ID 证书派生 Team ID(此前会将 SHA 哈希与可读的 Authority= 字符串进行比较)。
v1.7.2强化与功能改进(v1.7.1 之后新增 30 多次提交,均采用 Refs #N IDD 并通过 6-AI 验证)。--self-update (#49) + SHA-256 二进制验证 (#98):为现有安装提供升级路径,并通过加密校验防止安装损坏的发布版本。make install-signed (#50):macOS 26 上维护者的开发 TCC 流程——缺少 Developer ID 时快速失败,并强制进行 codesign 验证。CI 测试工作流 (#51):在 PR 阶段于 macos-latest 上运行 swift build + swift test。清理器强化系列:escapeForStderr 完整覆盖 C0+DEL (#73),为 executeUndo/executeRedo 标题插值新增 sanitizeForInterpolation (#74),CLIRunner stderr 改由 writeFailureLog 处理,以允许受信任分支例外 (#80),writeFailureLog 增加 1024 字符 DoS 上限 (#86),CLIError.invalidJSON 增加仅限作者控制内容的约定文档 (#85),记录 FileHandle.standardError.write 线程安全和 macOS PIPE_BUF=512 (#70 / #94)。分发优化:过期 codesign 缓存的安装代码片段增加 rm -f 前置命令 (#90,确保与 #62 的 zh-TW 版本一致)。v1.7.1 后续优化 (#46 #57 #58 #60):保持重做错误插值一致、调整 build-mcpb.sh 步骤编号、完善 Entitlements.plist 文档、补充 Makefile release-signed: 工作目录说明。cleanup_completed_reminders 工具 (#21):一次调用即可清理所有已完成提醒,默认 dry_run=true。
v1.7.1安全强化 (#20 #26):在所有事件/提醒入口处进行输入验证(长度限制 + URL scheme 允许列表),为 MCP 读取响应添加提示词注入包装器,在解析边界验证 days_of_week / days_of_month / alarms_minutes_offsets(遇到无效值时抛出错误,而非静默丢弃),补全 Info.plist,新增 42 项回归测试。
v1.7.0参与者和组织者信息 (#17):在事件响应中提供只读的 attendees 数组和 organizer 对象。重构共享的 formatEventDict 方法。
v1.6.0--setup 标志 (#13):为 launchd/自动化预先授权 TCC 权限。检测非交互式会话(TERM + ppid)。合并 SSH+launchd 错误消息。--cli 模式 (#14):无需 MCP 服务即可直接从命令行调用全部 28 个工具。支持基于标志(--key value)和 JSON stdin 两种模式。自动推断 bool/int/double/array 参数类型。MCP Swift SDK 0.12.0(兼容 Swift 6.3)。
v1.5.0每个事件独立时区 (#12):在 create_event/update_event/create_events_batch 中支持 timezone 参数;事件输出使用事件自身的时区;无时区信息的日期时间按事件时区解析。清除到期日期 (#9):update_reminder 新增 clear_due_date。星期验证 (#5):create_event/update_event 会根据 days_of_week 验证 start_time 的星期几。撤销/重做 (#8):新增 3 个工具(undo、redo、undo_history)。修复重复事件 (#7):通过 occurrence_date 支持按发生项删除/更新。Swift 6 构建 (#11):更新 README,说明 make release 工作流
v1.4.0提高大模型可靠性:修复默认搜索范围(使用 ±2 年而非 distantPast/Future),在 search_events 响应中增加 searched_range 元数据,在 create_events_batch 中增加 similar_events 提示,在工具描述中提供大模型提示
v1.3.1文档修复:明确说明标签属于 MCP 层(而非 Reminders.app 原生标签);Apple 未提供原生标签的公开 API
v1.3.0提醒标签(MCP 层):为 create_reminder/update_reminder/create_reminders_batch 提供将 #hashtag 文本存储在备注中的功能,在 search_reminders 中支持按标签筛选,并新增 list_reminder_tags 工具;MCP SDK 0.11.0。注意:可通过 MCP 搜索标签,但这些标签不会显示为 Reminders.app 原生标签(Apple 未提供相应的公开 API)
v1.2.0幂等写入:create_event、create_events_batch、create_reminder、create_reminders_batch、create_calendar 现在都会先检查再写入,避免重试时产生重复项;响应包含 skipped 数量
v1.1.0重复规则 + 地点:支持重复事件/提醒(每日/每周/每月/每年)、带坐标的结构化地点、基于地点的提醒触发条件(进入/离开地理围栏)、丰富的重复规则输出
v1.0.0开发体验改进:灵活的日期解析(4 种格式)、模糊日历匹配、list_events/list_reminders 筛选/排序/限制、delete_events_batch 支持试运行 + 日期范围模式
v0.9.0新增 4 个工具(20→24):update_calendar、search_reminders、create_reminders_batch、delete_reminders_batch
v0.8.2国际化周支持:为 list_events_quick 提供 week_starts_on 参数(monday/sunday/saturday/system)
v0.8.1修复:update_event 时间验证错误;移动事件时保留时长
v0.8.0破坏性变更:创建操作现在必须提供 calendar_name(不再隐式使用默认值)
v0.7.0为 Anthropic Connectors Directory 提供工具注释、自动刷新机制,以及改进后的批量工具描述
v0.6.0来源消歧:为同名日历提供 calendar_source 参数
v0.5.0批量删除、重复项检测、多关键词搜索、改进权限错误处理、PRIVACY.md
v0.4.0复制/移动事件:copy_event、move_events_batch
v0.3.0高级功能:搜索、快速范围、批量创建、冲突检查、时区显示
v0.2.0使用 Swift 重写,完整支持 Reminders
v0.1.xPython 版本(已弃用)

贡献

欢迎贡献!请随时提交 Pull Request。

发布流程(维护者适用)

版本号分别位于三个位置,含义各不相同:

文件作用何时更新
Sources/CheICalMCP/Version.swift — AppVersion.current事实来源;显示在 --version、help 和 MCP serverInfo.version 中每次发布
Sources/CheICalMCP/Info.plist — CFBundleVersionmacOS 软件包版本每次发布;必须与 AppVersion.current 一致
mcpb/manifest.json — version随 .mcpb 一同发布的 Claude Desktop 软件包清单每次发布;必须与 AppVersion.current 一致
server.json — version + packages[].identifier + fileSha256MCP Registry 提交快照仅在向 MCP Registry 重新提交新版 .mcpb 时更新(周期独立)

scripts/build-mcpb.sh 会确保前三者一致;只要有一项不一致,构建就会失败。server.json 有意独立维护,因为更新它需要重新构建 .mcpb、生成新的 SHA256 并重新提交——这些步骤并非每次源代码发布都会执行。

签名与公证(macOS 26+ 必需)

从 v1.7.1 起,发布二进制文件会使用 Developer ID Application 证书签名,并通过 Apple 的 notarytool 进行公证。在 macOS 26 上,必须执行此操作——临时签名的二进制文件无法触发 Calendar / Reminders 的 TCC 权限对话框。

前提条件(一次性设置):

  1. 注册 Apple Developer Program。
  2. 在登录钥匙串中安装 Developer ID Application 证书。
    • 使用以下命令验证:security find-identity -p codesigning -v(必须显示 Developer ID Application: <Your Name> (<TeamID>))。
    • Team ID 属于你自己——可在 https://developer.apple.com/account → Membership Details 中查找。(本仓库中任何位置显示的维护者 6W377FS7BS 仅供参考。)
  3. 配置 notarytool 钥匙串配置文件(名称不限;构建脚本默认查找 che-ical-mcp)。
    • 交互式创建(推荐——密码不会留在 shell 历史记录中):
      xcrun notarytool store-credentials che-ical-mcp --apple-id <your-apple-id> --team-id <your-team-id>
      # notarytool 会提示输入 App 专用密码
      
    • App 专用密码:在 https://account.apple.com → Sign-In and Security → App-Specific Passwords 中生成。请使用专用密码(例如命名为 che-ical-mcp);如果密码泄露,请撤销并重新生成。切勿在命令行中通过 --password 传递密码——这会将密码写入 ~/.zsh_history。
  4. 为构建脚本导出你的身份:
    export DEVELOPER_ID='Developer ID Application: <Your Name> (<TeamID>)'
    export NOTARY_PROFILE='che-ical-mcp'   # match what you set up in step 3
    
    将这些变量持久保存到 ~/.zshrc 或项目本地的 .envrc(已加入 gitignore)。脚本特意不提供默认值,这样新分叉的仓库就不会因引用维护者身份而报错。

每次发布的流程:

make release-signed     # builds universal binary → signs + notarizes → packages .mcpb
gh release create vX.Y.Z mcpb/server/CheICalMCP mcpb/server/CheICalMCP.sha256 mcpb/che-ical-mcp-X.Y.Z.mcpb mcpb/che-ical-mcp-X.Y.Z.mcpb.sha256 --notes "..."

make release-signed 会运行 scripts/build-mcpb.sh;该脚本创建通用二进制文件后,会调用 scripts/sign-and-notarize.sh。签名脚本会执行预检(证书和 notarytool 配置文件),如果缺少任何项目,就会立即给出清晰易懂的提示并失败。公证通常需要 1–15 分钟(notarytool submit --wait 会一直等待,直到 Apple 完成处理)。

构建完成后进行验证(运行以下全部三项,确认整个流程正常):

# 1. Signature properties (cert + hardened runtime + team ID)
codesign -dv --verbose=2 mcpb/server/CheICalMCP
# Expected:
#   Authority=Developer ID Application: <Your Name> (<TeamID>)
#   TeamIdentifier=<TeamID>
#   flags=0x10000(runtime)
#   Signature size in the few thousand bytes range (varies by cert chain)

# 2. Signature integrity
codesign --verify --deep --strict --verbose=2 mcpb/server/CheICalMCP
# Expected: exit 0, no warnings

# 3. Notarization end-to-end (this is the real "Gatekeeper would accept" gate)
spctl -a -vvv -t install mcpb/server/CheICalMCP
# Expected: <binary>: accepted; source=Notarized Developer ID
#
# Note on flag choice (verified empirically on macOS 26.4.1, 2026-05-04):
#   -t execute → rejected "code is valid but does not seem to be an app"
#                (Apple's "execute" type expects a .app bundle structure,
#                 not raw Mach-O CLI binaries)
#   -t install → accepted; source=Notarized Developer ID  ← use this
#   -t open    → rejected "Insufficient Context"
#
# Apple's Code Signing Guide describes -t execute as the assessment type for
# "applications and tools", but on macOS 26 raw Mach-O binaries fall through
# the .app bundle check. -t install is the documented assessment type for
# software being installed (which describes how a CLI binary lands in ~/bin),
# and is the type that returns the actual notarization verdict in practice.
# Re-test if Apple changes this behavior in a future macOS update.

本地开发迭代(无需等待签名):

SKIP_CODESIGN=1 ./scripts/build-mcpb.sh   # ad-hoc signed; do NOT ship the result
make install                              # installs ad-hoc to ~/bin (dev only)

当 DEVELOPER_ID 未设置,或钥匙串中没有对应证书时,build-mcpb.sh 也会自动跳过签名,因此贡献者 / CI / 分叉仓库可以构建可用的未签名 .mcpb 用于测试,无需手动设置 SKIP_CODESIGN。(出现这种情况时,你会看到清晰的“Skipping codesign”警告。)

签名身份环境:

环境变量默认值必需场景
DEVELOPER_ID(未设置 — 自动跳过签名)已签名发布
NOTARY_PROFILE(未设置 — sign-and-notarize.sh 中快速失败)已签名发布
ENTITLEMENTSSources/CheICalMCP/Entitlements.plist自定义权限文件
SKIP_CODESIGN(未设置)即使存在证书也强制跳过签名(设置为 1 或 true)
REQUIRE_CODESIGN(未设置)缺少签名前提条件时快速失败(make release-signed 会设置为 1 — 规范的发布路径不得静默生成未签名的构件;直接运行 ./scripts/build-mcpb.sh 进行适合分支开发的构建时不要设置)

已知限制 — 无法装订票据:stapler staple 不支持原始 Mach-O 二进制文件(仅支持 .app / .pkg / .dmg 捆绑包)。公证后,Gatekeeper 会在首次启动时在线检查二进制文件,而不是读取已装订的票据。处于隔离网络后的最终用户可能会看到“无法验证开发者”警告;联网启动一次即可解决(Apple 会缓存验证结果)。缓解方法:如有需要,可在未来的 .pkg 封装包上运行 xcrun stapler staple。

故障排查:

  • 公证被拒?运行 xcrun notarytool log <submission-id> --keychain-profile $NOTARY_PROFILE 查看 Apple 给出的原因。签名脚本每次运行都会打印提交 ID。
  • codesign 提示缺少身份?运行 security find-identity -p codesigning -v 确认存在有效证书;运行 xcrun notarytool history --keychain-profile $NOTARY_PROFILE 确认配置文件可用。
  • 证书过期?前往 https://developer.apple.com/account/resources/certificates 重新签发并安装,然后重新导出 DEVELOPER_ID。
  • 安全警告:不要在共享或不受信任的机器上解锁签名钥匙串。用于签署构件的证书和私钥是供应链安全的关键。

许可证

MIT 许可证 - 详情请参阅 LICENSE。


作者

由 Che Cheng(@kiki830621)创建

如果你觉得这很有用,请考虑点个星!

重复事件读取名称(#198,尚未发布): 事件使用 event_recurrence_rules,提醒使用 reminder_recurrence_rules。两者都是规则数组,但选择器缺失时的处理方式和结束日期的呈现方式不同。保留了旧版别名 recurrence_rules。拒绝未知字段的客户端需要更新解码器。参见格式对比。

评论

支持 Markdown

第一次接触 MCP?

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

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