关于 imessage-max
iMessage Max 是用 Swift 编写的 macOS iMessage MCP 服务,可读取、搜索和发送对话。其工具围绕用户意图设计,让 Agent 能处理聊天和附件,而非直接操作原始数据库表。
主要功能
- 01按联系人、名称或内容查找聊天
- 02读取并筛选消息
- 03搜索消息并获取上下文
- 04通过 Contacts 将电话号码解析为姓名
- 05浏览和获取图像附件
- 06向选定聊天发送消息
适用场景
- 01查找并查看与联系人的对话
- 02搜索主题并检查相关上下文
- 03检查未读及近期活跃对话
- 04查找并获取共享图像
MCP 相关
通过 stdio 和 HTTP 将 iMessage 操作作为 MCP 工具提供,并支持新旧协议协商。仅实现工具,不提供提示词或资源。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
iMessage Max
适用于 iMessage 的 MCP(Model Context Protocol)服务。它可让 AI Agent 读取、搜索和发送你的消息,并在此过程中将电话号码解析为联系人姓名。
使用 Swift 编写。单个二进制文件,无运行时依赖。
分发方式
一个 Swift 实现,位于 swift/,通过以下方式发布:
- GitHub Releases(arm64,临时签名)
- Homebrew(
cyberpapiii/tap) - 源码构建
- Codex 插件元数据(
.codex-plugin/) - Claude Desktop MCPB 元数据(
mcpb/)
功能
- 13 个围绕人们实际提出的问题设计的工具,而非围绕数据库表设计
- 通过 macOS 通讯录将电话号码解析为姓名
- 三种图像规格:视觉版(1568px)、缩略图(400px)、完整原图,因此照片不必以原始大小传输
- 消息按会话分组,间隔达到或超过 4 小时即拆分
- 附件列表会标明每个文件是在磁盘上还是已卸载到 iCloud
- 原始 SQLite3 和 Core Image GPU 加速
- 仅读取 chat.db。发送消息需要 Messages.app 的自动化权限
为什么要开发这个项目
大多数 iMessage 工具会暴露原始数据库结构,每个用户意图都需要调用 3-5 次工具。这个 MCP 提供与用户意图对应的工具:
"What did Contact A and I talk about yesterday?"
→ find_chat(participants=["Contact A"]) + get_messages(since="yesterday")
"Show me the exact details for this thread before I reply"
→ get_chat_details(chat_id="chat123")
"Show me photos from the group chat"
→ list_attachments(chat_id="chat123", type="image")
"Find where we discussed the launch timeline"
→ search(query="launch timeline")
常见的 Agent 工作流
Agent 将这些工具作为简短工作流使用,而不是孤立地单次调用,效果最佳。
Agent 应将 chat123 这样的 chat_id 值视为工具调用和精确发送时使用的内部标识符。向用户说明结果时,应使用返回的聊天名称、群组名称或根据参与者生成的标签,而不要说“聊天 123”。
找到合适的对话,然后阅读
find_chat(participants=["Contact A"])
get_chat_details(chat_id="chat123")
get_messages(chat_id="chat123", since="yesterday", limit=50)
当联系人比确切的会话 ID 更重要时,使用此工作流。
先搜索,再深入查看
search(query="launch timeline", limit=10)
get_context(message_id="msg_456", before=5, after=10)
当你知道主题但不清楚它在哪个对话中讨论过时,使用此工作流。
检查需要关注的内容
get_unread()
get_active_conversations(hours=24, min_exchanges=2)
在广泛浏览聊天列表后,使用此工作流查看未读会话和活跃对话。
安全地处理附件
list_attachments(chat_id="chat123", type="image", since="30d")
get_attachment(attachment_id="att123", variant="vision")
使用 list_attachments 查找分享文件的消息。它会返回确切的附件 ID,并标明每个文件是否在磁盘上,因此你可以在获取文件前了解其状态。
需要精确定位时再发送
find_chat(participants=["Contact A", "Contact B"])
send(chat_id="chat456", text="Please use the latest draft")
发送敏感消息时,建议先解析出确切的聊天,再使用 chat_id,确保消息发送到预期的会话中。
安装
Homebrew(推荐)
brew tap cyberpapiii/tap
brew install imessage-max
从源码安装
git clone https://github.com/cyberpapiii/imessage-max.git
cd imessage-max/swift
swift build -c release
# Binary is at .build/release/imessage-max
有关本地开发、高级设置和签名安装流程,请参阅:
协议支持
iMessage Max 是一个支持两个协议时代的 MCP 服务。两种传输方式(stdio 和 HTTP)都可同时提供这两个时代的支持,并按请求选择:
| 时代 | 修订版 | 生命周期 | 选择方式 |
|---|---|---|---|
| 现代 | 2026-07-28 | 无状态,按请求提供 _meta | 请求 _meta 中的 io.modelcontextprotocol/protocolVersion(或 server/discover) |
| 旧版 | 2025-03-26 … 2025-11-25 | initialize + 会话 | initialize 请求 / Mcp-Session-Id |
现代客户端通过 server/discover 探测,并通过 HTTP 发送必需的 MCP-Protocol-Version、Mcp-Method 和(针对 tools/call 的)Mcp-Name 标头。旧版客户端仍可照常工作。无需迁移客户端;只要仍有实际客户端依赖旧版支持,就会继续保留。
此服务仅实现工具。它有意不提供提示词、资源、补全、订阅、任务或 MRTR 流程。官方一致性测试套件会针对这两个时代运行,基线见 docs/conformance-baseline.yml。
客户端图标元数据
iMessage Max 为 MCP 协议的主要接口和使用自有元数据的客户端打包格式提供图标:
- MCP
2025-11-25初始化响应包含 PNGserverInfo.icons。 - 每个工具都会提供一个精简的 PNG 工具图标。
- Codex 插件元数据位于
.codex-plugin/plugin.json,使用assets/codex/icon.png和assets/codex/logo.png。 - Claude Desktop / MCPB 元数据位于
mcpb/manifest.json,使用mcpb/assets/下的 PNG 资源。
已提交的 PNG 源文件集位于 assets/icons/ 下,尺寸为 16x16、32x32、
64x64、128x128、256x256 和 512x512。
设置
1. 授予“完全磁盘访问权限”
读取 ~/Library/Messages/chat.db 所必需:
- 打开“系统设置” →“隐私与安全性” →“完全磁盘访问权限”
- 点击 + 添加二进制文件
对于 Homebrew 安装,二进制文件位于 /opt/homebrew/Cellar/imessage-max/VERSION/bin/imessage-max(而非 /opt/homebrew/bin/ 下的符号链接)。使用以下命令查找:
# Open the folder containing the actual binary
open $(dirname $(readlink -f $(which imessage-max)))
对于源码构建,请从克隆目录添加 .build/release/imessage-max。
更改授权后,请重新启动服务;macOS 仅会将“完全磁盘访问权限”应用于更改后启动的进程。
在文件选择器中,按 ⌘+Shift+G 并粘贴路径,即可直接前往。
2. 授予“通讯录”访问权限
将电话号码解析为姓名所必需。只有从终端启动服务器时,它才会请求访问权限;launchd 和 MCP 客户端会以无头模式启动服务器,而无头进程不会弹出请求。请在终端中运行 imessage-max --request-contacts-access 一次以授予访问权限,然后重启服务。--contacts-policy request|skip(或 IMESSAGE_MAX_CONTACTS_POLICY)可覆盖终端检测结果。
手动操作方式:前往“系统设置” →“隐私与安全性” →“通讯录” →添加 imessage-max。
3. 配置 MCP 客户端
将 imessage-max 添加到 MCP 客户端的服务配置中。
许多 MCP 客户端使用类似这样的 JSON 结构:
对于 Homebrew:
{
"mcpServers": {
"imessage": {
"command": "/opt/homebrew/Cellar/imessage-max/VERSION/bin/imessage-max"
}
}
}
对于源码构建:
{
"mcpServers": {
"imessage": {
"command": "/path/to/imessage-max/swift/.build/release/imessage-max"
}
}
}
如果客户端使用不同的配置格式,请将其指向同一个二进制文件路径。
4. 重新连接 MCP 客户端
保存配置后,重新连接或重启 MCP 客户端。服务器应会显示在可用工具中,你可以使用 diagnose 验证连接。
工具
find_chat
按参与者、名称或近期内容查找聊天。
默认情况下,Messages.app 已筛选到“未知发件人”或“垃圾信息”中的聊天会被隐藏。响应中包含 filtered_hidden,表示筛选器从此视图中移除的聊天数量;传入 include_filtered=True 即可查看这些聊天。
find_chat(participants=["Contact A"]) # Find a direct chat
find_chat(participants=["Contact A", "Contact B"]) # Find a group with both
find_chat(name="Project Group") # Find by chat name
find_chat(contains_recent="latest draft") # Find by recent content
find_chat(name="Project Group", include_filtered=True) # Also search junk / unknown-sender chats
get_chat_details
查看已知会话的详情,无需打开完整对话。
get_chat_details(chat_id="chat123") # Participants, handles, state, last message
get_chat_details(chat_id="chat123", include_shared_summary=false) # Skip recent shared summary
get_messages
使用灵活的筛选条件检索消息。返回媒体元数据。指定 chat_id 的查询不会经过筛选。
get_messages(chat_id="chat123", limit=50) # Recent messages
get_messages(chat_id="chat123", since="24h") # Last 24 hours
get_messages(chat_id="chat123", from_person="Contact A") # From specific person
get_messages(chat_id="chat123", has="links") # Messages that contain a URL
has 可按内容类型筛选(links、attachments、images)。links 包含 Messages 存储为 URL 预览气泡的链接消息(macOS 26 上的常见情况)。
群组系统消息(更改群组名称、添加或移除成员、有人离开)返回时会将 text 设为 null,并附带一个 event 对象:
{"type": "rename", "title": "Trip"}、{"type": "participant_added", "participant": "Alice"}、
{"type": "participant_removed", ...}、{"type": "left"},或者对于服务器无法命名的事件类型,返回
{"type": "other", "item_type": N}。聊天预览会用文字描述相同事件
(“将群组名称更改为 Trip”)。
回应、回复、编辑:每条消息可能包含 reactions
(标准轻点回 Tapback 显示为 ["❤️ alice"];自定义表情符号会显示其本身;贴纸回应使用标记 🩵 sticker)、reply_to
(发起回复的消息对应的 msg_<rowid>)、reply_count 和 edited: true。
已移除的 Tapback 不会返回。这四个字段都是可选的,值为空时会省略。
search 和 get_context 也会携带相同的四个字段。
这些字段均为只读;由于服务器无法发送 Tapback 和编辑撤回,diagnose 仍会将
tapbacks 和 edit_unsend 报告为 unsupported。
get_messages_since
按到达顺序获取所有聊天中 ROWID 游标之后的新消息。将返回的 next_rowid 作为 since_rowid 传回,以进行分页或轮询。由于已处理的行(表情回应、已过滤的聊天或孤立项)会推进游标,next_rowid 可能大于最后一条返回消息的 rowid。省略 since_rowid 可仅获取当前游标。游标仅适用于这台 Mac 的 chat.db。
get_messages_since() # Current cursor only
get_messages_since(since_rowid=234000) # Messages after that row
get_messages_since(since_rowid=234000, limit=50)
get_messages_since(since_rowid=234000, chat_id="chat123")
get_messages_since(since_rowid=234000, include_filtered=True)
| 参数 | 类型 | 默认值 | 含义 |
|---|---|---|---|
since_rowid | integer | omitted | 排他的 ROWID 游标。省略或传入 -1 可仅获取当前游标。 |
chat_id | string | omitted | 限定为一个聊天(chat123 或 123) |
limit | integer | 100 | 要返回的最大消息数(1–500) |
include_filtered | boolean | false | 包含垃圾信息/未知发件人的聊天 |
include_reactions | boolean | true | 为返回的消息附加表情回应字符串 |
响应示例:
{
"since_rowid": 234000,
"messages": [
{
"id": "msg_234001",
"rowid": 234001,
"chat": {"id": "chat12", "name": "Alice Smith"},
"from": "Alice Smith",
"text": "on my way",
"ts": "2026-09-02T15:00:00Z"
},
{
"id": "msg_234010",
"rowid": 234010,
"chat": {"id": "chat40", "name": "Weekend"},
"from": "me",
"text": "see you there",
"ts": "2026-09-02T15:01:00Z"
}
],
"next_rowid": 234050,
"has_more": false,
"current_rowid": 234050,
"stalled": false,
"filtered_hidden": 1
}
轮询方法:先调用一次但不传入 since_rowid,保存 next_rowid,然后按需定期传入该值进行调用。当 stalled 为 true 时,等待约一秒,然后使用相同的游标重试。切勿将 next_rowid 与消息 ID 进行比较。
get_attachment
按附件 ID 获取图像内容,并可选择不同分辨率。
get_attachment(attachment_id="att123") # Default: vision (1568px)
get_attachment(attachment_id="att123", variant="thumb") # Quick preview (400px)
get_attachment(attachment_id="att123", variant="full") # Original resolution
| 变体 | 分辨率 | 用途 | Token 成本 |
|---|---|---|---|
vision(默认) | 1568px | AI 分析、OCR | ~1,600 tokens |
thumb | 400px | 快速预览 | ~200 tokens |
full | 原始 | 最大细节 | 不定 |
list_chats
浏览带预览的近期聊天。
默认情况下,Messages.app 过滤到“未知发件人”或“垃圾信息”中的聊天会被隐藏。响应中包含 filtered_hidden,表示过滤器移除的聊天数量;传入 include_filtered=True 可查看这些聊天。
list_chats(limit=20) # Recent chats
list_chats(is_group=True) # Only group chats
list_chats(since="7d") # Active in last week
list_chats(include_filtered=True) # Also show junk / unknown-sender chats
search
对消息进行全文搜索。
默认情况下,垃圾信息和未知发件人的聊天会被隐藏。响应中包含 filtered_hidden;传入 include_filtered=True 也可搜索这些聊天。
search(query="draft") # Search all messages
search(query="budget", from_person="Contact A") # From specific person
search(query="launch", is_group=True) # Only in group chats
search(query="draft", include_filtered=True) # Also search junk / unknown-sender chats
get_context
获取指定消息前后的消息。
get_context(message_id="msg_123", before=5, after=10)
get_active_conversations
查找近期有来回交流的聊天。
get_active_conversations(hours=24)
get_active_conversations(is_group=True, min_exchanges=3)
list_attachments
按消息分组浏览共享项目。每行都包含后续获取所需的准确附件 ID。
list_attachments(type="image", since="7d")
list_attachments(chat_id="chat123", type="any")
Messages 隐藏的附件(hide_attachment,例如链接预览负载)不会列出;get_attachment 仍可通过 ID 返回这些附件。
get_unread
获取未读会话或未读消息。默认按聊天汇总。
默认情况下,垃圾信息和未知发件人的聊天会被隐藏。响应中包含 filtered_hidden;传入 include_filtered=True 可将其包含在内。
get_unread() # Summary by chat for last 7 days
get_unread(since="24h") # Summary by chat for last 24 hours
get_unread(format="messages") # Row-level unread messages
get_unread(include_filtered=True) # Also show junk / unknown-sender chats
send
发送消息或文件附件(需要 Messages.app 的自动化权限)。
send(to="Contact A", text="Checking in")
send(chat_id="chat123", text="Please use the latest draft")
send(chat_id="chat123", file_paths=["/path/save-the-date.jpg"])
send(to="Contact A", file_paths=["/path/reference.png"], text="Sharing the file here")
规则:
to和chat_id必须且只能提供其中一个- 必须至少提供
text或file_paths之一 - 如果两者都提供,则先发送文件,最后发送文本
附件路径必须是绝对路径(或以 ~/ 开头)。路径会逐级检查,如果任何部分是符号链接,则会拒绝该路径(允许 /tmp、/var、/etc,并按 /private/... 读取)。打开文件时不会跟随链接;文件必须是常规文件,并会从已打开的文件句柄复制到 ~/Pictures/imessage-max-staging/ 下权限为 0700 的私有目录中;Messages 只会接触该副本。如果你这台 Mac 上的 ~/Pictures 本身是符号链接,则在其指向真实目录之前,send 将拒绝暂存文件。
diagnose
排查配置和权限问题。
diagnose() # Returns: database status, contacts count, permissions, capabilities
当 chat.db 可读且 Messages Automation 正常时,capabilities.verified_send 为 supported;当数据库可读但 Automation 不正常时,为 degraded;当数据库不可读时,为 permission-gated。
database.features 列出这台 Mac 上 chat.db 中存在的可选列,以 table.column 为键(例如 message.date_edited)。某项为 false 时,读取该列的工具会降级运行,而不会失败:没有 message.thread_originator_guid 时不会提供 reply_to 或 reply_count,没有 message.date_edited 时不会提供 edited,没有 message.associated_message_emoji 时不会提供自定义表情符号反应文本。
contacts.status 的值为 authorized、limited、denied、restricted、not_determined、not_requested_headless、skipped_ci 或 <status>_load_failed。跳过权限提示的无头进程会报告 not_requested_headless,修复建议会指出使用 --request-contacts-access。
发布检查
发布前,请完成以下检查:
- docs/RELEASING.md,发布流程
- docs/validation/2026-04-09-release-checklist.md,现场抽查
- swift/Tests/iMessageMaxTests/SendManualValidation.md,在 Messages.app 中进行手动发送检查
发送补充说明:
- 目标明确无误时,消息会立即发送;没有确认关卡。目标不明确时会拒绝发送,并返回
status: "ambiguous"。confirm参数已弃用且会被忽略(仅为兼容性而保留)。授权通过用户与 Agent 的对话以及客户端的工具审批界面完成,而不是在服务端完成。
发送结果语义(文本发送会在发送后通过 chat.db 验证):
status: "confirmed"表示在验证时间窗口内于 chat.db 中找到外发消息记录,且没有错误;verified_message_guid是相应凭据。这并不代表送达回执。status: "uncertain"表示传输层已接受发送,但在轮询窗口内未找到消息记录;请使用get_messages跟进status: "mismatch"表示消息发送到了与预期不同的聊天;不要将其视为成功status: "failed_delivery"表示找到了消息记录,且其中记录了投递错误;消息未送达,verified_message_guid和错误代码是相应凭据status: "partial_failure"表示多载荷发送在后续某个载荷失败前已发送部分载荷;message会列出已发送和失败的内容。只重试失败的载荷,绝不要重试整个调用status: "sent"表示无法进行验证(数据库不可读);仅表示传输层已接受发送status: "pending_confirmation"表示 Messages 已接受附件发送,但在轮询窗口内无法确认文件传输已完成status: "failed"表示发送失败status: "ambiguous"表示无法安全地解析目标
Disposition 和 retry_safe
每个 send 响应还包含 disposition 和 retry_safe。disposition 描述传输状态(Apple 事件是否已发出);status 描述 chat.db 状态。
| status | disposition | retry_safe |
|---|---|---|
| confirmed、uncertain、mismatch、sent | completed | false |
| failed_delivery | completed | true |
| pending_confirmation | may_have_completed | false |
| failed(传输) | 取自 send | 仅当为 not_started 时是 true |
| failed(验证 / 解析) | not_started | true |
| partial_failure | 取自失败载荷的 disposition | false |
| ambiguous | not_started | true |
{"status":"failed","disposition":"not_started","retry_safe":true,"error":"Could not find chat 'iMessage;-;does-not-exist' in Messages.app."}
{"status":"failed","disposition":"may_have_completed","retry_safe":false,"error":"Send operation timed out. Messages.app may be unresponsive."}
说明:
pending_confirmation是一种正常的非致命附件状态,不等同于硬性失败- 精确聊天发送的目标是由
chat_id标识的现有对话 - 返回 JSON 结构的工具会同时返回 MCP
structuredContent和面向旧版客户端的传统文本内容
示例:
{"status":"confirmed","verified_message_guid":"...",...}表示已在 chat.db 中验证送达{"status":"pending_confirmation","success":false,...}表示 Messages 已接受附件,但 MCP 尚无法确认最终完成状态
故障排查
联系人显示为电话号码
运行 diagnose 并查看 contacts.status。如果状态为 denied 或 not_determined:
- 在“系统设置”→“隐私与安全性”→“通讯录”中添加
imessage-max二进制文件
如果 diagnose 报告 contacts.status: "not_requested_headless",请在终端中运行 imessage-max --request-contacts-access。通讯录变更后,姓名会在 30 秒内刷新;访问权限一经撤销,姓名即会被移除;无需重启。
“无法读取 iMessage 数据库” / permission_denied
缺少“完全磁盘访问”权限,未获授权的是打开 chat.db 的进程:对于 launchd 服务,该进程是 imessage-max 二进制文件;对于 stdio 客户端,则是启动它的应用。运行 diagnose;database.fix 会列出对应的可执行文件和操作步骤:
- 前往“系统设置”→“隐私与安全性”→“完全磁盘访问”,添加该可执行文件(或启动它的应用)。
- 如果该项目已在列表中,请将其关闭后再打开。绑定到旧代码签名的授权看似存在,实际却无法生效;
make setup-signing会为二进制文件设置稳定身份,使重新构建后仍能保留该身份。 - 授权仅适用于新启动的进程。请重新启动:
launchctl kickstart -k gui/$(id -u)/local.imessage-max或cd swift && make restart。 - 在终端中进行二分排查:
sqlite3 -readonly ~/Library/Messages/chat.db 'pragma quick_check;'。ok表示终端有访问权限,但服务进程没有;unable to open database file表示当前用户缺少授权。
现在,make install 会在结束前运行 make verify-db,通过 HTTP 调用 diagnose,并在 database.accessible 为 false 时失败。更改“完全磁盘访问”权限后,请单独运行:
cd swift && make verify-db
“未找到数据库”错误
~/Library/Messages/chat.db 不存在。请登录 iMessage 并发送或接收一条消息。
图片显示“attachment_offloaded”错误
有些附件存储在 iCloud 中,而不在磁盘上。list_attachments 会提供嵌套的附件摘要,其中每个文件都有 available: true/false 状态。要下载已卸载的附件,请在 Messages.app 中打开对话。
MCP 客户端未加载服务
- 检查配置文件语法是否为有效 JSON
- 确认二进制文件路径正确
- 重新连接或完全重启 MCP 客户端
架构
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MCP Client / │◄───►│ iMessage Max │◄───►│ chat.db │
│ Agent │ │ (Swift MCP) │ │ (SQLite) │
└─────────────────┘ └────────┬────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Contacts.app │
│ (CNContactStore)│
└─────────────────┘
要求
- macOS 15+(Sequoia 或更高版本)
- “完全磁盘访问”权限
- “通讯录”权限(用于解析姓名)
- Messages.app 的自动化权限(仅用于发送)
高级设置
有关 HTTP 模式、本地后台服务设置、开发命令和面向贡献者的工作流详情,请参阅 Swift README。请求正文必须在 30 秒内传输完毕;上传停滞时会返回包含 JSON-RPC 错误正文的 HTTP 408,空闲 60 秒的连接会关闭。另请参阅:
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。