内容
# icloud-mcp
一款给予 AI 助手**只读**权限访问您的 iCloud 邮件和日历的 [Model Context Protocol](https://modelcontextprotocol.io) 服务器,支持 IMAP 和 CalDAV。凭证存储在您的操作系统密钥环中(默认为 macOS 钥匙串)——绝不会存储在配置文件或代码仓库中。
默认目标是 iCloud,但每个端点都可以覆盖,因此它适用于任何标准的 IMAP/CalDAV 提供商。
## 状态
**默认只读;写入严格需要确认。** 邮件、日历和联系人可以列出、搜索和读取,但无权修改任何内容:IMAP 连接以只读模式打开,消息体使用 `BODY.PEEK[]` 获取,因此消息甚至不会被标记为已读。
可变工具涵盖邮件(`send_mail`、`reply_mail`、`forward_mail`)、日历(`create_event`、`update_event`、`delete_event`)和联系人(`create_contact`、`update_contact`、`delete_contact`)——但所有这些工具都**需要设置 `ICLOUD_ENABLE_WRITES=1`才能启用**,即使启用后,每次写入也需要交互式确认(MCP 询问)。请参阅[写入(需要确认)](#写入需要确认)。
### 写入(需要确认)
写入权限有两种保护机制:
1. **操作开关** —— 写入工具除非在服务器环境中设置了 `ICLOUD_ENABLE_WRITES=1`,否则会拒绝并显示解释性错误。
2. **逐次确认** —— 启用后,每个写入工具都会回调客户端以确认确切的操作,然后再执行。破坏性操作(删除事件/联系人)也受到相同的保护 —— 没有额外的强制标志,只有相同的确认。
iCloud 颁发单个特定于应用程序的密码,涵盖 IMAP、SMTP、CalDAV 和 CardDAV —— 没有范围限定的“仅写入”凭证 —— 因此写入安全性是**结构性的**:邮件通过单独的、新的 SMTP 连接发送(读取路径的 IMAP 客户端无发送能力),并且确认标志 + 交互式确认每次都保护写入。
## 安装
```bash
pip install git+https://github.com/eodozzy/icloud-mcp
```
或者用于本地开发:
```bash
git clone git@github.com:eodozzy/icloud-mcp
cd icloud-mcp
python3 -m venv .venv && .venv/bin/pip install -e ".[test]"
```
需要 Python 3.11+。
## 凭证
为您的 Apple ID 生成一个[特定于应用程序的密码](https://appleid.apple.com) (绝不能使用您的主密码),然后将其存储在您的密钥环中:
```bash
# macOS
security add-generic-password -a "you@icloud.com" -s "icloud-mcp" -w "xxxx-xxxx-xxxx-xxxx"
```
在其他平台上,使用跨平台的 [`keyring`](https://pypi.org/project/keyring/) 库 —— `keyring set icloud-mcp you@icloud.com` 在任何地方都有效。
用户名来自环境变量 `ICLOUD_USERNAME`。密码解析顺序为:
1. OS 密钥环(`ICLOUD_KEYRING_SERVICE`,默认为 `icloud-mcp`,+ 用户名)
2. `ICLOUD_APP_PASSWORD` 环境变量(备用)
要**重用现有的密钥环条目**(例如,一个名为 `talos-icloud` 的条目),请设置 `ICLOUD_KEYRING_SERVICE=talos-icloud`。
## 配置
设置 `ICLOUD_USERNAME`(必需)。所有其他设置均为可选 —— 请参阅 [`.env.example`](.env.example) 以获取完整的端点/时区覆盖列表。
## 注册到 MCP 客户端
服务器通过 **stdio** 与 MCP 通信:客户端启动 `icloud-mcp` 命令作为子进程,并通过 stdin/stdout 与其通信。“安装”到客户端只是意味着告诉客户端运行哪个命令以及传递哪些环境变量 —— 密码本身保留在密钥环中,绝不会出现在客户端配置文件中。
如果 `icloud-mcp` 不在您的 `PATH` 中(例如,您安装到了虚拟环境中),请使用启动器的绝对路径,例如 `/path/to/repo/.venv/bin/icloud-mcp`。
### Claude Code
```bash
claude mcp add icloud \
--env ICLOUD_USERNAME=you@icloud.com \
--env ICLOUD_KEYRING_SERVICE=icloud-mcp \
-- icloud-mcp
```
然后运行 `claude mcp list` 以确认。添加 `-s user` 以使其在所有项目中可用,而不仅仅是当前项目。
### Claude 桌面版
将服务器添加到 Claude 桌面版的配置文件中。在 macOS 上,这是:
```
~/Library/Application Support/Claude/claude_desktop_config.json
```
(在 Windows 上:`%APPDATA%\Claude\claude_desktop_config.json`。)
最简单的方法是打开它 **设置 → 开发者 → 编辑配置**。添加一个 `mcpServers` 键,旁边是文件中已有的内容 —— **不要** 粘贴第二个顶级 `{ ... }` 对象,否则文件将变为无效 JSON:
```json
{
"mcpServers": {
"icloud": {
"command": "icloud-mcp",
"env": {
"ICLOUD_USERNAME": "you@icloud.com",
"ICLOUD_KEYRING_SERVICE": "icloud-mcp"
}
}
}
}
```
如果文件已经包含其他键,请将 `mcpServers` 合并为一个兄弟节点(记住键之间的逗号):
```json
{
"someExistingSetting": "...",
"mcpServers": { "icloud": { "...": "..." } }
}
```
然后 **完全退出** Claude 桌面版(⌘Q,而不仅仅是关闭窗口)并重新打开它。服务器将显示为一个*本地 MCP 服务器*,其工具变得可用。
注意:
- **首次调用会提示获取 Keychain 访问权限。** macOS 会询问 `icloud-mcp` 是否可以读取密钥环项目;请单击 **始终允许** 以避免重复提示。
- **Claude 桌面版可能会重写此文件**,当它保存自己的首选项时,会删除它不识别的手动添加的键。如果服务器在您更改其他设置后消失,只需重新添加 `mcpServers` 块即可。
## 工具和资源
**工具**(模型调用):
| 工具 | 描述 |
|---|---|
| `list_mail` | 列出一个文件夹(默认为 INBOX),最新的在前,可选 `since_date` |
| `search_mail` | 对收件箱(或命名文件夹)进行全文搜索 |
| `list_folders` | 列出可用的 IMAP 邮箱文件夹名称 |
| `get_message` | 通过 UID 获取一个消息,包含完整正文 |
| `list_events` | 指定时间窗口内的日历事件 |
| `search_events` | 查找标题与文本匹配的事件,限定在某个时间窗口内 |
| `list_calendars` | 所有日历的名称 |
| `list_contacts` | 列出通讯录联系人(姓名、电子邮件、电话号码、组织) |
| `search_contacts` | 查找姓名、组织和电子邮件中与文本匹配的联系人 |
| `send_mail` ⚠️ | 发送纯文本电子邮件 |
| `reply_mail` ⚠️ | 回复通过 UID 的消息(引用原文;可选 `reply_all`) |
| `forward_mail` ⚠️ | 将通过 UID 的消息转发给新收件人 |
| `create_event` ⚠️ | 创建日历事件 |
| `update_event` ⚠️ | 编辑通过 UID 的事件(仅限您传递的字段) |
| `delete_event` ⚠️ | 删除通过 UID 的事件 |
| `create_contact` ⚠️ | 创建新联系人 |
| `update_contact` ⚠️ | 编辑通过 UID 的联系人(合并到现有的 vCard) |
| `delete_contact` ⚠️ | 删除通过 UID 的联系人 |
⚠️ 写入工具需要 `ICLOUD_ENABLE_WRITES=1` 并确认每个操作 —— 请参阅 [写入(需要确认)](#写入需要确认)。
**资源**(被动上下文):
| URI | 描述 |
|---|---|
| `icloud://mail/inbox/recent` | 最近的收件箱消息 |
| `icloud://calendar/today` | 今日和明日事件 |
## 行为说明
- **空/缺失的头部:** 消息的 `Subject` 头部缺失或为空时,渲染为 `(no subject)`;空白或缺失的 `From` 头部渲染为 `(unknown)`。(有些邮件有空主题行而不是没有主题行 —— 两者都规范化。)
- **摘要** 优先使用 `text/plain` 部分;对于仅 HTML 的邮件,剥离标签(丢弃 `<style>`/`<script>`/`<head>` 内容),因此您仍然可以获得可读的预览。
- **双重包装的正文:** 一些发送者(例如 USPS Informed Delivery)将冗余的 MIME 头块嵌入到解码正文的顶部。剥离前导 `Content-*`/ `MIME-Version` 头块,以免这些头部泄漏到摘要或正文中。
- **`since_date` 是按日期粒度** 的,在 IMAP 服务器的时区(iCloud 为 UTC)中进行评估,因此今天的 `since_date` 可能包含昨天晚上您的本地时间的消息。
## 开发
```bash
.venv/bin/pytest # 运行基于夹具的测试套件(无实时帐户)
.venv/bin/mcp dev -m icloud_mcp.server # 交互式 MCP 检查器
```
## 安全说明
- 特定于应用程序的密码仅存储在 OS 密钥环中 —— 绝不会存储在 `.env` 中,也绝不会被提交。
- 读取访问权限(邮件、日历、联系人)无法修改任何内容;IMAP 会话以只读模式打开。
- 写入权限**默认关闭**。它们需要 `ICLOUD_ENABLE_WRITES=1` **和** 每个操作的交互式确认,并且邮件通过与读取路径隔离的单独 SMTP 连接发送。
- 特定于应用程序的密码可以随时在 appleid.apple.com 上撤销,而不会影响您的 Apple ID。
## 许可证
MIT —— 请参阅 [LICENSE](LICENSE)。
---
不隶属于、不受 Apple Inc. 赞助或支持。iCloud 是 Apple Inc. 的商标。