mcpField
M
macOS Apps

macOS Apps

本地服务
github.com/elfensky生产力11 天前更新

关于 macOS Apps

macOS Apps 是面向 macOS 的本地 MCP 服务,可通过单一接口访问邮件、日历、提醒事项、备忘录等应用。它以指针和单独限量读取内容,并对写入进行分级、审计及删除预览。

主要功能

  1. 01访问多种 macOS 应用
  2. 02搜索结果以指针形式返回
  3. 03按需单独读取受限内容
  4. 04写入分级并记录审计日志
  5. 05删除、移动和发送默认预览

适用场景

  1. 01查询日历安排与空闲时段
  2. 02筛选待回复邮件并打开草稿
  3. 03预览并撤销邮件移动操作

MCP 相关

作为本地 MCP 服务,向客户端暴露 macOS 应用的搜索、读取和写入工具。可按应用关闭适配器,并通过只读模式禁用写入。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"elfensky-macos-apps": {
"command": "uvx",
"args": [
"macos-apps-mcp"
]
}
}
}
启动命令uvx macos-apps-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypimacos-apps-mcp0.15.1

工具

还没有获取到工具列表

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

详细介绍

macos-apps-mcp

macos-apps-mcp logo

elfensky/macos-apps-mcp MCP server

一个本地 MCP 服务,可在 macOS 上用于 Mail、Calendar、Reminders、Notes、 Messages、Contacts、Photos、Safari、Music 和 Shortcuts。搜索和列表操作会返回指针:一个 id、一行摘要,以及可在相应应用中打开该项目的链接。正文需单独获取,且有长度上限。 写入分级并记录审计日志;删除、移动和发送操作会先预览。仅支持 macOS。使用 Python + FastMCP + uv。请参阅 DESIGN.md 和 CHANGELOG.md。

你可以这样提问

  • “这周我的日历上有什么安排?周四下午什么时候有空?”
    events、free_busy
  • “哪些邮件需要回复?为第一封邮件起草一封回复。”
    mail_needs_response、mail_reply。回复会在 Mail 中作为草稿打开,不会发送。
  • “把收件箱里的新闻邮件移到 Archive。先给我看看。”
    mail_search、move_mail、mail_undo。默认会先预览移动操作。mail_undo 可以撤销该操作,但受下文所述已知限制影响。

安全与隐私

  • 本地运行。 不会收集遥测数据,也不会自行发起网络请求:仅使用本地 unix socket(从 shim 到 daemon)和 127.0.0.1 上的仪表板。调用时,只有三个工具会通过应用访问 Mac 之外的内容:发送工具(默认关闭)通过 Mail 发送邮件,safari_open 打开网页,run_shortcut 运行可能会访问网络的 Shortcut。
  • 三级权限。 分为读取、写入和外发。发送工具在你按应用启用之前不会提供:macos-apps-mcp allow-send mail(daemon)或 MACOS_APPS_ALLOW_SEND=mail(stdio)。MACOS_APPS_READ_ONLY=1 只注册读取工具,且优先于这两项设置。
  • 先试运行。 delete_draft、move_mail、trash_mail、mail_undo、 send_mail、reply_all、forward_mail、delete_reminder、delete_event、delete_note 和 update_note 的 dry_run 默认值为 true。其他写入操作在调用时会直接执行。mail_reply 只会打开草稿。
  • 审计日志。 所有写入操作都会记录到 ~/.local/state/macos-apps-mcp/audit.jsonl(若设置了 $XDG_STATE_HOME,则记录在其下)。 按 id 更新或删除项目时,也会记录该项目的原始状态。audit 工具可读取日志。
  • 邮件恢复。 移动或删除 Mail 邮件前,每封邮件都会以 .eml 文件的形式复制到 ~/.local/state/macos-apps-mcp/backup/mail/ 下。mail_undo 可撤销整批操作。没有工具会清空废纸篓。
  • 已知限制。 如果 Mail 只下载了部分邮件,备份中不会包含其附件。通过 Gmail 标签文件夹移动或移入废纸篓的操作会被拒绝,因为 Gmail 会在约 2 分钟后将其还原。sent: true 表示 Mail 已接受该邮件,并不代表邮件已送达。所有 Mail 相关说明。
  • 仪表板。 在已签名的 .app daemon 下,本地页面(仅限 127.0.0.1)会显示每项写入操作、其修改内容,以及每批 Mail 操作对应的备份。以下为虚构数据:

