Apple Messages MCP
Apple Messages MCP
Lee y busca tus conversaciones de iMessage, SMS y RCS desde Claude, en macOS.
Complemento de claude-connector-apple-mail y claude-connector-apple-reminders.
Estado: la lectura y la búsqueda son sólidas. El envío funciona, pero no está probado en un envío real — la llamada de scripting está implementada y su sintaxis verificada, pero Apple ha roto
sendantes, así que trata el primer envío real como una prueba. Ver Envío de mensajes.
Herramientas
Tool | Description |
| Totales, recuento de no leídos, desglose por servicio (iMessage/SMS/RCS), rango de fechas |
| Conversaciones, las más recientes primero, con participantes y una vista previa |
| Mensajes de una conversación, de más antiguo a más reciente, paginados |
| Búsqueda de subcadenas en todo el historial, filtrada por chat, remitente y rango de fechas |
| Un mensaje completo, con adjuntos y marcas de tiempo de entrega |
| Bytes del adjunto, codificados en base64 |
| Calienta o reconstruye el índice de búsqueda local |
| Abre Messages con el texto prellenado — tú pulsas enviar |
| Envía a una conversación existente; entrega inmediatamente |
Related MCP server: jons-mcp-imessage
Requisitos
macOS 13 Ventura o posterior. RCS requiere macOS 26 o posterior.
Acceso total al disco para la app de Claude — necesario para la lectura.
Permiso de Automatización para Messages — necesario para el envío y para los nombres de contacto. macOS solicita este permiso automáticamente.
Cómo otorgar Acceso total al disco
Ajustes del Sistema → Privacidad y Seguridad → Acceso total al disco
Activa Claude (añade
/Applications/Claude.appcon + si no aparece en la lista)Sal y vuelve a abrir Claude. macOS guarda en caché este permiso al iniciar el proceso, por lo que el reinicio es obligatorio: la extensión seguirá fallando sin él.
Por qué esto necesita Acceso total al disco cuando Apple Mail no
La extensión de Apple Mail se comunica con Mail.app enteramente mediante scripting, por lo que no necesita permisos especiales. Messages no puede funcionar de esa manera.
El diccionario de AppleScript de Messages expone exactamente cuatro clases — account, chat, participant, file transfer — y ninguna clase de mensaje. Verificado en 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)Los chats y los participantes se enumeran sin problema; los cuerpos de los mensajes simplemente no están expuestos. Así que la única vía de lectura es SQLite sobre ~/Library/Messages/chat.db, que está protegido por TCC. A diferencia de la Automatización, el Acceso total al disco no puede solicitarse mediante programación: el usuario debe concederlo manualmente.
Por lo tanto, la extensión utiliza ambos permisos para distintas tareas:
Ámbito | Mecanismo | Permiso |
Messages, chats, búsqueda, adjuntos | SQLite sobre | Acceso total al disco |
Nombres de contacto para identificadores sin procesar | Scripting de Messages | Automatización |
Envío | Scripting de Messages ( | Automatización |
Ventana de redacción, prellenada | Esquema de URL | ninguno |
Los nombres de contacto provienen de la clase participant de Messages (full name), que lee la tarjeta de Contactos del usuario. Esto evita la base de datos de AddressBook, protegida por separado: si se deniega la Automatización, los identificadores se muestran simplemente como números sin procesar.
Notas de implementación
attributedBody. Desde Ventura, message.text es frecuentemente NULL y el cuerpo vive en message.attributedBody como un typedstream de Apple — el formato heredado de NSArchiver, que plistlib no puede leer. typedstream.py lo decodifica en Python puro, por lo que el paquete no necesita dependencia de PyObjC. Se ancla en el nombre de clase NSString/NSMutableString y lee la carga útil UTF-8 con prefijo de longitud después del marcador de tipo +. La decodificación es total: un cuerpo no decodificable produce None en lugar de hacer fallar la consulta.
Marcas de tiempo. message.date es la época de Apple (2001-01-01), en segundos antes de macOS 13 y en nanosegundos desde entonces. Ambos casos se detectan y se manejan.
Búsqueda. chat.db no incluye ningún índice de texto, y la mayoría de los cuerpos viven solo en attributedBody, donde SQL no puede verlos. Esa combinación es más problemática de lo que parece.
La primera implementación ampliaba su predicado a m.text LIKE ? OR m.attributedBody IS NOT NULL y volvía a filtrar el texto decodificado en Python. Como esa segunda cláusula es verdadera para casi todas las filas modernas, el LIMIT de la consulta truncaba el escaneo a los últimos cientos de mensajes antes de que el filtro de Python llegara a ejecutarse, por lo que cualquier coincidencia más antigua desaparecía silenciosamente. Una búsqueda de un mensaje real devolvía cero resultados en lugar de ser lenta. En un historial de 916 MB, eso significaba que la búsqueda cubría efectivamente solo los últimos días.
La solución es decodificar una sola vez en lugar de hacerlo por consulta. index.py replica los cuerpos decodificados y convertidos a minúsculas (casefold) en ~/Library/Caches/apple-messages-mcp/search-index.db, contra el que las búsquedas hacen join — de modo que la coincidencia, los filtros, el orden y el LIMIT se aplican al historial completo en SQL. El espejo es:
Incremental. Los mensajes nuevos se encuentran mediante una marca de agua
message.ROWID. Las ediciones y las cancelaciones de envío reutilizan un ROWID existente, por lo que cada actualización también examina las 2000 filas más recientes — pero solo aquellas condate_editedestablecido o con ambas columnas de cuerpo ahora NULL, ya que volver a decodificar 2000 blobs en cada búsqueda es un trabajo real que casi nunca encuentra nada. Una edición que Messages no haya marcado de algún modo, o una más antigua que esa ventana, necesitarefresh_search_index(rebuild=True). Mejorar el decodificador deattributedBodytambién justifica una reconstrucción; aumentarSCHEMA_VERSIONfuerza una.Solo con casefold, y nada más. El texto mostrado sigue viniendo de chat.db, por lo que el espejo es puramente un oráculo de coincidencias. Almacenar
str.casefold()reduce su tamaño a la mitad y hace que la coincidencia sin distinción de mayúsculas sea correcta para texto no ASCII — elLIKEde SQLite solo pliega mayúsculas para ASCII.Desechable. Vive en
~/Library/Cachesy se reconstruye si se elimina. Nada de esto escribe en chat.db.
No es FTS5, a pesar del plan anterior: FTS5 coincide con tokens completos, por lo que MATCH 'dentist' nunca encuentra "mydentist", lo cual es más restrictivo que la semántica de subcadena que documenta search_messages. Un escaneo de subcadenas sobre texto compacto con casefold ya es rápido, así que FTS5 habría duplicado el índice para una semántica que no podemos usar. Añadirlo más adelante es un cambio contenido si alguna consulta llegara a ir lenta.
Solo lectura y sin bloqueos. Las conexiones se abren con mode=ro y ninguna sentencia muta la base de datos. Si SQLite no puede abrir el WAL en vivo en modo solo lectura, recurre a una copia instantánea privada para que una instancia en ejecución de Messages.app nunca se vea afectada.
Tapbacks, ediciones, respuestas. Las reacciones se decodifican desde associated_message_type (2000–2007, con el rango 3000 como sus eliminaciones), las respuestas en hilo desde thread_originator_guid, y las ediciones desde date_edited.
Envío de mensajes
Messages no tiene objeto de borrador, por lo que no existe un análogo exacto del diseño de borrador primero de la extensión de Mail. Por lo tanto, la vía de escritura se presenta en dos niveles, y deliberadamente no son equivalentes.
compose_message — el valor seguro por defecto. Abre Messages con el destinatario y el cuerpo prellenados mediante el esquema de URL imessage: / sms:, y se detiene. Una persona lo lee y pulsa enviar, así que nada sale de la máquina por orden de Claude. Esta es también la única forma de iniciar una conversación nueva. No necesita ningún permiso.
send_message — entrega inmediatamente. Utiliza el send de la interfaz de scripting, y no se puede deshacer. Toma un chat_id en lugar de un número de teléfono, lo cual no es una limitación sino el objetivo: el diccionario acepta tanto un participant como un chat, y dirigirse a un chat existente por GUID permite que Messages elija el transporte (iMessage / SMS / RCS) en lugar de que quien llama adivine y envíe silenciosamente un SMS a alguien que está en iMessage. También requiere confirm=True, puramente como protección contra una activación casual.
Qué está verificado y qué no
Confirmado en macOS 26.5.2 — el diccionario expone
send : direct-parameter (file | text), to: (participant | chat)la enumeración service type es SMS, iMessage, RCS, chat tiene una propiedad id GUID para dirigirse a él, y el AppleScript generado compila.
No confirmado: que un envío real realmente entregue. Apple ha roto el send de AppleScript antes, y su presencia en el diccionario nunca ha sido prueba de que funcione. Nada en el conjunto de pruebas entrega un mensaje, así que el primer envío real es el experimento. Si falla, shortcuts run con una acción "Enviar mensaje" es la alternativa que vale la pena probar a continuación.
El texto del mensaje llega a AppleScript como un argumento de osascript (on run argv) en lugar de ser interpolado en el código fuente del script, por lo que un cuerpo que contenga una comilla doble es inerte en lugar de un error de sintaxis o una inyección.
El envío de adjuntos no está conectado, aunque el parámetro directo file significa que está al alcance.
Desarrollo
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 .mcpbtests/test_db.py crea bases de datos desechables con el esquema real, por lo que el SQL puede validarse sin Acceso total al disco ni un historial de mensajes real. Una de ellas entierra una coincidencia bajo 3000 mensajes más recientes, que es la prueba de regresión para el error de búsqueda truncada descrito anteriormente.
tests/test_send.py nunca envía nada ni abre una ventana: cubre el constructor de URL, las cláusulas de protección y el argv exacto de osascript — por lo que es seguro en cualquier lugar y, en consecuencia, no puede decirte si el send de Apple funciona.
Ninguna de las dos suites toca el índice de búsqueda real; ambas inyectan uno temporal.
Licencia
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
- AlicenseNot gradedqualityCmaintenanceEnables Claude to send and read iMessages on macOS, with smart contact lookup, message history retrieval, and cross-conversation search using natural language commands.5MIT
- AlicenseAqualityDmaintenanceEnables 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.1311MIT
- AlicenseNot gradedqualityDmaintenanceEnables 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.19MIT
- AlicenseNot gradedqualityBmaintenanceEnables Claude to send and read iMessages on macOS, with human approval required for sending and no auto-replies.51Apache 2.0
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.
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/falconbradley/claude-connector-apple-messages'
If you have feedback or need assistance with the MCP directory API, please join our Discord server