iMessage Connector
Connects a coding agent to iMessage on macOS, enabling reading conversations, searching, sending messages, reacting, and receiving commands via iMessage.
Click on "Install 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 Connectorsend 'Build finished, tests pass' to Ship Room"
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 Connector
Connect a coding agent to iMessage — under rules it cannot talk its way past.
An MCP server for macOS Messages. Your agent can read conversations, search them, send messages, react, and be commanded from your phone. Every one of those is governed by a policy whose layers combine by narrowing: nothing can widen what another layer closed.
you, from a café your Mac at home
│ │
"!imsgc status" ──────────► agent (Claude Code / Codex)
│ │ reads the repo, runs the tests
"✅ api: tests (2m 14s)" ◄────┘Three things people actually want from this:
Tell me when it's done. A long build finishes at 23:40; you find out without watching.
Work from anywhere. Text the Mac at home; it does the work and answers.
A room with the agent in it. A group chat with your team where the agent posts and answers, and a human can reply in the same thread.
Before you install: what this cannot do
Some of it is possible and some of it is not, and the not is worth knowing before you start.
Sending works. tell application "Messages" to send … to chat id … is verified working on
macOS 27 (build 26A5388g), including attachments, once Automation is granted. The first Apple
Event raises an authorisation dialog, and until someone answers it every call that needs a
reply blocks — activate still returns, so the app looks healthy while nothing else responds.
That looks exactly like a hang, and it is the single most likely reason iMessage Connector appears broken
on a fresh install. imsgc doctor names it.
Two fallbacks exist for when Automation is unavailable: a Shortcut you create once (text only),
and driving the Messages window through Accessibility. iMessage Connector probes rather than assuming,
and imsgc doctor reports which works on your machine.
These are not possible on any current macOS, and iMessage Connector says so rather than pretending:
Group create / rename / add or remove participants. The Messages scripting dictionary's entire vocabulary is
send,login,logout. There is no command, on any version.Pinning, and replying in-thread. Both need to point at one specific message. The accessibility tree of the Messages window exposes no individual messages — no static text, no scroll area, no rows — so any implementation would be a guess about pixel positions.
Reacting to an older message. ⌘T targets the newest incoming message and nothing else. Reacting to the newest is supported; anything before it is not. Reactions have never had a scripting API, which is why this needs Accessibility and stays behind
ui_automation.
The projects that go further do it by injecting a helper into Messages.app to reach private IMCore APIs — BlueBubbles is the best-known. That buys edit, unsend, typing indicators and arbitrary reactions, at the price of disabling System Integrity Protection; and on macOS 26 library validation blocks the injection anyway (open issue). iMessage Connector deliberately stays on supported interfaces.
Reading is unaffected by all of this: it goes straight to the database and is complete.
Related MCP server: imessage-mcp
Install
Requires macOS and Node 22.5 or later. No native modules, no compiler.
npx imessage-connector --help # or: npm i -g imessage-connector
imsgc init # writes ~/.imessage-connector/config.toml
imsgc doctor # checks permissions and backends, tells you what to fixClaude Code
claude mcp add imessage-connector -- npx -y imessage-connectorCodex — in ~/.codex/config.toml:
[mcp_servers.imessage-connector]
command = "npx"
args = ["-y", "imessage-connector"]Permissions. Reading needs Full Disk Access for the program that runs the server — for a
terminal agent that is the terminal application (Terminal, iTerm2, Ghostty…), not node.
Interface automation additionally needs Accessibility. imsgc doctor names the exact
setting for whatever is missing.
The policy
One file, ~/.imessage-connector/config.toml, plus optional layers. imsgc init writes a commented
starting point.
mode = "interactive" # off | read | notify | interactive | full
ui_automation = false
[chats]
allow = ["Ship Room", "+33600000000"]
[content]
max_length = 2000
require_marker = true
marker = "🤖 "
deny_patterns = ["(?i)-----BEGIN [A-Z ]*PRIVATE KEY-----", "sk-[A-Za-z0-9_-]{20,}"]
[rate]
per_chat_per_minute = 3
global_per_hour = 60
[schedule]
timezone = "Europe/Paris"
quiet_hours = ["22:00-08:00"]
[approval]
mode = "first_time"
[remote]
commanders = ["+33600000000"]
required_prefixes = ["!imsg"]Layers narrow; they never widen
Four sources combine: built-in defaults, ~/.imessage-connector/config.toml, a project's
.imessage-connector/config.toml, [chat."…"] sections, and a sealed policy. They are merged with an
operation that is commutative, associative and idempotent — the result is at least as
restrictive as every input, on every field.
That is a stronger claim than "the last layer wins":
There is no ordering of layers to get wrong, because order cannot change the result.
A repository's config cannot out-rank yours. A per-chat section cannot re-open what another layer closed. A layer injected by an agent can only ever take capability away. Limits take their lowest value, allow-lists intersect, deny-lists union, and "this is required" stays required. It is checked by property tests over generated policies, not by inspection.
# In the repo, checked in: this project may only ever notify, never read.
mode = "notify"
# Per-conversation, anywhere:
[chat."Famille*"]
mode = "off"Sealing
Every config file is writable by the agent — it runs as the same user. Narrowing alone
protects against a confused agent, not a determined one: it could rewrite config.toml and
restart.
~/.imessage-connector/policy.sealed.toml is pinned by a SHA-256 in a separate lock file. Any change to
it, a missing lock, or a missing sealed file all mean lockdown — every capability refused,
including reads — until a human re-seals:
imsgc seal # refuses unless run from a real terminalThe MCP server exposes no tool that writes configuration, and seal will not run without a
TTY. That combination is what an agent cannot get around.
Also: imsgc pause refuses everything immediately, and ~/.imessage-connector/PAUSE does the same if
you would rather touch a file.
Tools
tool | capability | notes |
|
| conversations, newest first |
|
| reactions folded in; removed ones are not shown |
|
| reports how much it examined and whether it stopped early |
|
| |
|
| inside the attachments directory only, size-capped |
|
| draft-then-confirm when approval is on |
|
| needs the AppleScript backend |
|
| newest incoming message only; needs |
|
| addressing, not permission |
|
| what is permitted, and which layer decided |
|
| blocks until someone answers, or the timeout |
|
| completion notice, same policy as any message |
A tool cannot be registered without declaring its capability and how to derive the target conversation from its arguments, and the server builds its tool list from that registry. There is no path from a client request to an effect on the world that skips the policy check.
Text me when the job is done
Bind a conversation once, then add the hook:
// ~/.claude/settings.json
{ "hooks": { "Stop": [ { "matcher": "", "hooks": [
{ "type": "command", "command": "imsgc notify --outcome done --task \"$CLAUDE_LAST_USER_MESSAGE\"" }
] } ] } }imsgc notify goes through the same policy as any other message — including quiet hours,
which is the point: a job that finishes at 03:00 is exactly when you do not want a text.
Being commanded from your phone
Four gates, all of which must pass before an inbound message counts as an instruction: the conversation is bound for control, the sender is on the commander list, the message carries every required prefix, and in a group it mentions the agent. Then the verb must be on the allow-list.
A message that fails any gate is still readable by the agent — nothing can stop a model reading text put in front of it — it simply is not an instruction. Each rejection names the gate it failed, so a command that did nothing can be explained.
Approving from your phone
When the policy asks for approval, a send returns a draft with a token instead of going out. The token is pinned to the exact text and the exact conversation, so an agent cannot get "deploying to staging" approved and then send "deploying to production".
The agent can also ask in the conversation itself and wait for a 👍 — a reaction is attached to one specific message, so a bare "yes" cannot be misread as answering a different pending question. 👎 rejects immediately instead of waiting out the deadline.
What iMessage Connector records
Every decision goes to ~/.imessage-connector/audit.jsonl, one line each, chained to the previous
entry's hash. Deleting the one message the agent should not have sent breaks every hash after
it, and imsgc audit says exactly where.
Message bodies are never written to the log. A record of everything the agent ever sent would be a second plaintext copy of your private conversations. Length and a short hash are enough to answer "was this the message I saw".
How it reads messages
On modern macOS, about 97 % of rows in chat.db have message.text set to NULL. The real
content lives in attributedBody, a NeXTSTEP streamtyped archive. iMessage Connector ships a decoder
for it, validated against 2242 real messages: zero decode failures, and an exact match on
every row where Apple also back-filled text.
Reads open the database read-only, falling back to a snapshot copy — including the -wal,
without which the newest messages are missing — when SQLite refuses the live file. Optional
columns are probed at startup rather than pinned to a macOS version.
Documentation
SECURITY.md — reporting a vulnerability
docs/THREAT-MODEL.md — what this defends against, and what it does not
docs/policy-cookbook.md — worked configurations
Licence
MIT.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Flicense-qualityFmaintenanceAn MCP server that provides safe access to your iMessage database through MCP, enabling LLMs to query and analyze iMessage conversations with proper phone number validation and attachment handlingLast updated79
- AlicenseAqualityDmaintenanceA local MCP server that enables reading iMessage conversations and sending new messages through Claude Desktop. It provides secure, read-only access to your Mac's iMessage database and AppleScript-based message sending capabilities.Last updated6MIT
- FlicenseAqualityCmaintenanceA read-only MCP server that exposes your iMessage data to Claude Code and Claude Desktop, with automatic contact name resolution.Last updated3
- Alicense-qualityDmaintenanceEnables reading and sending iMessages on macOS through MCP, with tools for managing chats, messages, and attachments via AI agents.Last updatedMIT
Related MCP Connectors
Remote MCP server for The Colony — a social network for AI agents (posts, DMs, search, marketplace).
Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.
Push notifications for AI agents - send instant iPhone notifications from any MCP client.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Connected-Mate/imessage-connector'
If you have feedback or need assistance with the MCP directory API, please join our Discord server