仪表板:三封新闻邮件已移至 Archive,每封都已备份,并显示撤销整批操作的提示

前 5 分钟

需要 macOS、Python ≥ 3.12 和 uv。uv 提供 uvx。此软件包已发布到 PyPI。将 MCP 客户端指向 uvx。它会获取软件包并运行,因此无需克隆,也无需指定 venv 路径:

{
  "mcpServers": {
    "macos-apps": {
      "command": "uvx",
      "args": ["macos-apps-mcp"]
    }
  }
}

如果 Claude Desktop 找不到 uvx,请将 "command" 设为它的完整路径:在终端运行 which uvx(默认安装 uv 时会显示 /Users/you/.local/bin/uvx)。

对于 Claude Code:

claude mcp add macos-apps --scope user -- uvx macos-apps-mcp

或者,不使用 claude mcp add,而是安装 Claude Code 插件。它会启动同一个服务,并添加一项技能 来指导你使用 dry-run 工作流。在 Claude Code 中,运行 /plugin marketplace add elfensky/macos-apps-mcp,然后运行 /plugin install macos-apps@macos-apps-mcp。

下文的 CLI 命令(allow-send、dedupe-mail)也以相同方式运行:uvx macos-apps-mcp allow-send。

先运行 doctor。 doctor 工具会报告已授予的权限,且不会打开任何对话框(每项 Automation 授权都会实时读取;未运行的应用会显示 not_running)。你在屏幕前时,doctor(request=True) 会打开 EventKit 和 Automation 对话框。服务需要:

  • EventKit:日历和提醒事项。
  • Automation:每个应用各打开一个对话框:Mail、Notes、Contacts、Safari、Messages、Music。
  • Full Disk Access(可选,不会打开对话框:在“系统设置”→“隐私与安全性”→“完全磁盘访问权限”中,为启动服务的应用开启此权限):Messages 内容、Photos、Mail 索引读取、提醒事项标签和子任务,以及 Notes 快速路径。没有此权限时,Notes 和部分 Mail 读取会使用较慢的路径。其余操作会返回错误或 coverage 说明。

使用 stdio 时,macOS 会将每项授权授予启动服务的应用(Claude Desktop、Terminal、VS Code),因此每个客户端都需要单独授权。已签名的 .app 守护进程则为所有客户端共用一组授权:docs/DAEMON.md。

只加载你会用到的应用。设置 MACOS_APPS_ADAPTERS_OFF=photos,music 后,不会为这些应用注册工具,因此客户端上下文中保留的工具会更少。使用守护进程时,请参阅关闭适配器。

从源代码开始(开发): 如果要开发服务本身,请使用此路径。

git clone https://github.com/elfensky/macos-apps-mcp && cd macos-apps-mcp
uv sync

然后将 MCP 客户端指向项目自己的 venv python——这样可以确保运行结果一致,并使用锁定版本的 PyObjC wheel:

{
  "mcpServers": {
    "macos-apps": {
      "command": "/absolute/path/to/macos-apps-mcp/.venv/bin/python",
      "args": ["-m", "macos_apps_mcp"]
    }
  }
}

为什么不选 apple-mcp?

Dhravya Shah 开创的 apple-mcp 是一个适用于所有 Apple 应用的 MCP 服务。它现在已归档。它会直接返回完整的笔记和邮件正文。本服务会返回指针,仅在请求时获取正文,并按等级限制每项写入操作。详见 CREDITS.md。

遇到问题?运行 doctor,并将其输出粘贴到 GitHub issue 中。报告会显示进程路径,发布前请先检查。

工具

读取操作会返回指针;每个适配器的结果都有上限。正文/内容需通过单独的、有上限的获取操作读取。设置 MACOS_APPS_READ_ONLY 后会完全跳过写入/操作(见下文)。

