内容
# mac-mcp
一款只读的MCP服务器,通过stdio向AI代理暴露来自原生macOS应用程序(邮件、便笺、日历、提醒事项、联系人、消息、Spotlight)的数据。
使用[Vite+](https://viteplus.dev/)和Bun启动。状态:邮件域已发货;其他域正在开发中。
## 状态
| 领域 | 状态 |
| --------- | -------------- |
| 邮件 | 已发货(v0.1) |
| Spotlight | 已发货 |
| 联系人 | 已发货 |
| 日历 | 已发货 |
| 提醒事项 | 已发货 |
| 便笺 | 计划中 |
| 消息 | 计划中 |
服务器从设计上来说是只读的。没有任何CLI标志、环境变量或配置键可以启用写入。回归测试会扫描每个JXA模板以查找可写入的Apple Events短语(`set readStatus`、`move to`、`delete`、`send`等),并扫描每个工具/域模块以确保它们只生成只读系统命令(`osascript`、`mdfind`)。
## 要求
- macOS 14或更新版本(15+解锁Apple Mail类别支持)
- [Bun](https://bun.sh) 1.3+
- 授予终端/MCP客户端完全磁盘访问权限(用于读取Apple的本地数据存储)
- 为Mail.app授予自动化权限(在列出帐户时在第一个JXA调用时授予)
## CLI
```bash
mac-mcp serve # 在stdio上启动MCP服务器(默认)
mac-mcp init # 编写~/.mac-mcp/config.toml模板
mac-mcp doctor # 探测macOS权限,打印检查清单
mac-mcp status # 以JSON格式打印每个域的索引健康状况
mac-mcp index # 批量构建域索引
mac-mcp rebuild --domain <name> # 重建单个域的索引
```
## 邮件工具
九种只读MCP工具,以及`index://status`资源。
| 工具 | 功能 |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mail_list_accounts` | 列出所有邮件帐户,显示名称+UUID。 |
| `mail_list_mailboxes` | 列出每个帐户的邮箱,当前未读计数。 |
| `mail_get_emails` | 按时间顺序排列的电子邮件列表。可选`account`、`mailbox`、`category`(主要/交易/更新/促销)、`filter`(all/unread/flagged/today/last_7_days)、`before`/`after`(YYYY-MM-DD)和 **`group_by`** 按未读状态、类别或帐户分组。 |
| `mail_get_email` | 通过Mail.app整数ID获取完整的电子邮件,包含正文、收件人、头部。 |
| `mail_get_email_links` | 从电子邮件正文中提取每个URL和`List-Unsubscribe` / `List-Help` / `List-Archive`头部。返回`(url, kind, text?, inHeader?)`记录。可选`kinds`过滤、去重和限制。 |
| `mail_get_email_attachments` | 列出电子邮件的附件元数据:索引、文件名、内容类型、大小、处置、选项内容ID。 |
| `mail_get_email_attachment` | 通过0-based索引获取附件的字节为base64。默认上限5 MiB,硬上限10 MiB;较大的附件返回一个错误信封,描述实际大小。 |
| `mail_resolve_addresses` | 批量解析1到100个裸电子邮件地址 against 本地AddressBook。返回每个电子邮件的联系人摘要,如果精确匹配,则返回null。子字符串匹配被过滤掉。 |
| `mail_search` | 跨主题/发件人/正文的FTS5 BM25搜索,带有范围、帐户、邮箱、类别和日期过滤器。 |
### Apple Mail类别感知
邮件的内置分类(主要、交易、更新、促销)原生支持macOS 15+。服务器在启动时探测`message_global_data.model_category`列,并在旧版macOS上干净地降级为无类别输出。`category`过滤器和`group_by: "category"`都优雅地遵循这一点。
### 本地索引
邮件域维护一个SQLite + FTS5索引在`~/.mac-mcp/mail.db`:
- WAL模式,`synchronous=NORMAL`,反向规范化`is_unread`/`is_flagged`列用于索引排序。
- 磁盘优先状态协调同步(NEW / DELETED / MOVED diffs in pure SQL)。
- 默认每5分钟后台同步(可配置)。
- 死信队列通过`index://status`显示解析失败。
## Spotlight工具
一个只读工具:`spotlight_search`.
| 输入 | 类型 | 默认 | 注释 |
| ------- | --------------------------------- | -------- | ----------------------------------------------------------------------------------------- |
| `query` | 字符串 | 必需 | 普通文本或完整mdfind元数据查询语法(`kMDItemContentType == "public.image"`)。 |
| `path` | 字符串 | 无 | 限制在此目录树中。必须在 `$HOME` 下解析。 |
| `kind` | `"file"` \| `"folder"` \| `"any"` | `"any"` | 文件系统条目类型的后过滤。 |
| `limit` | 数字 | 25 | 硬上限100。 |
macOS Spotlight索引(`mds`)已经由操作系统维护;我们从不构建自己的索引。子进程运行`mdfind`,每个调用超时5秒;截断表示超出限制的匹配项仍然存在。
## 联系人工具
三个只读工具。
| 工具 | 功能 |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `contacts_list` | 跨每个AddressBook源合并联系人;输出按显示名称排序。 |
| `contacts_get` | 通过Apple的`ZUNIQUEID`(`<GUID>:ABPerson`)获取完整记录。包括每个电子邮件、电话、邮政地址、URL和备注文本。 |
| `contacts_search` | 按`name`(first/last/nick/organisation)、`email`(规范化)、`phone`(数字或last-four)或`all`进行子字符串搜索。 |
跨源去重使用`(displayName, primaryEmail)`的软键;冲突保留完整性得分更高的源,并将丢弃的源UUID折叠到保留的记录中。电话规范化为E.164,当AddressBook存储解析的部分(国家代码+区号+本地号码);否则,我们从显示值中剥离空格和标点符号。没有FTS5索引 - 对索引列的LIKE查询在个人地址簿的容量下足够快。
## 日历工具
| 工具 | 功能 |
| ------------------------- | -------------------------------------------------------------------------------------------------------- |
| `calendar_list_calendars` | 列出每个日历,带有id、标题、类型(`Local`、`CalDAV`、`Birthdays`、`Subscribed`等)和颜色。 |
| `calendar_list_events` | 按开始时间排序的事件。可选日历ID和YYYY-MM-DD日期范围。 |
| `calendar_get_event` | 通过UUID获取完整的事件,带有描述和上次修改。 |
| `calendar_search` | 跨标题、描述和位置的子字符串搜索,带有可选日期范围。 |
来源:`~/Library/Group Containers/group.com.apple.calendar/Calendar.sqlitedb`(现代macOS路径)。日期通过Core Data的2001-01-01纪元进行往返。
## 提醒事项工具
| 工具 | 功能 |
| -------------------------- | ---------------------------------------------------------------------------------------------------- |
| `reminders_list_lists` | 每个帐户的每个列表;`type`区分常规列表和智能列表。 |
| `reminders_list_reminders` | 按到期日期排序的提醒事项。可选列表ID和`open`/`completed`/`all`状态(默认`open`)。 |
| `reminders_get_reminder` | 通过标识符获取完整的提醒事项,带有备注、开始/到期/完成日期。 |
| `reminders_search` | 跨标题和备注的子字符串搜索。 |
来源:`~/Library/Group Containers/group.com.apple.reminders/Container_v1/Stores/`下的每个帐户的一个SQLite文件。域查询每个存储并合并结果。
## MCP客户端配置
```json
{
"mcpServers": {
"mac": {
"command": "bunx",
"args": ["-y", "github:DaniAkash/mac-mcp"]
}
}
}
```
安装后运行`mac-mcp doctor`以验证权限。
## 开发
```bash
bun install # 安装依赖
bun test # 单元测试+集成测试(CI安全;e2e测试跳过)
bun run test:e2e # 实时端到端测试;需要macOS + FDA + Mail.app数据
bun run check # 校验 + 格式化 + 代码质量检查,并行
bun run lint # vp lint(oxlint with full TS typecheck)
bun run fmt # vp fmt --check
bun run fmt:fix
```
没有构建步骤:Bun直接执行TypeScript二进制文件(`src/bin.ts`),适用于开发期间的`bun src/bin.ts`和通过`bunx -y github:DaniAkash/mac-mcp`为消费者提供。软件包提供其`src/`目录,Bun处理其余部分。
### 端到端测试
`tests/e2e/`包含测试,针对真实的Mail.app + Envelope Index在本地机器上运行。它们需要完全磁盘访问权限和配置的邮件帐户,因此只有在设置了`MAC_MCP_E2E=1`时才会运行。 CI从不设置此环境变量;测试在每次CI运行时干净地跳过。
覆盖范围包括直接针对实时数据的五个邮件工具(排序、未读/类别/帐户分组、多帐户过滤器、电子邮件往返)以及一个完整的MCP_stdio往返,该往返生成实际的`mac-mcp serve`二进制文件,并将其作为真正的MCP客户端通过JSON-RPC驱动。
```bash
# 授予终端完全磁盘访问权限。
bun run test:e2e
```
## 许可证
MIT