Skip to main content
Glama
0xdeadd
by 0xdeadd

imessage-mcp

A local MCP (Model Context Protocol) server that lets Claude Code read your macOS Messages history directly, so you stop copy-pasting text threads into chat by hand.

It reads ~/Library/Messages/chat.db and your local Contacts database directly with Python's stdlib sqlite3. There are no native dependencies and nothing leaves your Mac: every tool is a local, read-only SQL query plus a small typedstream decoder for the message bodies that Messages stores as binary blobs.

What it gives Claude

  • list_chats(query, limit): recent chats, with names resolved from Contacts.

  • read_thread(chat, since, limit): a thread in order, with sender names, attachment paths, and tapback reactions folded into the message they landed on.

  • search(text, chat, since, limit): full text search over decoded message bodies.

  • whats_new(mark_seen): everything new across every chat since the last call, using a small cursor file at ~/.imessage-mcp/cursor.json.

  • send(chat, text): sends a message through Messages.app. Disabled unless you explicitly turn it on, see "Sending" below.

Related MCP server: iMessage MCP Server

Requirements

  • macOS with Messages.app signed in and syncing.

  • Full Disk Access granted to whatever process runs this server (your terminal, or Claude Code itself, depending on how you launch it). Without it, ~/Library/Messages/chat.db will fail to open even in read-only mode. Grant it under System Settings, Privacy and Security, Full Disk Access.

  • Python 3.12 or newer, managed with uv.

Install

cd /Users/clint/Projects/imessage-mcp
uv sync

Register with Claude Code

claude mcp add --scope user imessage -- uv run --directory /Users/clint/Projects/imessage-mcp python -m imessage_mcp.server

That registers the server once, for every project, over stdio.

Sending is off by default

send(chat, text) only works when the server process has the environment variable IMESSAGE_SEND=1 set. Without it, the tool returns a plain message saying sending is disabled, and does nothing else.

When enabled, sending goes through osascript and Messages.app:

  • a one on one chat sends with send text to buddy handle of (service 1 whose service type is iMessage).

  • a group chat sends with send text to chat id "<guid>".

The first send will prompt macOS for Automation permission for whatever process is driving Messages.app. Treat this as a real send: nothing here double checks with you before the message goes out, so only turn IMESSAGE_SEND on in a session where you are prepared to review the exact text before asking the tool to send it.

Privacy

Everything runs locally. The server opens chat.db and your Contacts database read only (sqlite3 URI mode=ro), decodes text and attachment paths in process, and returns plain text to Claude. Nothing is uploaded anywhere, and no network calls happen anywhere in this codebase.

Tests

uv run pytest

The tests read your live chat.db and Contacts database and skip themselves cleanly if either is unreadable (for example, no Full Disk Access, or run on a machine with no Messages history).

Layout

  • imessage_mcp/typedstream.py: decodes the attributedBody blob that Messages uses instead of plain text for most rows.

  • imessage_mcp/db.py: all the read only SQL against chat.db and Contacts.

  • imessage_mcp/server.py: the FastMCP server and tool definitions.

  • tests/: pytest tests against the live database.

Available Tools

5 tools
list_chatsA

List recent iMessage/SMS chats, optionally filtered by a case insensitive substring match against the chat name, contact names, or chat identifier. Returns one line per chat with ROWID, name, last message time, and message count.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the behavioral disclosure burden. It discloses that the operation is a read-style listing, that matching is case-insensitive, and that output is one line per chat with specific fields (ROWID, name, last message time, message count). It does not mention ordering or pagination, but the core behavior is transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two tightly written sentences. It front-loads the core purpose, then adds filtering behavior and return format without any filler or redundant schema restatement.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has only two optional parameters and an output schema, the description covers the important behavioral choices: listing, optional filtering, case-insensitivity, and returned fields. It is slightly incomplete only in not elaborating on what 'recent' means or how 'limit' affects the result, but these are minor given the schema defaults and output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema itself contains no parameter descriptions (0% coverage), so the description must compensate. It does well for 'query' by explaining case-insensitive substring matching against chat name, contact names, or chat identifier, but it provides no semantics for 'limit' beyond what the parameter name and default already imply.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('List') with a clear resource ('recent iMessage/SMS chats') and details optional filtering by substring against chat name, contact names, or identifier. It also specifies the output shape, making the tool's purpose immediately unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly implies when to use the tool: when you need a recent chat list, optionally narrowed by a text query. It does not explicitly contrast with sibling tools like search or read_thread, but the listing behavior is stated well enough that an agent would rarely confuse it with those tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_threadA

Read messages from one chat, in date order.

chat accepts a chat ROWID, a chat guid/chat_identifier, or a case insensitive substring of a contact/display name. If the name is ambiguous, this returns a list of candidate chats instead of messages. since is an optional "YYYY-MM-DD" or "YYYY-MM-DD HH:MM" local time filter. limit caps how many of the most recent matching messages come back (still returned oldest first).

