A native Swift server that hooks into macOS Messages and Contacts databases to give Claude read and send access to your iMessage history. Instead of raw SQL queries, you get 11 intent-aligned tools like find_chat, search, and get_messages with automatic contact resolution and session grouping. The attachment handling is smart: images come back as vision, thumb, or full variants to control token cost, and you can see what's local versus offloaded to iCloud before fetching. Useful when you need Claude to search conversations, pull context around specific messages, or send replies to exact threads after confirming recipients. Requires Full Disk Access for chat.db and Contacts permission for name resolution.
A high-performance MCP (Model Context Protocol) server for iMessage that lets AI agents read, search, and send your messages with proper contact resolution.
Built in Swift for native macOS integration - single binary, no runtime dependencies.
The project now ships a single Swift implementation:
The old Python package has been retired and removed from the repository.
Everything current lives under swift/.
Most iMessage tools expose raw database structures, requiring 3-5 tool calls per user intent. This MCP provides intent-aligned tools:
"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")
The tools work best when an agent uses them as short workflows instead of isolated one-off calls.
Agents should treat chat_id values like chat123 as internal handles for tool calls and exact sends. When explaining results to a person, use the returned chat name, group name, or participant-derived label instead of saying "Chat 123."
find_chat(participants=["Contact A"])
get_chat_details(chat_id="chat123")
get_messages(chat_id="chat123", since="yesterday", limit=50)
Use this when the person matters more than the exact thread id.
search(query="launch timeline", limit=10)
get_context(message_id="msg_456", before=5, after=10)
Use this when you know the topic but not where it was discussed.
get_unread()
get_active_conversations(hours=24, min_exchanges=2)
Use this to surface unread threads and active conversations after a broad chat-list sweep.
list_attachments(chat_id="chat123", type="image", since="30d")
get_attachment(attachment_id="att123", variant="vision")
Use list_attachments to discover the message where files were shared first. It still returns exact attachment ids and local-availability state before you fetch a file.
find_chat(participants=["Contact A", "Contact B"])
send(chat_id="chat456", text="Please use the latest draft")
For sensitive sends, prefer resolving the exact chat first and then using chat_id so the message lands in the intended thread.
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
For local development, advanced setup, and the signed install workflow, see:
iMessage Max ships icons for the main MCP protocol surface and the client packaging surfaces that use their own metadata:
2025-11-25 initialize responses include PNG serverInfo.icons..codex-plugin/plugin.json and uses
assets/codex/icon.png plus assets/codex/logo.png.mcpb/manifest.json and uses PNG
assets under mcpb/assets/.The committed PNG source set is under assets/icons/ at 16x16, 32x32,
64x64, 128x128, 256x256, and 512x512.
Required to read ~/Library/Messages/chat.db:
For Homebrew installs: The binary is at /opt/homebrew/Cellar/imessage-max/VERSION/bin/imessage-max (not the symlink at /opt/homebrew/bin/). Find it with:
# Open the folder containing the actual binary
open $(dirname $(readlink -f $(which imessage-max)))
For source builds: Add .build/release/imessage-max from your clone directory.
Tip: In the file picker, press ⌘+Shift+G and paste the path to navigate directly.
Required for resolving phone numbers to names. The app will request access on first run, or add manually:
System Settings → Privacy & Security → Contacts → add imessage-max
Add imessage-max to your MCP client's server configuration.
Many MCP clients use a JSON structure like this:
For Homebrew:
{
"mcpServers": {
"imessage": {
"command": "/opt/homebrew/Cellar/imessage-max/VERSION/bin/imessage-max"
}
}
}
For source builds:
{
"mcpServers": {
"imessage": {
"command": "/path/to/imessage-max/swift/.build/release/imessage-max"
}
}
}
If your client uses a different config format, point it at the same binary path.
After saving the config, reconnect or restart your MCP client. The server should appear in the available tools, and you can verify the connection with diagnose.
Find chats by participants, name, or recent content.
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
Inspect a known thread without opening the full conversation.
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
Retrieve messages with flexible filtering. Returns metadata for media.
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
Retrieve image content by attachment ID with resolution variants.
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
| Variant | Resolution | Use Case | Token Cost |
|---|---|---|---|
vision (default) | 1568px | AI analysis, OCR | ~1,600 tokens |
thumb | 400px | Quick preview | ~200 tokens |
full | Original | Maximum detail | Varies |
Browse recent chats with previews.
list_chats(limit=20) # Recent chats
list_chats(is_group=True) # Only group chats
list_chats(since="7d") # Active in last week
Full-text search across messages.
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
Get messages surrounding a specific message.
get_context(message_id="msg_123", before=5, after=10)
Find chats with recent back-and-forth activity.
get_active_conversations(hours=24)
get_active_conversations(is_group=True, min_exchanges=3)
Browse shared items grouped by message. Each row includes exact attachment ids for follow-up fetches.
list_attachments(type="image", since="7d")
list_attachments(chat_id="chat123", type="any")
Get unread threads or unread messages. Default is summary by chat.
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
Send a message or file attachment (requires Automation permission for 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")
Rules:
to or chat_idtext or file_pathsFor a lightweight pre-release routine, use:
Additional send note:
reply_to is currently unsupportedstatus: "ambiguous". The confirm parameter is deprecated and ignored (kept only for compatibility). Authorization happens in the user's conversation with the agent and in the client's tool-approval UI, not server-side.Send result semantics (text sends are verified post-send against chat.db):
status: "confirmed" means the message row was found in chat.db with no error; verified_message_guid is the evidencestatus: "uncertain" means transport accepted the send but the row was not found within the polling window; follow up with get_messagesstatus: "mismatch" means the message landed in a different chat than intended; do not treat as successstatus: "sent" means verification was unavailable (DB unreadable); transport accepted onlystatus: "pending_confirmation" means Messages accepted an attachment send, but the file transfer was not confirmed as finished within the polling windowstatus: "failed" means the send failedstatus: "ambiguous" means the target could not be resolved safelyNotes:
pending_confirmation is a normal non-fatal attachment state, not the same as a hard failurechat_idstructuredContent as well as legacy text content for older clientsExamples:
{"status":"confirmed","verified_message_guid":"...",...} means delivery was verified in chat.db{"status":"pending_confirmation","success":false,...} means Messages accepted the attachment, but the MCP could not yet confirm final completionTroubleshoot configuration and permission issues.
diagnose() # Returns: database status, contacts count, permissions, capabilities
Run diagnose to check status. If contacts_authorized is false:
imessage-max binary to System Settings → Privacy & Security → ContactsAdd the imessage-max binary to System Settings → Privacy & Security → Full Disk Access
Some attachments are stored in iCloud, not on disk. list_attachments includes nested attachment summaries with available: true/false for each file. To download offloaded attachments, open the conversation in Messages.app.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MCP Client / │◄───►│ iMessage Max │◄───►│ chat.db │
│ Agent │ │ (Swift MCP) │ │ (SQLite) │
└─────────────────┘ └────────┬────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Contacts.app │
│ (CNContactStore)│
└─────────────────┘
For HTTP mode, local background service setup, development commands, and contributor-focused workflow details, see:
MIT
com.mcparmory/google-search
io.github.pipeworx-io/brave-search
marcopesani/mcp-server-serper
brave/brave-search-mcp-server
com.mcparmory/google-search-console
acamolese/google-search-console-mcp