内容
bluebubbles-mcp
BlueB 的 MCP 服务器 — 从任意 MCP 客户端访问 iMessage。
从头开始构建,没有第三方 MCP 依赖,除了官方的 [`mcp`](https://pypi.org/project/mcp/) SDK 和 [`httpx`](https://pypi.org/project/httpx/)。
## 前置条件
- Python 3.11+
- 运行中的 [BlueBubbles 服务器](https://bluebubbles.app),并启用 API 访问
## 安装
```bash
git clone https://github.com/metaember/bluebubbles-mcp.git
cd bluebubbles-mcp
uv sync
```
## 配置
在您的 MCP 客户端配置文件中添加(例如 Claude Code 的 `~/.claude/settings.json````json
{
"mcpServers "bluebubbles": {
"command": " "args": ["--directorypath/to/blue-mcp", "run", "python", "-m",_mcp.server"],
"env": {
"BLUELES_URL": "https://your-bluebubbles-server",
BUBBLES_PASSWORD": "your-server-password"
}
}
}
```
### 限制写收件列表)
默认情况下,服务器可以给任何人设置 `BLUEBUBBLES_WRITE_ALLOWLIST`逗号分隔的电话号码和/或电子邮件列表**所有写操作**(发送、反应、附件、调度、群组编辑、删除/离开)到件人。它在服务器端强制执行,因此 MCP 客户端 HTTP 传输的客户端)无法绕过它。
```jsonc
"BLUEBUBBLES_WRITE_ALLOWLIST": "+15551234567, partner@example.com",
"BLUEBUB_ALLOWLIST_REGION": "US" // 可选,解析本地号码
```
行为:
- **未限制(向后兼容)。**已设置但为空**(`""`)→ 拒绝所有,安全失败- 号码按规范的 E.164 格式匹配) 123-4567` 和 `+155` 是等效的;电子邮件不区分大小- 对于**群聊**,*每个*参与必须在列表中,否则写入将被阻止。无法解析参与被拒绝(关闭失败)。
- 读取工具**不**消息-GUID 写入(`edit_message`、``)不被覆盖 — 它们只对已起作用,无法到达新收件人。可能会添加 `BLUEBUBBLES_READ_ALLOWLIST`。
### 私有 API 与 AppleScript
BlueBubbles 可以通过两种方式驱动 Messages。**AppleScript** 适用于任何安装,无需额外发送纯文本/附件。**私有 API**(ubbles Helper + 部分禁用 SIP)额外解锁了、编辑/取消发送、打字指示器、回执、群组回复,以及 SMS 发送。
服务器启动时,会读取 `/server/info` 并根据实际情况进行调整:
- **发送**使用私有 API(如果存在),并在不存在时回落到 AppleScript — 因此 `send_message` 在裸安装上有效,而不是出错。
- **需要私有 API 的工具反应、编辑/取消打字、执、群组管理、iMessage/Face用性检查)**在不可用时从工具列表**,因此客户端永远不会看到可能失败的工具。
BLUEBUBBLES_PRIVATE_API` 覆盖自动
```jsonc
"BLUEBUBBLES_PRIVATE_API": "auto" // 默认:内省 /server/info "true" — 强制启用(假设私有)
// "false" — 强制禁用(仅;隐藏私有 API 工具)
```
如果 `/server 在启动时无法读取,则检测失败打开(假设私有),因此暂时的故障不会隐藏一半的工具集 `/server/info` 读取还发现了用户自己的 i `get_my_address` 工具公开。如果检测错误多个句柄,请覆盖它:
```jsoncBLUEBUBBLES_MY_ADDRESS": "+15551234567" // 或 you@icloud.com
```
###人姓名
BlueBubbles 的消息和聊天数据显示和电子邮件地址,而不是姓名。为了避免模型不断号码,读取响应**会丰富每个句柄旁边的Name`**,并且 `find_contact` / `find 允许通过姓名而不是号码找到人员。
解析的,并且每个会话都会缓存:响应地址会在首次看到处理 `/contact/query`,然后重用。通过以下方式禁用它(为了更轻的响应或如果您的联系慢):
```jsonc
"BLUEBLES_RESOLVE_NAMES": "false" // 默认:启用
```
`find_contact` / `find_chats`仍然有效 — 它们是显式的。
###度保护
代理可以回复对话的过时快 它在一段时间前读取了线程,新消息到达了空白在未看到新消息的情况下作出了回应。新鲜度保护在服务器端和每个代理强制执行,在聊天中仅在该代理**在最近一小时内读取,并且从那时起没有新消息到达**。:您必须在发送消息之前读取现有的聊天 —的良好卫生习惯。 通过 `create_chat` 启动对话不受影响;它仅用于首次联系,并且启用新鲜度保护后,拒绝访问现有聊天 — 使用 `send_message` 进行这些操作。)
**工作原理。** 保护措施保持每个代理的 *水位标记* — 每个代理在每个聊天中看到的最新消息(乐观并发,如线程的 `ETag`):
- 使用 `get_chat_messages聊天记录会记录水位标记。只有该工具会记录像 `get_unats` 这样的扫描不会要回复,您必须故意打开实际的线程。
发送消息之前,服务器会重新检查聊天的最新从您的水位标记以来有任何新消息(来自 对方、另一台设备上或),或者您的读取时间超过 TTL,则发送消息会被,并附有重新读取和重新计划的- 您自己的发送会推进您的水位标记,因此不会阻止您的下一次详见 [`docsness-guard.md`](reshness-guard**默认启用。**BLUEBUBBLES_FRESHNESS=off` 禁用。调整:
```jsonc
"BLUEBUBBLES_FRESHNESS": "off", // 默认:on
"BLUEBUBRESHNESS_IDENTITY": "session", //如何区分(默认)
"BLUEBUBBLES_TTL_SECONDS": "3600", // 读取保持“新鲜”的时间(默认 1 小时)
BUBBLES_WATERMARK_MAX_AGENTS":" // 内存默认 100新鲜度检查是**每个代理的**,代理。`UBBLES_FRESHNESS` 选择如何区分:
- **`session`**):使用 MCP 传输会话 — 适用于 **stdio一个代理)和 **直接 HTTP** (每个连接的会话)。在 HTTP依赖于有状态会话CP 的默认);如果您将无状态 HTTP新鲜度结合使用,服务器**拒绝启动**每次发送都会被- **`meta`**者在请求 `_meta` 中标记的每个代理的 `agentId` 来标识代理。仅在**代理/**后面需要,其中每个代理共享一个传输会话session` 无法区分它们空气锁合约/freshness-guard.md`](docs/fuard.md)。
###凑响应和发送
默认情况下,消息读取返回**紧凑的预测** — 助手需要的字段(`guid`、`text` + `contactName`、`isFromMe`、时间戳、附件名称、反应/回复链接)而不是完整的原始 BlueBubbles 对象,这大大减少了令牌使用量。在任何读取工具上传递 `extended=true` 以获取完整的原始字段。
消息读取(`get_chat_messages`、`search_messages`、`get_recent_messages`)_address`** 按发送消息的人过滤 — 传递电话号码/电子邮件,或 `"me"` 表示用户自己的消息按真正的发送者进行(当 `isFromMe` 时为用户,否则为消息的句柄), 1:1 和群聊中都是正确的。
| 工具 | 描述 | 注解 |
|------|-------------|-------------|
| `ping` | 检查服务器连接读 |
| `get_server_info` | 服务器信息和健康状态 | 只读 |
| `get_my_address` | 用户自己的 iMessage 地址(用于识别自己的消息) |
| `list_chats` | 按出对话 | 只读 |
| `get_chat 聊天详细信息,含参与者 | 只读 `get_chat_messages` | 聊天中的读 |
| `search_messages` | 按文本时间范围搜索 | 只读 |
| `get | 按 GUID 获取单个消息 | 只读 |
|acts` | 所有联系人 | 只读 `lookup_contact`电话/电子邮件查找 只读 |
| ` | 按联系人(未知电话/电子邮件) | 只| `find_chats` | 按姓名查找人的聊天 | 只读 |
| `check_imessage 检查 iMessage 注册 | 只读 |
| `check_facetime` | 检查 FaceTime 注册 | 只读 |
| `query_handles` | 列出/搜索已知句柄 |
| `get_handle` | 按地址获取句柄 | 只读 |
| `get_focus_status` | 联系人的专注/请勿打扰状态 | |
| `find_my_devices` | 查找我的您的设备的地点 | 只读 |
| `findriends` | 查找我的 — 朋友的地点 | |
| `list_scheduled_messages` |未来消息 | 只读 `get_scheduled | 按 ID 获取单个预定消息 | 只读 |
| `get_recent_messages` | 最近 N 分钟聊天的消息 | 只读 |
| `get_unread_chats` | 有未读消息的聊天 + 它们最新的消息 | 只读 |
| `get_attachment_info` | 附件元数据 | 只读 |
| `download_attachment` | 以 base64 下载附件 | 只读 `get_group_icon` | 下载群聊图标读 |
| `mark_chat_read` | 发送已 | 幂等,全开放 |
|_chat_unread` | 标记聊天为未读(本地) | 幂等 |
| `rename_group` | 重命名群聊幂等set_group_icon` | 设置群聊图标 | 幂等 |
| `start_typing` |字指示器 | 全开放 |
| `stop` | 停止打字指示器 | 全开放 |
| `send_message`到现有聊天(1 或群聊 全开放 |
| | 按电子邮件启动新的:1 对话 | 全开放 |
| `create | 创建群聊 + 第一条消息 || `send | 发送文件附件 | 全开放 |
| `send_multipart` | 发送文本附件作为一条消息 | 全开放 |
| `` | Tapback 反应 | 全开放 `edit_message`已发送的消息 || `schedule_message` | 安排未来 全开放 |
|_scheduled_message` |定消息 | 全开放 |
| `add_part 添加到群 全开放 |
| `unsend_message` |消息 | 销毁 `remove` | 从群删除 | 销毁,全 `leave_chat` | 离开群聊 | 销毁,全开放 |
| `remove_group_icon` | 删除群聊图标 | 销毁,全开放 |
| `delete_message` | 删除单个消息 | 销毁,全开放 |
| `delete_chat` | 删除对话 | 销毁,全开放 |
| `delete_scheduled_message` | 取消预定消息 | 销毁,全开放 |
## 通过 HTTP 运行(Docker)
服务器默认使用 stdio 通信。设置 `MCP_TRANSPORT=streamable-http` 以通过 [Streamable HTTP](https://modelcontextprotocol.io) 改为 HTTP 的 MCPhttp://<host>:8000/mcp` 连接。Docker 镜像为您设置了此功能。
```sh
docker build -t bluebubbles-mcp .
docker run --rm -e BLUEBUBBLES_URL -e BLUEBUBBp :800bubbles-mcp
Compose 服务 —存储在容器的`env_file` 或 Docker 机密),对该工具保持
```yaml
bluebubbles:
build: .
environment:
BLUELES_URL: ${BLUEBUBBLES BLUEBUBBLES_PASSWORD: ${BLUEBLES_PASSWORD}
unless-stopped注意:
- HTTP未经身份验证不要公开暴露它在私有/上(如果的客户端通过 Compose 网络,则删除已发布的)。
- `BLUEBUBBLES_URL必须可以从内部**访问 —可以解析的主机名例如 Bluebles 主机的局或 `host),而不是 `## 许可证