日历和提醒事项 — 读写(EventKit)
工具参数说明
eventswhen = today | week | YYYY-MM-DD列出事件指针
free_busystart、end(ISO),可选的 calendars ID返回时间范围内合并后的忙碌时段和空闲间隙;不含事件详情
remindersdue = today | overdue | this-week | 一个列表名称以 {results, coverage?} 的形式列出提醒事项;每个结果包含 folder、tags 和 parent(只读;需要 EventKit 和完全磁盘访问权限)
calendars / reminder_lists—用于指定写入目标的容器(ID + 名称)
create_event / update_event标题、开始时间、结束时间(ISO)、日历、地点、备注、all_day、recurrence、alarms(开始前的分钟数,最多 5 个;全天事件:从当地午夜起算,-540 = 当天 09:00)update 会按 ID 完全替换;但对于 alarms:省略时保留事件的闹钟,[] 则移除闹钟
delete_eventID、span、dry_rundry_run 只预览,不会删除;实际删除后会验证事件已删除(仅删除该次事件,不删除整个系列)
create_reminder / update_reminder标题、到期时间、列表名称、备注、priority(0–9)、开始时间、recurrenceupdate 会按 ID 完全替换
create_reminder_list名称在默认账户中新建列表;如果名称完全重复,则拒绝创建
complete_reminderID标记为已完成;完成父项时,会在 subtasks 下列出仍未完成的子任务;如果无法读取提醒事项存储,则拒绝执行且不做任何更改(需要 EventKit 和完全磁盘访问权限)
delete_reminderID、dry_run(默认 true)、with_subtasks按 ID 删除并确认已删除;如果父项有子任务,则必须设置 with_subtasks=true,否则会拒绝执行,因为删除父项也会删除子任务(需要 EventKit 和完全磁盘访问权限)

事件和提醒事项指针包含 folder,其值为日历或列表 ID;free_busy(calendars=…) 和写入工具(calendar=、list_name=)均接受此值。

提醒事项的 标签 和 子任务(tags、parent = 父项的 ID)从提醒事项存储中读取,且为只读;需要完全磁盘访问权限。如果无法读取该存储,仍会返回提醒事项,并由 coverage 说明原因。没有公共 API 可以写入标签或嵌套提醒事项,因此这里没有相应工具。

写入操作通过 名称或 Pointer.id 指定容器;如果名称不唯一,则会报错,而不会猜测。重复规则 使用 RFC 5545 RRULE:FREQ、INTERVAL、COUNT、UNTIL、BYDAY(月度和年度规则支持 2TU 或 -1FR 等序数)、BYMONTHDAY、BYMONTH、BYYEARDAY 和 BYSETPOS,例如 FREQ=MONTHLY;BYDAY=2TU;COUNT=6。重复提醒事项必须有到期日期。BYWEEKNO、BYHOUR、BYMINUTE、BYSECOND 和 WKST 会按名称拒绝(EventKit 会保存 BYWEEKNO,但只展开第一个日期);任何超出范围的值或 RFC 5545 禁止的组合也会被拒绝;写入后会再次检查每个部分。不符合规则的开始日期仍会被接受——RFC 5545 将其计为第一次出现——事件结果会说明第一次出现是额外的一次。

邮件 — 先按 ID 读取 + 创建草稿并打开(自动化)

默认情况下禁用发送:读取、create_draft 和 mail_reply 都不会发送邮件——它们会打开撰写窗口供你查看。外发操作(send_mail、reply_all、forward_mail)存在,但只有在操作员通过 MACOS_APPS_ALLOW_SEND 明确选择启用后才会运行;即使如此,dry_run 仍默认为 True。

