Skip to main content
Glama

imessage-mcp

A local MCP server that exposes your Mac's iMessage data to Claude Desktop / Claude Code. Two surfaces:

  1. SEND via AppleScript → Messages.app

  2. READ via direct, read-only SQLite access to ~/Library/Messages/chat.db

Everything is local. No API keys, no network calls.

Install

# 1. Clone / copy into ~/mcp-servers/imessage-mcp
cd ~/mcp-servers/imessage-mcp

# 2. Create a Python 3.11+ venv and install deps
python3.12 -m venv .venv
.venv/bin/pip install -e .

Permissions (required)

Full Disk Access — so we can read chat.db

System Settings → Privacy & Security → Full Disk Access → toggle ON for:

  • your terminal app (e.g. Terminal, iTerm2, Ghostty), AND

  • Claude.app (if using Claude Desktop)

Automation — so we can control Messages.app

System Settings → Privacy & Security → Automation → expand your terminal / Claude.app and toggle Messages to ON.

Messages.app must be running and signed into iMessage.

If a permission step is missing, the server errors with the exact settings path to open.

Claude Desktop config

Merge into ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "imessage": {
      "command": "/Users/YOUR_USERNAME/mcp-servers/imessage-mcp/.venv/bin/python",
      "args": ["-m", "imessage_mcp.server"]
    }
  }
}

(The absolute path to the venv's python is the safest — it avoids PATH ambiguity. Replace YOUR_USERNAME.)

Tools

Tool

Purpose

send_imessage(recipient, body, service?)

Send via Messages.app. recipient is a phone, Apple ID email, or existing buddy name.

list_recent_chats(limit=20)

Newest-first chats with last-message preview and unread count.

get_chat_messages(chat_id?, handle?, limit=50, since?)

Messages for a chat; provide chat_id or handle.

search_imessages(query, since?, until?, from_contact?, limit=25)

Case-insensitive LIKE across message bodies.

get_my_info()

Self-handles + DB metadata.

Dates are ISO8601 in and out. Internally, Apple stores message.date as nanoseconds since 2001-01-01 UTC; the server converts both ways.

Safety invariants

  • chat.db is opened with sqlite3.connect("file:...chat.db?mode=ro", uri=True). Any write attempt raises sqlite3.OperationalError: attempt to write a readonly database.

  • send_imessage passes recipient / body / service as separate osascript argv entries — no shell interpolation, no injection.

  • Attachments return metadata only (filename, mime_type, total_bytes). Blobs are never read.

Limitations

  • Scheduled / delayed sends are not supported.

  • Rich / reply-threaded messages may have their text stored in attributedBody (NSKeyedArchive). We best-effort extract the embedded NSString; messages with more exotic payloads (images, taps, Apple Pay) will show empty body but correct metadata.

  • Delivery confirmation: send_imessage reports success from osascript's exit code. To verify the message actually went through, call search_imessages or get_chat_messages a few seconds later.

  • This is macOS-only and will not work on sandboxed App Store apps.

Local development

.venv/bin/pytest -q

Latest Blog Posts

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/camfortin/imessage-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server