Skip to main content
Glama
falconbradley

Apple Messages MCP

Apple Messages MCP

Читайте и ищите свои переписки iMessage, SMS и RCS из Claude на macOS.

Дополнение к claude-connector-apple-mail и claude-connector-apple-reminders.

Статус: чтение и поиск работают надёжно. Отправка работает, но не проверена на реальной отправке — вызов скрипта реализован, его синтаксис проверен, но Apple уже ломала send раньше, так что первую реальную отправку считайте тестом. См. Отправка сообщений.

Инструменты

Инструмент

Описание

get_stats

Итоги, количество непрочитанных, разбивка по службам (iMessage/SMS/RCS), диапазон дат

list_chats

Переписки, сначала самые недавние, с участниками и превью

get_chat_messages

Сообщения в одной переписке, сначала старые, с постраничной разбивкой

search_messages

Поиск подстроки по всей истории, с фильтром по переписке, отправителю и диапазону дат

get_message

Одно сообщение полностью, с вложениями и временными метками доставки

get_attachment

Вложение в байтах, в кодировке base64

refresh_search_index

Прогрев или пересоздание локального поискового индекса

compose_message

Открыть Messages с предзаполненным текстом — вы нажимаете «Отправить»

send_message

Отправить в существующую переписку; доставляется немедленно

Related MCP server: jons-mcp-imessage

Требования

  • macOS 13 Ventura или новее. RCS требует macOS 26 или новее.

  • Полный доступ к диску для приложения Claude — требуется для чтения.

  • Разрешение автоматизации для Messages — требуется для отправки и для имён контактов. macOS запрашивает его автоматически.

Предоставление полного доступа к диску

  1. Системные настройки → Конфиденциальность и безопасность → Полный доступ к диску

  2. Включите Claude (добавьте /Applications/Claude.app через +, если его нет в списке)

  3. Завершите работу Claude и откройте его снова. macOS кэширует это разрешение при запуске процесса, поэтому перезапуск обязателен — без него расширение будет продолжать давать сбои.

Почему здесь нужен полный доступ к диску, а для Apple Mail — нет

Расширение Apple Mail общается с Mail.app полностью через скрипты, поэтому ему не нужны особые разрешения. Messages так работать не может.

Словарь AppleScript для Messages предоставляет ровно четыре класса — account, chat, participant, file transfer — и никакого класса сообщений. Проверено на macOS 26.5.2:

$ osascript -e 'tell application "Messages" to get every text message of first chat'
syntax error: Expected "from", etc. but found identifier. (-2741)

Переписки и участники перечисляются нормально; тексты сообщений просто не доступны. Поэтому единственный путь чтения — SQLite через ~/Library/Messages/chat.db, который защищён TCC. В отличие от автоматизации, полный доступ к диску нельзя запросить программно — пользователь должен предоставить его вручную.

Поэтому расширение использует оба разрешения для разных задач:

Задача

Механизм

Разрешение

Сообщения, переписки, поиск, вложения

SQLite на chat.db

Полный доступ к диску

Имена контактов для «сырых» идентификаторов

Скрипты Messages

Автоматизация

Отправка

Скрипты Messages (send)

Автоматизация

Окно создания, предзаполнение

Схема URL imessage: / sms:

нет

Имена контактов берутся из класса participant в Messages (свойство full name), который читает карточку контакта пользователя. Это обходит отдельно защищённую базу AddressBook — если автоматизация запрещена, идентификаторы просто отображаются как «сырые» номера.

Заметки по реализации

attributedBody. Начиная с Ventura, message.text часто равен NULL, а текст сообщения хранится в message.attributedBody в формате Apple typedstream — это устаревший формат NSArchiver, который plistlib не умеет читать. typedstream.py декодирует его на чистом Python, так что пакету не нужна зависимость PyObjC. Он опирается на имя класса NSString/NSMutableString и читает полезную нагрузку UTF-8 с префиксом длины после маркера типа +. Декодирование полное: не поддающееся декодированию тело даёт None, а не приводит к сбою запроса.

Временные метки. message.date — это эпоха Apple (2001-01-01), в секундах до macOS 13 и в наносекундах начиная с неё. Оба варианта распознаются и обрабатываются.

Поиск. В chat.db нет текстового индекса, и большинство текстов живут только в attributedBody, где SQL их не видит. Такое сочетание сложнее, чем кажется.

Первая реализация расширяла свой предикат до m.text LIKE ? OR m.attributedBody IS NOT NULL и повторно фильтровала декодированный текст в Python. Поскольку второе условие истинно почти для каждой современной строки, LIMIT запроса усекал сканирование до нескольких сотен самых новых сообщений до того, как фильтр Python вообще запускался — поэтому любое более старое совпадение молча исчезало. Поиск реального сообщения возвращал ноль результатов, а не был медленным. На истории объёмом 916 МБ это означало, что поиск фактически покрывал только последние несколько дней.