工具参数说明
mailsubject-OR-sender 子串匹配收件箱;id = 稳定的 RFC822 message-id,message:// 深层链接
mail_bodyid, mailbox单封邮件的纯文本,有长度限制并标记截断;mailbox 是从 mail_search 结果中原样传回的 folder 值(或规范名称)——任何邮箱都可以,不只是收件箱
mail_searchsubject, from_, to, mailbox, account, since, until, unread, flagged, has_attachments, body, limit通过 Envelope Index 进行索引搜索(静态存储——除非 account= 是显示名称,否则不会启动 Mail;显示名称会通过 Mail 解析;UUID 只使用纯 sqlite,未知名称则会报错);每封邮件返回一个结果(优先选择 INBOX);has_attachments 不包括内嵌图片;body 尽力匹配(仅限已索引内容)
mail_index_bodiesrebuild从静态存储的 .emlx 构建/刷新启用后才使用的全文搜索(FTS)正文索引;可恢复,限制大小;跳过尚未下载的邮件(设计如此,覆盖不完整)
mail_threadid, limit(默认 100)完整会话,按时间从早到晚;包括你发送的邮件;已去重;超过 limit 时舍弃最早的邮件(回复时读取会话)
mail_overview—列出所有邮箱及其总数和未读数,未读优先;包括 Junk/Trash/All Mail;实时统计(存储的计数会过时),按不同邮件计数;账户名称来自 Mail(会启动它),无法连接时使用 UUID 代替;On My Mac 始终显示名称
mail_attachmentsmailbox(搜索结果中的 folder,原样传入——或 inbox/sent/drafts/trash/junk),可选 query按邮件列出附件名称/大小/下载状态;适用于草稿
mail_needs_response—列出可能需要你回复的收件箱邮件,并按 reason 排序(已标记 / 未读且直接发送 / 未回复且直接发送);仅读取邮件头,不读取正文
mail_awaiting_replydays(1–365,默认 3)列出你发送时间至少为 days 天且尚未收到回复的邮件(基于真实的 In-Reply-To/References 线程),按时间从早到晚排列,原因是 awaiting-reply
create_draftto, subject, body打开草稿供审核——绝不发送;返回一个定位符
mail_replymessage_id, mailbox, reply_body, include_quote原生线程回复(设置 In-Reply-To/References),引用原文并打开供审核——绝不发送
drafts—将 Mail 草稿列为指针(id + subject — to 收件人)
delete_draftid, dry_run按 message-id 删除一封草稿;dry_run 预览操作
create_mailboxname(使用 / 创建嵌套邮箱),account创建文件夹;自动创建缺失的父文件夹。没有对应的删除功能——delete <mailbox> 无法通过脚本执行,因此只能在 Mail.app 中删除。在 Gmail 账户中,新文件夹是标签,move_mail 会拒绝操作
move_mailids(≤25), from_mailbox, to_mailbox, dry_run移动/归档/重新归档;移动前会备份并记录每封邮件,因而 mail_undo 可以将其还原。dry_run 默认为 True。跨账户移动后只保留一个副本。如果任一端是 Gmail 标签文件夹(移出标签会留下副本)或源是统一名称,则会拒绝操作
trash_mailids(≤25), mailbox, dry_run软删除,也是唯一可用的删除方式——Mail 的 delete 会将邮件移至账户的 Trash,其脚本字典中的任何功能都无法从那里彻底删除邮件。可通过 mail_undo 撤销;清空 Trash 需在 Mail.app 中自行操作。dry_run 默认为 True
mail_undoreceipt, dry_run反向重放 move_mail/trash_mail 回执;撤销操作本身也会备份,且可以再次撤销。对于移至 Gmail 标签或统一名称的回执,操作会被拒绝,并说明如何手动还原
update_mail_statusids(≤25), mailbox, read, flagged, flag_color标记已读/未读、加标记(+颜色)。重新执行并传入相反值即可撤销,因此 dry_run 默认为 False
mail_duplicateslimit仅报告——按邮箱统计冗余副本数量及最严重的案例。清理请使用下方的 dedupe-mail CLI;此工具无法删除邮件
send_mailto, subject, body, cc, bcc, html, from_address, dry_run受 MACOS_APPS_ALLOW_SEND 门控;dry_run 默认为 True
reply_allmessage_id, mailbox, body, include_quote, dry_run受门控;使用原生线程标头
forward_mailmessage_id, mailbox, to, dry_run受门控;原文和附件均会完整转发——没有附言参数(编写正文会破坏原文和附件,已通过设备验证)
消息 — 通过 chat.db 获取内容(只读;需要“完全磁盘访问”权限)
工具参数说明
messages_chats—对话列表(id + 名称);不包含内容,无需 FDA
messages_searchquery, limit搜索消息文本(解码 attributedBody),按时间从新到旧排列
messages_withcontact (phone/email), country, limit与某人的近期消息;country = 国家/地区电话区号或 2 字母地区代码(默认使用区域设置,绝不使用 +1)
message_bodyid根据 guid 获取一条消息的完整文本
备忘录 — 读取 NoteStore.sqlite + 按需获取正文
工具参数说明
notestitle, snippet 或 body words{results, truncated?, plane?, coverage?} — 匹配的备忘录(id + 摘要),优先显示标题/摘要匹配项,然后是仅正文匹配项;在“完全磁盘访问”权限范围内于内存中搜索正文(跳过已锁定的备忘录);正文词语仅按空格和标点拆分,因此在未加空格的中文或日文文本中,只有通过标题或摘要才能找到词语;忽略变音符号和智能标点差异
notes_all—每条有效备忘录(id +“帐户 / 文件夹”+ 摘要),不包括“最近删除”中的备忘录
note_bodiesids (≤ 50)按需获取纯文本正文 → [{id, body}]
create_notetitle, body, optional folder name返回稳定的 x-coredata id;如果文件夹名称未知或有歧义,则拒绝操作,不会猜测
update_noteid, title, body按 id 完整替换标题和正文;保留稳定 id,并在写入后验证
delete_noteid, expect_title, dry_run移至“最近删除”;dry_run 可预览
其他只读上下文
工具参数返回内容
contactsname substring联系人卡片(姓名、组织、首个电话号码 + 电子邮件)
photossearch string{results, truncated?} 指针(标题 · 文件名 · 日期),按时间从新到旧排列,最多 25 个;匹配文件名、标题、描述、关键词、地点、人物和标签。id 为 Photos uuid;仍接受旧版 <UUID>/L0/001 id
photo_albums—{results, truncated?} 相册指针(id、title (n photos)、文件夹路径),最多 100 个
photo_infophoto id日期、位置、地点、人物、部分 EXIF 信息、像素尺寸、类型;绝不返回图像字节或缩略图
safari_tabs—所有打开的标签页(url + 标题)
shortcutsname substring(留空 = 全部)用户的 Shortcuts;id = 稳定 UUID,shortcuts:// 深层链接
ping / now / doctor—(doctor 可选用 request=True 触发权限提示)健康检查 / 时间 / 权限诊断
audit可选的 since (ISO datetime)最近的写入审计条目(按时间从新到旧排列)——macos-apps-mcp 所做的更改,包含更改前/后的指针(足以手动撤销)
usage—各工具调用次数 + 从未使用的工具列表,用于清理很少使用的工具
操作(写入)
工具参数说明
create_contactgiven_name, family_name, organization
run_shortcutname 或 id, 可选的 input_text运行一个 Shortcut;返回有长度限制的输出片段
safari_openurl在新标签页中打开;纯主机名 → https://;仅允许 http/https
export_photophoto id, dest_dir(位于允许的根目录内)将编辑后的静态图像(未编辑时则为原图)另存为新文件,文件名为 <original stem>_<id prefix>.<ext>,绝不覆盖现有文件,大小上限为 250 MiB;仅存在于 iCloud 的照片状态为 absent(不会下载任何内容);拒绝导出视频;Live Photo 仅导出静态图像;仅新增,不覆盖,并记录审计
只读模式

