Skip to main content
Glama
cannavis

imessage-rich-search

by cannavis

imessage-rich-search

Búsqueda de texto completo en iMessages de macOS — incluyendo los metadatos de vista previa de enlaces (títulos, resúmenes, nombres de sitios) que Messages.app indexa pero que la columna de texto chat.db sin procesar nunca expone.

License: MIT Python 3.9+ Platform: macOS No deps MCP

El problema que resuelve

Cuando pegas una URL en iMessage, macOS obtiene una vista previa enriquecida (título, resumen, nombre del sitio, imagen principal) y almacena esos metadatos en chat.db como un blob de NSKeyedArchiver en message.payload_data. La barra de búsqueda de Messages.app los lee. La columna text básica de chat.db no los contiene.

Por lo tanto, si un amigo te envió https://x.com/foo/status/123 y la tarjeta de vista previa decía "Obsidian + Claude Code es la pila de productividad más subestimada" — buscar "obsidian" en cualquier herramienta que solo lea text devuelve cero resultados. Messages.app los encuentra. Esta herramienta los encuentra. Ambas buscan en la misma superficie.

Related MCP server: imessage-mcp

Características

  • Busca en el cuerpo del mensaje y en los metadatos de vista previa de enlaces decodificados en una sola pasada

  • Filtrar por identificador (teléfono / correo electrónico)

  • Salida legible por humanos o en formato JSON

  • Solo lectura en chat.db (usa el modo URI de SQLite)

  • Cero dependencias en tiempo de ejecución para la CLI (solo biblioteca estándar de Python)

  • Servidor MCP opcional para que Claude Desktop / Claude.ai pueda llamarlo directamente

  • Resultados de más reciente a más antiguo, marcas de tiempo ISO 8601, flechas de dirección, rowid para referencia cruzada

Qué es — y qué no es

Es:

  • Una búsqueda forense / de archivo de solo lectura sobre tu chat.db local

  • Un complemento directo para herramientas MCP de iMessage que solo ven texto sin procesar

  • ~200 líneas de Python de la biblioteca estándar

No es:

  • Un reemplazo de Messages.app (sin interfaz de usuario, sin envío/edición/eliminación)

  • Una forma de acceder a los mensajes de otra persona

  • Una herramienta de sincronización de iCloud / multidispositivo — busca solo lo que está localmente en este Mac

  • Un bypass para el Acceso total al disco — debes otorgarlo explícitamente

  • Un lector de OCR / imagen / audio / sticker / escritura a mano (solo texto + metadatos de enlace)

  • Una forma de recuperar mensajes eliminados más allá de lo que SQLite aún conserva

Requisitos

SO

macOS 11 Big Sur o posterior (probado hasta macOS 26)

Arquitectura

Apple Silicon (arm64) o Intel (x86_64)

Python

3.9+ (el /usr/bin/python3 del sistema funciona — y es necesario para el servidor MCP, ver Instalación)

Disco

Despreciable (~50 KB instalado)

Permisos

Acceso total al disco para la terminal/aplicación que ejecuta el script

Los campos del esquema de chat.db en los que se basa (text, payload_data, balloon_bundle_id, handle.id) han sido estables desde macOS 10.13 High Sierra; es probable que esta herramienta funcione incluso en versiones anteriores a su límite reclamado oficialmente, aunque no está probado.

Instalación

Opción A — pipx (recomendado, se requiere Python del sistema para el servidor MCP)

pipx aísla la herramienta en su propio venv. Instala pipx primero si es necesario:

brew install pipx
pipx ensurepath

Luego instala esta herramienta desde GitHub. Usa /usr/bin/python3 explícitamente — esto es importante para el servidor MCP porque macOS solo propaga el Acceso total al disco desde Claude.app a procesos secundarios firmados por Apple. El Python de Homebrew está firmado por terceros; el /usr/bin/python3 del sistema está firmado por Apple y se hereda limpiamente. Si no te interesa el servidor MCP (solo CLI), cualquier Python 3.9+ funciona.