Исправление — декодировать один раз, а не при каждом запросе. index.py зеркалирует декодированные тексты, приведённые к нижнему регистру, в ~/Library/Caches/apple-messages-mcp/search-index.db, к которому затем подключается поиск — так что совпадение, фильтры, сортировка и LIMIT применяются ко всей истории в SQL. Зеркало:

  • Инкрементальное. Новые сообщения находятся по водяному знаку message.ROWID. Правки и отмены отправки повторно используют существующий ROWID, поэтому каждое обновление также просматривает последние 2000 строк — но только те, у которых date_edited установлен или оба столбца тела теперь NULL, поскольку повторное декодирование 2000 блоков при каждом поиске — это реальная работа, которая почти всегда ничего не находит. Правка, которую Messages каким-то образом не пометил, или правка старше этого окна, требует refresh_search_index(rebuild=True). Улучшение декодера attributedBody также оправдывает пересоздание; увеличение SCHEMA_VERSION принудительно его выполняет.

  • Приведено к нижнему регистру, и только это. Отображаемый текст по-прежнему берётся из chat.db, так что зеркало — чисто оракул для сопоставления. Хранение str.casefold() уменьшает его размер вдвое и делает сопоставление без учёта регистра корректным для не-ASCII — SQLite LIKE сворачивает регистр только для ASCII.

  • Одноразовое. Оно живёт в ~/Library/Caches и пересоздаётся при удалении. Ничто здесь не пишет в chat.db.

Не FTS5, несмотря на более ранний план: FTS5 сопоставляет целые токены, поэтому MATCH 'dentist' никогда не найдёт «mydentist», что уже, чем семантика подстроки, которую документирует search_messages. Сканирование подстрок по компактному тексту в нижнем регистре уже быстрое, так что FTS5 удвоил бы индекс ради семантики, которую мы не можем использовать. Добавить его позже — изолированное изменение, если какой-то запрос вдруг станет тормозить.

Только чтение и без блокировок. Соединения открываются с mode=ro, и ни один оператор не изменяет базу данных. Если SQLite не может открыть живой WAL в режиме только для чтения, он переключается на частную копию-снимок, так что работающий Messages.app никогда не нарушается.

Tapbacks, правки, ответы. Реакции декодируются из associated_message_type (2000–2007, а диапазон 3000 — их удаления), ответы в ветках — из thread_originator_guid, а правки — из date_edited.

Отправка сообщений

В Messages нет объекта черновика, поэтому нет точного аналога подхода Mail-расширения «сначала черновик». Поэтому путь записи реализован на двух уровнях, и они намеренно не эквивалентны.

compose_message — безопасный вариант по умолчанию. Открывает Messages с получателем и текстом, предзаполненными через схему URL imessage: / sms:, и останавливается. Человек читает и нажимает «Отправить», так что ничего не покидает машину по указанию Claude. Это также единственный способ начать новую переписку. Не требует никаких разрешений.

send_message — доставляет немедленно. Использует send из интерфейса скриптов и не может быть отменено. Он принимает chat_id, а не номер телефона, что не ограничение, а суть: словарь принимает либо participant, либо chat, и адресация существующей переписки по GUID позволяет Messages выбирать транспорт (iMessage / SMS / RCS) вместо того, чтобы вызывающий угадывал и молча отправлял SMS тому, кто на iMessage. Также требуется confirm=True — чисто как защита от случайного срабатывания.

Что проверено, а что нет

Подтверждено на macOS 26.5.2 — словарь предоставляет

send : direct-parameter (file | text), to: (participant | chat)

перечисление service type — это SMS, iMessage, RCS, у chat есть свойство GUID id для адресации, и сгенерированный AppleScript компилируется.

Не подтверждено: что реальная отправка действительно доставляет. Apple уже ломала AppleScript send раньше, и его наличие в словаре никогда не было доказательством работоспособности. Ничто в тестовом наборе не доставляет сообщение, так что первая реальная отправка — это эксперимент. Если она не сработает, shortcuts run с действием «Отправить сообщение» — следующий вариант, который стоит попробовать.

Текст сообщения передаётся в AppleScript как аргумент osascript (on run argv), а не вставляется в исходный код скрипта, поэтому тело, содержащее двойную кавычку, инертно, а не вызывает синтаксическую ошибку или инъекцию.

Отправка вложений не подключена, хотя прямой параметр file означает, что она в пределах досягаемости.

Разработка

python3 tests/test_db.py       # SQL, decoder, and search-index tests
python3 tests/test_send.py     # compose URLs, send guards, argv safety
python3 tools/probe_schema.py  # verify the real chat.db (needs Full Disk Access)
./build.sh                     # test, validate manifest, pack the .mcpb

tests/test_db.py создаёт одноразовые базы данных с реальной схемой, поэтому SQL можно проверять без полного доступа к диску или реальной истории сообщений. Один из тестов прячет совпадение под 3000 более новых сообщений — это регрессионный тест для описанной выше ошибки усечённого поиска.

tests/test_send.py никогда ничего не отправляет и не открывает окно: он покрывает построитель URL, защитные условия и точный argv osascript — так что он безопасен где угодно и, соответственно, не может сказать вам, работает ли send от Apple.

Ни один из наборов не касается реального поискового индекса; оба внедряют временный.

Лицензия

MIT

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • 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
    A
    quality
    D
    maintenance
    Enables AI assistants to read iMessage history and send messages on macOS. Supports conversation listing, message search with keyword and semantic modes, contact lookup, and sending messages to existing conversations.
    13
    11
    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.
    19
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude to send and read iMessages on macOS, with human approval required for sending and no auto-replies.
    5
    1
    Apache 2.0

View all related MCP servers

Related MCP Connectors

  • Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.

  • MCP connector for iMessage & Contacts via a local Mac agent + Vercel relay

  • Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.

View all MCP Connectors

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/falconbradley/claude-connector-apple-messages'

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