设置 MACOS_APPS_READ_ONLY=1(或 true / yes)以仅注册读取工具——跳过所有写入和操作工具,作为安全部署保护。(读取操作仍可能打开应用 / 读取本地存储。)

关闭适配器

设置 MACOS_APPS_ADAPTERS_OFF=photos,music(以逗号分隔的适配器名称列表),即可不为这些应用注册工具。 在守护进程模式下,文件 ~/.local/state/macos-apps-mcp/adapters_off 保存相同的列表,并在重启后生效。详情请参阅:docs/DAEMON.md。

控制面板

在守护进程模式下,http://127.0.0.1:47632 会显示审计记录、健康状态、适配器开关、使用情况和 Mail 备份。运行 macos-apps-mcp dashboard,即可使用页面密钥打开控制面板。详情请参阅:docs/DAEMON.md。两张截图使用的都是虚构数据。

控制面板中的一次日历编辑:旧时间带删除线,新时间显示在旁边,并展示模型发出的确切工具调用 适配器开关:每个应用及其权限、工具数量和调用次数
清理重复邮件

Mail 会累积同一封邮件的冗余副本——在 UI 中拖动会复制而非移动,Gmail 会在标签和「所有邮件」下同时显示同一封邮件,迁移也会在两个账户中留下副本。读取工具已经会将它们合并,因此这里仅涉及服务器上实际存储的内容。向会话请求 mail_duplicates(),查看问题,然后在终端中清理:

macos-apps-mcp dedupe-mail                       # preview every mailbox — changes nothing
macos-apps-mcp dedupe-mail --verbose             # also list the sets it will NOT touch
macos-apps-mcp dedupe-mail --execute --mailbox=<folder-url>   # do one mailbox for real

出于与 allow-send 相同的原因,这是 CLI 命令,而不是工具:数千次删除操作要交给一个有 30 秒上限的串行工作进程执行,需要数小时,而这是人类主动发起的工作。它只会合并字节完全相同(大小和发送日期都相同)的副本——Mail 无法指定某个特定副本,因此会保留 Mail 留下的那个;字节相同正是确保安全的条件。不一致的副本组会被计数、保留,并列在 --verbose 输出中。

冗余副本会被移至废纸篓,每次分小批处理,每批都会生成自己的 mail_undo 回执。清空废纸篓需要你在 Mail.app 中操作——这里的任何操作都无法彻底删除邮件。

