mcpField
I
imessage-max

imessage-max

本地服务
github.com/cyberpapiii通信协作62 周前更新

关于 imessage-max

iMessage Max 是用 Swift 编写的 macOS iMessage MCP 服务,可读取、搜索和发送对话。其工具围绕用户意图设计,让 Agent 能处理聊天和附件,而非直接操作原始数据库表。

主要功能

  1. 01按联系人、名称或内容查找聊天
  2. 02读取并筛选消息
  3. 03搜索消息并获取上下文
  4. 04通过 Contacts 将电话号码解析为姓名
  5. 05浏览和获取图像附件
  6. 06向选定聊天发送消息

适用场景

  1. 01查找并查看与联系人的对话
  2. 02搜索主题并检查相关上下文
  3. 03检查未读及近期活跃对话
  4. 04查找并获取共享图像

MCP 相关

通过 stdio 和 HTTP 将 iMessage 操作作为 MCP 工具提供,并支持新旧协议协商。仅实现工具,不提供提示词或资源。

配置

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

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

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

安装包
pypiimessage-max0.4.4

工具

还没有获取到工具列表

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

详细介绍

iMessage Max

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-25initialize + 会话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 初始化响应包含 PNG serverInfo.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 所必需:

  1. 打开“系统设置” →“隐私与安全性” →“完全磁盘访问权限”
  2. 点击 + 添加二进制文件

对于 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_rowidintegeromitted排他的 ROWID 游标。省略或传入 -1 可仅获取当前游标。
chat_idstringomitted限定为一个聊天(chat123 或 123)
limitinteger100要返回的最大消息数(1–500)
include_filteredbooleanfalse包含垃圾信息/未知发件人的聊天
include_reactionsbooleantrue为返回的消息附加表情回应字符串

响应示例:

{
  "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(默认)1568pxAI 分析、OCR~1,600 tokens
thumb400px快速预览~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。

发布检查

发布前,请完成以下检查:

发送补充说明:

  • 目标明确无误时,消息会立即发送;没有确认关卡。目标不明确时会拒绝发送,并返回 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 状态。

statusdispositionretry_safe
confirmed、uncertain、mismatch、sentcompletedfalse
failed_deliverycompletedtrue
pending_confirmationmay_have_completedfalse
failed(传输)取自 send仅当为 not_started 时是 true
failed(验证 / 解析)not_startedtrue
partial_failure取自失败载荷的 dispositionfalse
ambiguousnot_startedtrue
{"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 会列出对应的可执行文件和操作步骤:

  1. 前往“系统设置”→“隐私与安全性”→“完全磁盘访问”,添加该可执行文件(或启动它的应用)。
  2. 如果该项目已在列表中,请将其关闭后再打开。绑定到旧代码签名的授权看似存在,实际却无法生效;make setup-signing 会为二进制文件设置稳定身份,使重新构建后仍能保留该身份。
  3. 授权仅适用于新启动的进程。请重新启动:launchctl kickstart -k gui/$(id -u)/local.imessage-max 或 cd swift && make restart。
  4. 在终端中进行二分排查: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 客户端未加载服务
  1. 检查配置文件语法是否为有效 JSON
  2. 确认二进制文件路径正确
  3. 重新连接或完全重启 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

评论

支持 Markdown

第一次接触 MCP?

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

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