pipx install --python /usr/bin/python3 "git+https://github.com/cannavis/imessage-rich-search"

Esto instala tres comandos en tu PATH (bajo ~/.local/bin):

  • imessage-rich-search — la CLI

  • imrs — un alias corto para la CLI

  • imessage-rich-search-mcp — el servidor MCP

Opción B — pip en un venv

git clone https://github.com/cannavis/imessage-rich-search
cd imessage-rich-search
/usr/bin/python3 -m venv .venv && source .venv/bin/activate
pip install -e .

Opción C — archivo único, sin instalación

El módulo CLI no tiene dependencias. Puedes descargarlo con curl y ejecutarlo:

curl -O https://raw.githubusercontent.com/cannavis/imessage-rich-search/main/src/imessage_rich_search/cli.py
python3 cli.py "obsidian"

Otorgar Acceso total al disco (única vez, obligatorio)

chat.db está bloqueado por TCC de macOS. Sin FDA obtendrás unable to open database file.

  1. Abre Ajustes del Sistema → Privacidad y seguridad → Acceso total al disco

  2. Haz clic en + y añade la aplicación desde la que ejecutarás esto:

    • ¿Ejecutas imessage-rich-search directamente en la shell? → añade Terminal (o iTerm, Warp, Ghostty, Alacritty, etc. — la terminal que realmente uses)

    • ¿Lo ejecutas desde Claude Desktop vía MCP? → añade Claude.app

    • ¿Lo ejecutas desde un editor de scripts o IDE? → añade esa aplicación

  3. Cierra y reinicia esa aplicación por completo (⌘Q, no solo cerrar la ventana) para que el permiso surta efecto

  4. Verifica: python3 -c "import sqlite3; sqlite3.connect('file:'+__import__('os').path.expanduser('~/Library/Messages/chat.db')+'?mode=ro', uri=True).execute('SELECT COUNT(*) FROM message').fetchone()" — debería imprimir un número, no un error

Uso

# Basic search across all conversations
imessage-rich-search "obsidian"

# Restrict to one contact
imessage-rich-search "obsidian" --contact "+14073993471"

# JSON for piping into jq, scripts, or another tool
imessage-rich-search "obsidian" --contact "+14073993471" --json | jq '.[].preview[0]'

# Limit results, point at a backup chat.db
imessage-rich-search "claude code" --limit 20 --db /path/to/chat.db

# Short alias
imrs "obsidian"

# Module form (no entry point needed)
python3 -m imessage_rich_search "obsidian"

Salida

6 match(es) for 'obsidian':

[2026-04-08T22:56:23+00:00] -> +14073993471  (rowid=234953)
    url:     https://x.com/aiedge_/status/2041908011078447222?s=42
  * preview: Claude Code + Obsidian Ultimate Guide (build an AI second brain)
...

-> = enviado · <- = recibido · * = línea de vista previa que contiene tu consulta · rowid = clave de referencia cruzada en chat.db.

Uso como servidor MCP (Claude Desktop)

Permite que Claude Desktop llame a la búsqueda directamente durante las conversaciones.

  1. Instala el paquete usando el Python del sistema (Opción A anterior con --python /usr/bin/python3). Esto es obligatorio: el Acceso total al disco de macOS solo se propaga desde Claude.app a subprocesos firmados por Apple. /usr/bin/python3 está firmado por Apple; los Pythons instalados por Homebrew / pyenv / asdf no lo están, y serán denegados silenciosamente por tccd.

  2. Encuentra la ruta absoluta del punto de entrada: which imessage-rich-search-mcp

  3. Edita ~/Library/Application Support/Claude/claude_desktop_config.json:

    {
      "mcpServers": {
        "imessage-rich-search": {
          "command": "/full/path/from/which/imessage-rich-search-mcp"
        }
      }
    }
  4. Confirma que Claude.app ya tiene Acceso total al disco (lo tiene por defecto una vez que lo otorgas una vez — verifica en Ajustes del Sistema → Privacidad y seguridad → Acceso total al disco)

  5. Cierra y reinicia Claude Desktop por completo (⌘Q)