此操作很慢:每组重复邮件约需 1 分钟;对于真实的 IMAP 账户(Mail 的 whose 查询会扫描整个邮箱),因此大文件夹需要数小时。请在可以一直运行的终端中操作,每次处理一个邮箱。操作可恢复——每次运行都会根据 Mail 的索引重新计算计划,因此中断不会造成任何损失,重新运行只会发现需要处理的项目变少。Mail 无法删除的副本组会被报告出来,不会在后台静默重试。

出站(发送)模式

发送功能默认关闭——服务只会创建草稿,绝不会发送。通过以下命令开启:

macos-apps-mcp allow-send mail    # or: messages / mail,messages / all / off
macos-apps-mcp allow-send         # print the current setting

此操作会持久保存启用设置并重启守护进程,以便重新注册(注册发生在导入时,因此无法避免重启——之后请重新连接 MCP 客户端)。这是一个CLI 命令,而不是工具:此限制是对您授权的保护,因此模型既不能自行授权发送,也不能在您的会话过程中擅自重启服务。

同样的设置也可通过环境变量 MACOS_APPS_ALLOW_SEND 配置,stdio 服务会读取此变量(只要设置了该变量,其值始终优先于持久化设置):

值效果
未设置(默认)完全不注册发送工具
mail仅启用 Mail 出站功能(send_mail、reply_all、forward_mail)
mail,messages指定适配器(逗号分隔列表)
1 / true / yes / all启用所有适配器的出站功能

MACOS_APPS_READ_ONLY 始终优先:同时设置两者时,不会注册任何发送工具。

发送工具接受 dry_run 参数,其默认值为 True**——**这与按 ID 定位的删除操作恰好相反。删除的目标是读取操作已返回的项目;而发送操作会构造收件人,收件人错误才是关键风险。试运行完全不会调用 Mail,并会报告解析后的信封;传入 dry_run=False 才会实际发送。reply_all 是唯一的例外:其试运行会读取原始邮件中的实际收件人(to/cc),但绝不会发送,因为调用方无法预先确定的正是这组收件人。

send_mail / reply_all / forward_mail 成功时返回的结果(sent: True)表示 Mail 已接受邮件——并不表示邮件已送达。经设备验证:格式完全正确的邮件在 send 返回后,仍可能在 Mail 的发件箱中滞留数分钟而未送达;而一封收件人为空、被困住的邮件可能会堵塞发件箱,导致之后有效的发送操作排队等待,最终也无法发出。每个结果还会报告 outbox_pending,即 Mail 当前发件箱中的邮件数量;当该值大于零时,结果会附带一条 note,说明邮件尚未确认送达,并提示检查 Mail ▸ 发件箱。

运行 doctor 工具,检查发送功能是否已实际启用——deployment.outbound 会列出当前启用发送功能的所有适配器(若无则为 []),其值依据上述相同的注册逻辑生成,而非重新读取原始环境变量,因此与已注册的工具始终一致;deployment.outbound_note 会以文字说明当前状态。

在守护进程部署模式下,在 MCP 客户端配置中设置 MACOS_APPS_ALLOW_SEND 不会产生任何效果:客户端的 env 块会传给 shim,而不是在导入时读取该变量的长期运行守护进程;随附的 LaunchAgent plist 也没有 EnvironmentVariables 键。这正是 allow-send 命令存在的原因——它会写入守护进程可读取的状态(~/.local/state/macos-apps-mcp/allow_send,固定写入用户主目录,确保写入该设置的 shell 与读取它的 launchd 进程始终一致),并且重启后仍会保留,不像 launchctl setenv。请参阅 docs/DAEMON.md(“守护进程下的出站(发送)模式”)。

开发

uv sync
uv run pytest                   # unit tests (mock at the adapter boundary)
uv run pytest -m integration    # real macOS / EventKit / TCC — run manually, never in CI
uv run ruff check .             # lint (config in pyproject.toml)
uv run ruff format .            # format
uv run macos-apps-mcp                  # run the server (stdio)

ruff(lint + format,行长度为 88)和 pytest 是 CI 的门禁检查——完整工作流见 CONTRIBUTING.md。

相关先行项目与致谢

macos-apps-mcp 建立在先前的工作之上——它借鉴的 Apple Mail MCP、引用的 EventKit/Photos 服务、开创统一 Apple MCP 模式的项目,以及它依赖的 FastMCP / PyObjC / MCP 规范。请参阅 CREDITS.md。

评论

支持 Markdown

第一次接触 MCP?

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

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