apple-notes-reminders-mcp
apple-notes-reminders-mcp
一个 MCP(模型上下文协议)服务器,用于在 macOS 上向 MCP 兼容客户端(例如 Claude Desktop)开放 Apple Notes 和 Apple Reminders 功能。
功能
该服务器注册了一组工具,用于读写 Notes 和 Reminders。Notes 工具涵盖列出、搜索(包括图片附件中的识别文本)、读取、创建、更新、移动和删除笔记及文件夹,以及标签、置顶状态、图片附件和最近删除。Reminders 工具涵盖类似操作,还包括子任务、批量创建、完成、截止日期、标记、重复、位置/提前提醒、已保存筛选视图、模板和基于关键词的批量筛选。
Related MCP server: apple-reminders-mcp
架构
两个域通过不同的机制进行读写:
读取尽可能通过 SQLite 进行。笔记直接从磁盘上的 NoteStore 数据库中读取:
~/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite数据库被复制到临时位置并以只读方式打开,因此不会触及或锁定在线存储。笔记正文以 gzip 压缩的 protobuf blob 存储在 ZICNOTEDATA.ZDATA 中;解码器将其解压并确定性地导航 protobuf 结构,以提取文本和格式化元数据。
写入通过 AppleScript (osascript) 进行。NoteStore 数据库归 Notes.app 所有,无法从外部安全写入,因此创建/更新/删除/移动操作通过 AppleScript 委托给 Notes.app。Reminders 子任务也使用 AppleScript,因为公共 EventKit API 不暴露它们。
笔记正文解码
正确读取笔记正文是该项目中较为精细的部分。正文不是纯文本——它是一个包含在 gzip blob 中的 protobuf 消息。解码器:
解压缩
ZDATA并确定性地导航到笔记文本消息(document → field 2 → field 3),然后读取文本字符串(field 2)。这取代了早期的一种启发式方法,该方法扫描“最干净”的字符串候选项,并在包含检查清单的笔记中返回损坏的二进制数据。遍历重复的按段落排列的元数据,以检测检查清单项及其完成/未完成状态,用
- [x]前缀标记已完成项,用- [ ]前缀标记未完成项。
有两个细节对于正确性很重要:
Varints 是通过乘法(
* 2 ** shift)而不是<<运算符累积的,因为 JavaScript 的按位移位会截断为 32 位并破坏大的偏移量。跨度长度以 UTF-16 代码单元测量,与 Apple 存储它们的方式匹配,因此即使文本包含多字节字符或表情符号,检查清单标记也能保持对齐。
如果 SQLite 解码因任何原因失败,notes_get 会退而通过 AppleScript 读取笔记正文,这返回干净的文本,但无法恢复复选框状态(Apple 的 AppleScript body 属性不编码它)。
附件
图片附件从 ZICCLOUDSYNCINGOBJECT 的 ICAttachment/ICMedia 行读取(通过 Z_PRIMARYKEY/Z_ENT 动态解析,不是硬编码的,因为数字实体 ID 和 ZACCOUNT*/ZPARENT 列名在 macOS 版本之间会变化)。实际文件位于磁盘上的:
~/Library/Group Containers/group.com.apple.notes/Accounts/{account}/Media/{media id}/{generation}/{filename}notes_get 返回每个附件的 ID、文件名、类型、解析后的文件路径以及任何识别的 OCR 文本;notes_get_attachment 将图片附件作为 MCP 图片内容块获取。notes_search 将 OCR 文本折叠到搜索语料库中,因此仅出现在屏幕截图中的文本也是可查找的。不支持添加附件——请参阅下面的“已知限制”。
Reminders 的 flagged 和其他 AppleScript 独占读取
EventKit 的公共 API 没有 flagged 属性,因此它完全通过 AppleScript 读取和写入,并通过 ID 合并到 EventKit 来源的 Reminder 对象中。整个库的标记扫描相对较慢(AppleScript 每个属性的 IPC 开销),因此 reminders_list/reminders_search 仅在限定到单个列表时才包含 flagged;当需要在所有列表中跨列表查询时,请使用带有显式 flagged 过滤器的 reminders_query_where/reminders_view。
缓存
notesStore.ts 缓存打开的 SQLite 连接、检测到的模式以及每个笔记的解码正文,所有这些都通过在每次调用时比较源文件(及其 -wal/-shm 附属文件)的修改时间来失效——对在线 NoteStore 的写入总是会破坏缓存,因此这纯粹是性能提升,没有过时风险。解码正文还额外以 (Z_PK, 修改日期) 作为键,因此编辑过的笔记会获得新的缓存条目,而不是过时的命中。
要求与权限
macOS(在 macOS 26 / Tahoe 上测试)
Node.js 18+(使用
better-sqlite3访问 SQLite)Notes.app 和 Reminders.app 已设置并登录到账户
自动化权限:主机应用程序(例如 Claude Desktop)必须被允许控制 Notes 和 Reminders——macOS 会在首次使用时提示,或者在系统设置 › 隐私与安全性 › 自动化中授予
完全磁盘访问权限:主机应用程序需要能够读取位于
~/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite的 NoteStore 数据库——在系统设置 › 隐私与安全性 › 完全磁盘访问权限中授予
macOS 版本说明
ZICCLOUDSYNCINGOBJECT 内部的列名和数字实体 ID 会随 macOS/Notes.app 版本变化(例如,ZACCOUNT1 到 ZACCOUNT8 都曾在不同系统上被观察到作为实时文件夹→账户外键,而 ICAccount/ICAttachment/ICMedia 的 Z_ENT 值并不稳定)。notesStore.ts 的 detectSchema() 在每次缓存未命中时重新检测这些值,而不是硬编码任何一个——请参阅那里的注释,然后再硬编码新的列名。该项目针对 macOS 26 (Tahoe) 开发和测试;检测逻辑设计为兼容旧版本,但尚未验证。
安装
npm install
npm run build运行
npm start或者将 dist/index.js 注册为客户端配置中的 MCP 服务器命令。
项目布局
src/
index.ts MCP server + tool registrations
notes.ts Notes tool implementations (SQLite reads, AppleScript writes)
notesStore.ts NoteStore SQLite access + protobuf body decoder
reminders.ts Reminders tool implementations + local template/saved-view storage
applescript.ts Shared runAppleScript() helper (argv-only, never string-spliced)
markdown.ts Markdown -> Notes-compatible HTML converter
swift/
reminders-daemon.swift Persistent EventKit daemon (NDJSON over stdio)
scripts/
test-phase2.mjs Protobuf/checklist decoder tests (+ pinned full-pipeline fixtures)
test-markdown.mjs Markdown -> HTML converter tests
test-schema-detection.mjs Schema-detection sanity checks against the live DB
dist/ Compiled output (generated by `npm run build`)Reminder 模板和已保存的筛选视图(reminders_save_template、reminders_save_view)作为 JSON 存储在 ~/.apple-notes-reminders-mcp/ 下——服务器端没有用于这些的数据库,因为 EventKit 本身没有这样的概念。
关于权限和隐私的说明
所有读取操作都在本地针对本地 NoteStore 数据库的临时副本进行。服务器本身不会将任何内容发送出设备。服务器要求的访问权限与用户对自己 Notes 和 Reminders 已有的权限相同。
测试
npm run build && node scripts/test-phase2.mjs # protobuf/checklist decoder
npm run build && node scripts/test-markdown.mjs # markdown -> Notes-HTML converter
npm run build && node scripts/test-schema-detection.mjs # schema detection sanity (live DB)test-markdown.mjs 是完全确定性的。test-phase2.mjs 的单元测试部分(varint 安全性、检查清单边缘情况、置顶全管道夹具)是自包含的;其最后的“真实数据库笔记”部分以及整个 test-schema-detection.mjs 会读取真实的在线 Notes 数据库,并且只有在具有完全磁盘访问权限和实际笔记数据存在时才会通过——在其他机器上(除了原作者的那台)预期会出现失败/错误(test-phase2.mjs 的数据库部分特别引用了仅在那一个库中存在的笔记 ID)。
已知限制
文件夹重新父级化未实现。 已实机确认 Notes.app 的 AppleScript
move <folder> to <folder>不可靠——它间歇性地抛出错误(item N of every folder kan niet worden opgevraagd)或静默无操作,无论文件夹引用来自folder id、whose筛选器还是手动扫描。文件夹重命名和删除是可靠的并已实现;将某个文件夹重新父级化到另一个文件夹下则未实现,因为发布一个会不可预测地失败的工具比没有更糟糕。重命名/删除嵌套文件夹(通过 Notes.app 界面创建,而不是由本服务器创建)是支持的——传递其完整的"Parent/Child"路径。无法通过此服务器添加附件。 读取附件完全支持(见上文)。添加附件需要 Notes.app 界面——曾研究过基于 Shortcuts-CLI 的桥接(
shortcuts run <name> -i <path>),但发现作为零设置工具不可行:它只接受一个输入文件,无法同时传递目标笔记,并且shortcutsCLI 只能运行一个已存在的快捷指令,无法创建一个。请参阅notes.ts顶部的注释查看完整说明。音频转录不公开。 图片附件的 OCR 文本是公开的(
notes_get、notes_search)。数据库中也有一个类似于音频转录的列(ZTEMPORARYTRANSCRIPTDATA),但它是一个不透明的 blob,并且没有可用的音频附件来逆向工程其格式——留给将来有真实测试数据的贡献者处理。已删除的文件夹可能需要超过一分钟才能从
notes_list_folders中消失。 已实机确认:删除本身在 Notes.app 中是即时的(并且立即可见给 AppleScript),但 SQLite 行的软删除标志可能滞后 60 秒以上,似乎取决于 iCloud 同步往返——比通常在其他地方看到的重命名/创建的约 5 秒 SQLite 滞后长得多。这不是本服务器能缩短的;在notesStore.ts中已记录,供那些追查看似缓存错误的人参考。“智能文件夹” 作为 Reminders 所具有的通用 Notes.app 功能实际上并不存在——数据库中的
ZFOLDERTYPE=1仅区分内置的“最近删除”文件夹和普通文件夹。对此标志的只读支持存在(notes_list_folders上的isSmartFolder);基于标签的分组(notes_list_tags)对于 Notes 而言更接近“已保存的智能列表”。Reminders “列表分区”(一个较新的 Reminders.app 分组功能)不被读取——EventKit 不暴露它们,这样做意味着要逆向工程 Reminders 自己单独的磁盘存储,本轮未尝试。
工具
Notes
工具 | 用途 |
| 列出所有文件夹——ID、名称、嵌套路径、账户、智能文件夹标志、笔记数量 |
| 列出笔记,可选文件夹过滤,支持排序 + 分页(limit/offset) |
| 按名称或ID获取笔记,包含附件元数据 |
| 获取图片附件,作为MCP图像块 |
| 一次性读取文件夹中的所有笔记,解码正文,支持排序 + 分页 |
| 在所有文件夹中搜索标题/正文/OCR文本,支持排序 + 分页 |
| 创建笔记(markdown/html/文本正文) |
| 更新笔记(替换/追加/前置;附件安全防护) |
| 删除笔记 |
| 创建文件夹 |
| 重命名文件夹(顶级或嵌套,按路径) |
| 删除文件夹(其中的笔记移至“最近删除”) |
| 将笔记移动到其他文件夹 |
| 列出笔记中使用的 |
| 列出“最近删除”中的笔记 |
| 从“最近删除”中恢复笔记 |
| 按基于单词的过滤器(文件夹、搜索、标签)统计/列出笔记 |
| 批量删除匹配的笔记(需确认) |
| 批量移动匹配的笔记(需确认) |
提醒事项
工具 | 用途 |
| 列出所有提醒列表 |
| 列出提醒事项,可选列表过滤,支持排序 + 分页 |
| 按名称或ID获取提醒事项 |
| 按名称/备注/列表搜索提醒事项 |
| 提醒事项应用风格的智能列表:今天/已计划/逾期/紧急/已标记/已完成 |
| 创建提醒事项(自然语言截止日期、标记、重复、提前/位置提醒) |
| 在一次原生调用中创建多个提醒事项(单次数据库提交) |
| 更新提醒事项 |
| 标记为已完成/未完成 |
| 删除提醒事项 |
| 创建列表 |
| 重命名列表 |
| 删除列表及其提醒事项 |
| 添加子任务(AppleScript——EventKit 无公开子任务 API) |
| 完成/恢复子任务 |
| 批量删除已完成的提醒事项,可选限定范围到某个列表 |
| 按基于单词的过滤器统计/列出提醒事项 |
| 批量删除匹配的提醒事项(需确认) |
| 批量完成/恢复匹配的提醒事项(需确认) |
| 批量将匹配的提醒事项移动到其他列表(需确认) |
| 保存一个命名的提醒事项模板 |
| 列出已保存的模板 |
| 删除已保存的模板 |
| 从模板创建提醒事项,支持每次调用时覆盖参数 |
| 保存一个命名的基于单词的过滤器作为可复用视图 |
| 列出已保存的视图 |
| 删除已保存的视图 |
| 运行已保存的视图并返回匹配的提醒事项 |
This server cannot be deployed
Maintenance
Related MCP Connectors
Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.
Google Keep-style notes app with an MCP server for AI agents to read/write notes.
An MCP server that used to create notes
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceAn MCP server that enables AI assistants like Claude to access and manipulate Apple Notes on macOS, allowing for retrieving, creating, and managing notes through natural language interactions.82MIT
- AlicenseAqualityDmaintenanceAn MCP server that connects Claude Desktop to Apple Reminders on macOS via AppleScript.59 npmMIT
- AlicenseAqualityBmaintenanceAn MCP server that enables LLM agents to list, read, create, update, delete, and search Apple Notes on macOS.620 npmAGPL 3.0
- FlicenseNot gradedqualityCmaintenanceAn MCP server that gives AI assistants access to your Apple Notes, Reminders, and Contacts — with optional BERT-powered semantic search.1-