Claude ahora puede llamar a search_imessages_rich(query, contact?, limit?) como una herramienta.

Verificación de que la herencia TCC funciona

Si el servidor MCP devuelve "unable to open database file" dentro de Claude Desktop, la cadena de atribución de lanzamiento está rota. Revisa el registro del demonio TCC de macOS:

log show --predicate 'process == "tccd"' --last 5m | grep -iE "imessage-rich|chat\.db|SystemPolicyAllFiles"

A una instalación que funciona se le muestra la solicitud como permitida. Una instalación rota muestra responsible_path= apuntando a un binario de Python no firmado por Apple, seguido de recording denied. Reinstala con pipx install --python /usr/bin/python3 ... para corregirlo.

Cómo funciona

chat.db (SQLite, read-only)
  └─ message
       ├─ text                     ← raw text (what basic tools see)
       ├─ payload_data  (BLOB)     ← NSKeyedArchiver bplist of LPLinkMetadata
       │                              (title, summary, site, image refs)
       └─ balloon_bundle_id        ← e.g. com.apple.messages.URLBalloonProvider

For every row:
  1. Read text + payload_data
  2. plistlib.loads(payload_data) → walk $objects → collect strings
  3. Lower-case haystack = text + "\n".join(preview_strings)
  4. Match if query.lower() in haystack

El truco de "extraer cadenas de $objects" evita la necesidad de ccl_bplist, pyobjc o semántica completa de NSKeyedUnarchiver — para la búsqueda de texto completo no nos importa el grafo de objetos, solo las cadenas hoja.

Privacidad y seguridad

  • Solo lectura. Abre chat.db con la bandera URI de SQLite mode=ro.

  • Solo local. Sin llamadas de red. Nunca. (grep -r 'urllib\|requests\|http' src/ no devuelve nada.)

  • Sin telemetría.

  • Ningún dato sale de tu Mac a menos que elijas compartir la salida.

  • La CLI no tiene dependencias en tiempo de ejecución — nada que pueda ser atacado a través de la cadena de suministro.

  • Consulta SECURITY.md para reportar vulnerabilidades.

Limitaciones

  • Solo coincidencia de subcadenas. Sin clasificación FTS5, sin regex, sin operadores booleanos. Añádelo si lo deseas (PR welcome).

  • Solo base de datos local. Si un mensaje vive solo en iCloud y no está sincronizado con el chat.db de este Mac, no aparecerá.

  • Los metadatos de vista previa dependen de que Messages.app los haya obtenido. Si la tarjeta de enlace nunca se cargó (envío sin conexión, URL caducada), no hay payload_data para buscar.

  • La extracción de cadenas es con pérdida por diseño. Extrae cada cadena del bplist; ocasionalmente puedes ver tipos MIME de imágenes, tuplas de dimensiones como {0, 0} o URLs de imágenes de perfil en la lista de vista previa. No afectan los resultados de búsqueda pero aparecen en la salida sin procesar.

  • El Acceso total al disco es un requisito estricto — no hay solución alternativa.

Solución de problemas

Síntoma

Solución

unable to open database file / cannot open chat.db

Acceso total al disco no otorgado a la aplicación en ejecución. Añade la aplicación, luego ⌘Q + reiniciar.

Devuelve 0 coincidencias pero Messages.app las encuentra

Formato de --contact incorrecto (debe coincidir con el handle.id en chat.db — típicamente +1XXXXXXXXXX o correo electrónico completo). Ejecuta sin --contact para confirmar.

unable to open database file desde la llamada MCP de Claude Desktop (pero la CLI funciona bien)

TCC denegó el Python generado. Reinstala con Python del sistema: pipx reinstall --python /usr/bin/python3 imessage-rich-search. Consulta la sección de verificación TCC.

No module named 'imessage_rich_search' al iniciar el servidor MCP

