iMessage MCP
This server lets you read and search a local iMessage archive and send messages to existing conversations on macOS.
List conversations by recent activity, including chat GUID, participant name, unread count, and last-message preview.
Read messages from one conversation, newest first, with pagination; tapbacks and system events are excluded.
Search message text case-insensitively across the entire archive, optionally restricted to one conversation, with a true match total.
List participants in a conversation with their handles and service.
List unread received messages, newest first.
List attachment metadata only: filename, MIME type, size, direction, and date.
Send a message to an existing conversation by chat GUID.
Cannot start new conversations, and sent messages cannot be recalled.
Allows reading and sending iMessages from the local Messages database on macOS.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@iMessage MCP send a text to my wife that I'm on my way"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
iMessage MCP
An MCP server that reads the local iMessage database and sends messages through Messages.app on macOS.
It runs over stdio for local use and over HTTP for remote use, so a phone or tablet can reach the same server that the laptop uses. That is the point of the project: the desktop-only iMessage integrations work well, but the desktop is the wrong place — the messages worth acting on arrive while you are away from it.
Status
Working, and in use as a remote connector.
Reading is done: the tools below are exercised through a real client over both transports, with password-guarded OAuth 2.1 on the HTTP side and a LaunchAgent behind a tunnel. Sending is done as well, restricted to conversations that already exist.
Starting new conversations, attachment contents, and a full-text search index
are deliberately deferred. See docs/scope.md for the design, the measurements
behind it, and the condition that would bring each deferred item back.
Related MCP server: multimodal-imessage-mcp
Tools
Tool | What it does |
| Conversations by recent activity, or by who is in them |
| One conversation, paginated, newest first |
| Case-insensitive across the whole archive, not a window |
| Chat members, resolved names, service |
| Metadata only: filename, MIME type, size, direction |
| What arrived while you were away |
| Existing conversations only, addressed by chat GUID |
Reads are paginated and return both readable text and structured content, with a true total alongside the page — so "3 messages" is never mistaken for the whole answer when 137 matched.
Message text lives in the attributedBody typedstream blob rather than the
text column, which is empty on roughly 99% of messages on a current macOS.
Decoding that blob is the primary path here, not a fallback.
Sending is constrained on purpose
A server that reads a private archive, ingests text from anybody who can message this account, and can send is the whole lethal trifecta in one process. Two rules bound it:
Existing conversations only. There is no way to start a new one, so a hallucinated or mistyped number cannot reach a stranger.
No cross-conversation forwarding. Read tools record which conversation they showed text from;
send_messagerefuses text that reproduces something read from a different one, and names where it came from.confirm_forwardoverrides that, and is documented as the operator's authorization — never something message text can grant.
Every result carrying message text is labeled untrusted, in both the text and
the structured half. The honest gap is paraphrase: a sentence written from
memory carries nothing tying it back to its source, and no textual rule finds
it. docs/scope.md states what each defense catches and what it does not.
Requirements
macOS, with Messages signed in
Python 3.12+ and uv
Full Disk Access for the Python interpreter, to read
~/Library/Messages/chat.db
Contacts needs no second permission: the address book is read as a sqlite file, which Full Disk Access already covers.
Sending needs one more grant — Apple Events control of Messages.app — which macOS prompts for the first time a message is sent. Trigger it deliberately while sitting at the machine rather than letting it ambush a remote client months later.
Running
uv sync
uv run imessage-mcpThat is stdio. For HTTP, set the transport and bind to localhost behind a tunnel or reverse proxy:
IMESSAGE_MCP_TRANSPORT=http \
IMESSAGE_MCP_AUTH=password \
IMESSAGE_MCP_PASSWORD=... \
IMESSAGE_MCP_BASE_URL=https://imessage.example.com \
uv run imessage-mcpAuth applies to the HTTP transport only; stdio takes its security from the fact
that running it means already having a shell on the machine. There is no
version of this server that should be exposed to a network without
IMESSAGE_MCP_AUTH=password — it reads a personal message archive.
Every setting is documented in .env.example: TRANSPORT, HOST, PORT,
STATELESS, AUTH, PASSWORD, BASE_URL, STATE_DIR, DB_PATH, all under
the IMESSAGE_MCP_ prefix.
GET /health is unauthenticated by design so an uptime monitor can poll it. It
reports the resolved interpreter path — a Python patch upgrade silently moves
the binary and voids the Full Disk Access grant, which is the documented way
this service dies — along with the newest message in the database, whether
Messages is running, and the outcome of the last send. It returns 503, with
the problems named in status, when the database is unreachable, Messages is
not running, the last send failed, or the interpreter has moved.
Deployment
docs/deployment-macos.md covers running it as a LaunchAgent: the plist, the
privacy prompt that hangs the service if the grant is missing, why it must not
be a LaunchDaemon, monitoring, and pushing an update.
scripts/self-update.sh supports that.
Development
uv sync --extra test
uv run pytestThe test suite is offline and runs against a synthetic database built from Apple's schema, including synthesized typedstream blobs, so the real decode path is exercised without committing anybody's messages. It never opens the real database, so it works on a machine that has never sent an iMessage.
This repository is public and hosts a server for a personal archive, so nothing
identifying goes in it — no hostname, no real phone number, no chat GUID.
scripts/scan-secrets.sh checks tracked files for the usual shapes, and CI runs it
alongside the tests. CLAUDE.md has the placeholder conventions.
License
MIT
Available Tools
7 toolsget_attachmentsA
List attachment metadata: name, type, size, direction and date.
The files themselves are not read, so this says what was sent, not what is in it.
Inputs: limit, offset, chat_guid.
get_messagesA
Read messages from one conversation, newest first.
Tapbacks and system events such as group renames are excluded: they are stored as messages but are not things anybody said.
Inputs: chat_guid (required), limit, offset.
get_participantsB
List who is in a conversation, with their handles and service.
Inputs: chat_guid (required).
get_unreadA
List received messages that have not been read yet, newest first.
Inputs: limit.
list_chatsA
List conversations, most recently active first.
Each entry carries the chat_guid needed by the other tools, the other participant's name where it is known, how many unread messages it holds, and a preview of the last message.
Inputs: limit, offset.
search_messagesA
Search message text across conversations, case-insensitively.
The entire history is searched, not a recent window, so a total of 0 means the text is genuinely not there. The total is a true count of matches; limit bounds only how many are returned.
Inputs: query (required), limit, offset, chat_guid.
send_messageA
Send a message to an existing conversation.
Only conversations that already exist can be addressed, by the chat_guid from list_chats. There is no way to start a new conversation, so this cannot reach somebody who has not been talked to before.
A sent message cannot be recalled.
Inputs: text (required), chat_guid (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 7 tools
Each tool targets a distinct aspect of iMessage: listing chats, reading messages, searching, participants, unread, attachments, and sending. There is no overlap in purpose, and the descriptions clarify boundaries (e.g., get_messages excludes tapbacks, get_attachments only lists metadata).
All tool names follow a consistent verb_noun pattern: list_chats, get_messages, search_messages, get_participants, get_unread, get_attachments, send_message. The verbs are uniform (list/get/search/send) and nouns are clear, making the set predictable.
Seven tools is well-scoped for an iMessage server: it covers the core read and send operations without redundancy. Each tool earns its place, and the count is within the ideal 3-15 range.
The surface covers the main iMessage workflows: listing chats, reading/searching messages, checking unread, viewing participants and attachments, and sending. The only notable gap is the inability to start a new conversation, which is explicitly documented and may be a platform limitation, but it is a real dead end for reaching new contacts.
Related MCP Connectors
MCP connector for iMessage & Contacts via a local Mac agent + Vercel relay
Send and read iMessages from your own Mac and Apple ID — drafts, history and contacts.
Send and receive iMessage, SMS, RCS, and WhatsApp, and manage contacts, chats, and numbers.
Explore your Messages SQLite database to browse tables and inspect schemas with ease. Run flexible…
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables reading, searching, and sending iMessages directly from MCP-compatible clients by accessing the local macOS iMessage database, supporting conversations, attachments, and both individual and group chats.674 npm10MIT
- AlicenseBqualityCmaintenanceEnables reading, searching, sending iMessages, viewing image attachments, and managing conversations, with full support for modern macOS attributedBody parsing.142MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for reading and sending iMessages on macOS. Exposes iMessage history and send capabilities through tools like list_conversations and send_imessage.11 npmMIT
- AlicenseNot gradedqualityAmaintenanceRead, search, and send iMessages locally from your terminal or through MCP clients like Claude, Cursor, and VS Code.MIT