ParametersJSON Schema
NameRequiredDescriptionDefault
chatYes
limitNo
sinceNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden and does so well: it discloses chat identifier/name/substring forms, ambiguous-name candidate-list behavior, the date-time format for since, and the limit/ordering nuance. It omits edge cases like no-match handling, but still conveys substantial non-obvious behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-structured: purpose first, then each parameter's semantics in turn. Every sentence adds distinct value without repeating schema defaults or titles.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter read-only tool with an output schema available, the description covers the main callability concerns: chat resolution, time filtering, and limits/ordering. Minor gaps such as no-match behavior or the default of since do not prevent correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description fully compensates by explaining exactly what chat accepts, what since means and its accepted formats, and how limit affects result selection and ordering. This is the semantic information an agent needs beyond the raw parameter names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action ('Read messages from one chat') with a clear resource, scope, and ordering guarantee. The one-chat focus clearly separates it from sibling tools like list_chats, search, and send.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: reading a single chat's messages in date order. It doesn't explicitly name alternatives or exclusion conditions, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

sendA

Send a message through Messages.app.

Disabled by default. Set the environment variable IMESSAGE_SEND=1 on this server process to enable it. chat accepts the same matching rules as read_thread. Always show the exact text to the user and get a yes before calling this.

ParametersJSON Schema
NameRequiredDescriptionDefault
chatYes
textYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden. It discloses that sending is disabled by default, requires an environment variable, follows chat matching rules like read_thread, and mandates explicit user confirmation. This gives an agent meaningful safety and prerequisite context beyond the basic action.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and efficient. The core purpose is front-loaded, followed by critical activation and safety instructions. No wasted words or redundant restatement of the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter tool with an output schema, this description covers the essential operational context: activation, chat resolution, and the mandatory consent gate. Nothing critical is missing for an agent to call it safely and correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for both parameters. It adds useful semantics for `chat` by referencing read_thread matching rules, but it does not explicitly define `text` beyond the obvious 'message text' implied by the tool's purpose and the consent warning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Send a message through Messages.app.' This clearly distinguishes sending from the sibling tools (list_chats, read_thread, search, whats_new) without ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit usage conditions: the tool is disabled by default, must be enabled via IMESSAGE_SEND=1, and must only be called after showing the exact text and getting user consent. It does not explicitly contrast with sibling tools, but the purpose is so distinct that exclusion feels implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

whats_newA

Return every message across all chats since the last time this tool advanced its cursor, grouped by chat, oldest first within each chat.

On the very first call (no cursor yet) it returns the last 24 hours. The cursor lives at ~/.imessage-mcp/cursor.json. When mark_seen is true (the default), the cursor advances to the newest message ROWID seen so the next call only returns messages after this one.

ParametersJSON Schema
NameRequiredDescriptionDefault
mark_seenNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so well. It discloses the persistent cursor file location, the default mark_seen side effect that advances the cursor, and the grouping/ordering semantics. This gives an agent a realistic model of stateful behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The main purpose is front-loaded in a single precise sentence, followed by compact cursor mechanics. There is no filler, repetition of schema fields, or unnecessary detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a stateful tool, the description covers the full lifecycle: first call, cursor location, default advancement behavior, grouping, and ordering. Since an output schema exists, omitting return-value details is acceptable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema only provides the parameter name, type, and default; the description explains that mark_seen controls whether the cursor advances and how that affects future calls. The false branch is not explicitly spelled out, but it is easily inferred from the described behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a precise operation: return every message across all chats since the cursor, grouped by chat with oldest first. This clearly distinguishes it from siblings like read_thread (single chat) and search, while the cursor mechanism separates it from list_chats.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context about first-call behavior and cursor advancement, but it never explicitly says when to prefer whats_new over read_thread, search, or list_chats. The polling use case is implied rather than stated with alternatives or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedlist_chats
    • First observedread_thread
    • First observedsearch
    • First observedsend
    • First observedwhats_new

TDQS

A4.4/5.0

Scored across 5 tools

Disambiguation5/5

Each tool targets a distinct action: listing chats, reading a thread, searching messages, incremental polling, and sending. Even though read_thread and search both return messages, their purposes are clearly separated and easy to tell apart.

Naming Consistency4/5

list_chats and read_thread follow a verb_noun pattern, while search and send are bare verbs and whats_new is a phrase. All names use lower_snake_case and are readable, but the naming is not fully uniform.

Tool Count5/5

Five tools is a well-scoped set for an iMessage bridge. It covers the main interactions without unnecessary redundancy or surface-area bloat.

Completeness5/5

The tool set covers the core messaging workflow: enumerate chats, read conversations, search content, poll for new messages, and send replies. There are no obvious dead ends or missing operations for the stated domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables Claude to send and read iMessages on macOS, with smart contact lookup, message history retrieval, and cross-conversation search using natural language commands.
    5
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables Claude to read and search through iMessage, SMS, and RCS conversations, including mixed-protocol group chats with Android users. It decodes binary message data from the macOS Messages database to provide a comprehensive view of message history.
    8
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables fuzzy search and browsing of Apple Messages (iMessage/SMS) with contact resolution, filtering by sender or date, and context display through CLI, MCP, or Claude Code plugin.
    44
    19
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Connects Claude Desktop to iMessage on macOS, enabling reading conversations, searching messages, sending texts, and managing attachments.
    7
    7
    MIT