Reinstala con pipx install --python /usr/bin/python3 "git+https://github.com/cannavis/imessage-rich-search"

Claude Desktop no ve la herramienta

Verifica la sintaxis JSON en claude_desktop_config.json, cierra Claude por completo (⌘Q), reinicia.

La búsqueda es lenta en bases de datos enormes

La implementación actual realiza un escaneo lineal + análisis bplist por fila. Para bases de datos de más de 100k mensajes, espera unos segundos. Un índice respaldado por tabla virtual FTS5 está en la hoja de ruta.

Contribución

Consulta CONTRIBUTING.md. Problemas y PRs son bienvenidos.

Registro de cambios

Consulta CHANGELOG.md.

Licencia

MIT — consulta LICENSE.

Agradecimientos

  • El esquema chat.db de Apple, que ha sido notablemente estable a lo largo de una década de lanzamientos de macOS

  • Las personas que realizaron ingeniería inversa de payload_data / LPLinkMetadata a lo largo de los años

  • Model Context Protocol por la especificación MCP

Available Tools

1 tool
search_imessages_richA

Full-text search across macOS iMessages including link preview metadata (title, summary, site name) that Apple stores in payload_data — content the basic chat.db text column does not expose. Returns newest-first matches where the query (case-insensitive substring) appears in either the message body OR the rich link preview.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesSubstring to search for (case-insensitive).
contactNoOptional handle filter, e.g. '+14073993471' or 'name@example.com'.
limitNoMax matches to return (default 50).

TDQS

A4.3/5.0
Behavior4/5

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

With no annotations, description carries full burden. Discloses search over message body and rich link preview, case-insensitive substring matching, and newest-first sorting. Could add more on returns (empty results, pagination) but covers key behavioral traits.

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?

Two sentences, front-loaded with purpose, no superfluous words. Each sentence adds value: first defines scope, second details ordering and search targets.

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

Completeness3/5

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

No output schema, so description should cover return structure. It mentions 'newest-first matches' but does not describe fields (e.g., message text, sender, timestamp, preview metadata). Agent may need to infer or handle uncertainly. Lacks completeness for a search tool without output schema.

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?

Schema descriptions cover 100% of parameters, but description adds operational context: query searches both body and preview, contact is an optional handle filter, and limit default/max. Adds meaning beyond schema fields.

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?

Clearly states it performs full-text search across macOS iMessages, including link preview metadata beyond basic chat.db. Specifies scope, search scope (body or preview), and result ordering (newest-first). Distinguishes from potential siblings by highlighting the rich link preview capability.

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?

Provides context that this tool searches rich link preview metadata not exposed by basic chat.db, implying its niche. However, it does not explicitly state when not to use it or mention alternatives. Still clear enough for an agent to infer appropriate scenarios.

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. 1 tool updatev0.2.0
    • First observedsearch_imessages_rich

TDQS

A4.3/5.0

Scored across 1 tool

Disambiguation5/5

Only one tool exists, so there is no possibility of confusion or ambiguity between tools.

Naming Consistency5/5

With a single tool, naming consistency is perfect; the name 'search_imessages_rich' is descriptive and follows a clear verb_noun pattern.

Tool Count3/5

A single tool feels thin for a server named 'imessage-rich-search', as it likely covers only a narrow part of iMessage interaction. While the tool is focused, users may expect additional functionality like retrieving messages or managing conversations.

Completeness4/5

The tool thoroughly performs the described search across both message text and rich link previews, but lacks complementary operations such as fetching individual messages or performing more advanced queries, which are minor gaps.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    A 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.
    6
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    A read-only MCP server that exposes your iMessage data to Claude Code and Claude Desktop, with automatic contact name resolution.
    3
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Read, search, and send iMessages locally from your terminal or through MCP clients like Claude, Cursor, and VS Code.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    macOS-only MCP server that exposes iMessage history to Claude and exports per-chat conversations into an Obsidian vault.
    2
    MIT