mail-shadow-mcp

Servidor MCP para acceso estructurado y de solo lectura a correos electrónicos. Expone una superficie de API mínima y auditable: los agentes de IA pueden buscar y leer correos, pero no pueden enviar, eliminar ni modificar tu bandeja de entrada.

Documentación

mail-shadow-mcp logo

Build Latest Release Go Version Go Report Card License

La bandeja de entrada privada, segura e inteligente de tu agente de IA

Deja de darle a tu IA acceso directo a tu correo electrónico. Dale una copia "sombra" segura, ultrarrápida y llena de funciones.


¿Qué puedes hacer con mail-shadow-mcp?

Imagina tener un asistente personal que haya leído todos tus correos, sepa exactamente qué es importante y pueda responder tus preguntas en segundos, sin arriesgar jamás tu buzón real a través de una IA que se comporte mal o alucine.

Con mail-shadow-mcp, puedes preguntarle a tu IA (como OpenClaw, Hermes Agent, Claude, Cursor o cualquier otro agente personalizado):

  • "¿Recibí alguna factura de Amazon en los últimos 3 días?"
  • "Resume el último hilo de correo de mi jefe sobre el estado del proyecto."
  • "Por favor, resume todos los correos no leídos en mi carpeta 'Proyecto'."
  • "Comprueba si hay correos de confirmación de vuelo en mi bandeja de entrada para la próxima semana."
  • "Encuentra todos los correos de 'newsletter@example.com' que tengan archivos adjuntos."
  • "¿Hay algo en mi bandeja de entrada que parezca spam o basura?"

¿Por qué existe esto?

La mayoría de los agentes de IA requieren acceso directo a tu correo electrónico (IMAP) para "ver" tus mensajes. Esto es arriesgado, porque una vez que un agente tiene credenciales IMAP en vivo, tiene los mismos permisos que tú: puede leer, mover, eliminar o incluso enviar correos. Una sola alucinación, una instrucción mal entendida o un error podrían llevar a que una IA elimine accidentalmente toda tu bandeja de entrada, envíe una respuesta que nunca quisiste enviar o exponga tus credenciales a un tercero.

mail-shadow-mcp resuelve esto creando una "Zona Segura":

  1. La Copia Sombra: En lugar de conectarte a tu servidor de correo real, creamos una base de datos "sombra" local y de alta velocidad (SQLite) de tus correos. Esto también desbloquea capacidades que el IMAP puro simplemente no puede ofrecer: búsqueda instantánea de texto completo en todas las carpetas y cuentas a la vez, filtrado complejo por estado de leído/respondido, archivos adjuntos, rangos de fechas y remitente, todo sin idas y vueltas a tu servidor de correo. Y funciona igual de bien con múltiples buzones simultáneamente: solo agrega más cuentas a la configuración.
  2. Privacidad Total: Tu agente de IA solo se comunica con esta base de datos local. Tus credenciales IMAP son utilizadas exclusivamente por el motor de sincronización; nunca se exponen a través de ninguna llamada de herramienta MCP ni se devuelven al agente en ninguna respuesta.
  3. La "Red de Seguridad" (Eliminación Suave): Incluso si le pides a la IA que "elimine" un correo, en realidad no lo elimina. Simplemente lo mueve a una carpeta de "Papelera" que hayas designado. Si algo sale mal, siempre puedes revisar la carpeta, restaurar correos individuales o eliminarlos permanentemente tú mismo: mantienes el control total.
[Remote IMAP Server] ──IMAP──▶ [Sync Engine] ──▶ [SQLite FTS5] ◀──▶ [MCP Server] ◀──▶ [AI Agent]

Primeros pasos

La forma recomendada de ejecutar mail-shadow-mcp es mediante Docker. Ejecutarlo en un contenedor mantiene el motor de sincronización, las credenciales y la base de datos completamente aislados de tu agente de IA, que se conecta a través de HTTP. El agente nunca tiene acceso al sistema de archivos del host ni a tu contraseña IMAP, solo a la API MCP.

Si prefieres ejecutarlo localmente sin Docker, puedes descargar un binario precompilado desde la página de Releases y usar el transporte stdio en su lugar. Sin embargo, esto significa que el proceso del agente y mail-shadow-mcp comparten el mismo contexto de usuario, lo que reduce los beneficios de aislamiento descritos anteriormente.

Paso 1 — Inicia el contenedor para generar la configuración de ejemplo

Crea directorios locales para la configuración y los datos, luego haz una primera ejecución para generar la configuración de ejemplo:

mkdir -p ./config ./data

docker run --rm \
  -v ./config:/config \
  -v ./data:/data \
  ghcr.io/dryas/mail-shadow-mcp:latest

El contenedor detectará que no existe config.yaml, copiará una configuración de ejemplo anotada en ./config/, imprimirá un mensaje y saldrá.

Paso 2 — Edita el archivo de configuración

Abre ./config/config.yaml (o donde esté montado tu volumen /config) y completa tus datos IMAP:

sync_interval_min: 15

database:
  path: "/data/mail.db"

attachment_dir: "/data/attachments"

transport: http
http_addr: ":8080"
http_bearer_token: "your-secret-token"   # generate one: openssl rand -hex 32

accounts:
  - id: "work@example.com"
    host: "imap.example.com"
    port: 993
    username: "work@example.com"
    password: "$WORK_IMAP_PASS"          # resolved from environment variable at startup
    tls_mode: tls                        # tls (default) | starttls | none
    tls_skip_verify: false               # set true for self-signed certificates
    folders: ["INBOX", "Archive"]        # omit to sync all folders
    idle_folders: ["INBOX"]              # optional: instant new-mail push via IMAP IDLE
    trash_folder: "llm_delete"           # target folder for soft-deletes via delete_mail

Contraseñas como variables de entorno: En lugar de escribir tu contraseña IMAP directamente en el archivo de configuración, usa un marcador de posición $VARIABLE_NAME — mail-shadow-mcp lo resolverá desde el entorno del contenedor al inicio. En el ejemplo anterior, password: "$WORK_IMAP_PASS" significa que el contenedor lee el valor de la variable de entorno WORK_IMAP_PASS, que pasas mediante -e WORK_IMAP_PASS=your_password_here al iniciarlo (ver Paso 1 o 3). De esta manera, ninguna contraseña en texto plano termina en el archivo de configuración.

folders: La lista de carpetas IMAP a sincronizar. Si se omite, se sincronizan todas las carpetas. Restringir a las carpetas que realmente te interesan (por ejemplo, ["INBOX", "Archive"]) mantiene la base de datos más pequeña y la sincronización inicial más rápida.

idle_folders: Lista opcional de carpetas para las cuales mail-shadow-mcp abre una conexión IMAP IDLE persistente. Cuando el servidor de correo envía una notificación "EXISTS", se activa una sincronización inmediatamente en lugar de esperar al siguiente intervalo de sondeo, por lo que te informarás sobre nuevos correos en segundos. Mantén esta lista corta: cada entrada mantiene una conexión IMAP abierta durante toda la vida del contenedor. La mejor práctica es agregar solo "INBOX" aquí, o omitirla por completo y confiar en el sondeo regular.

trash_folder: La carpeta IMAP a la que mail-shadow-mcp mueve los correos cuando el agente de IA llama a la herramienta delete_mail. La carpeta ya debe existir en tu servidor de correo. Si no se establece, delete_mail devolverá un error y no hará nada: un valor predeterminado seguro. Los correos en la carpeta de papelera se excluyen automáticamente de todos los resultados de consulta MCP (búsqueda, actividad reciente, hilos), por lo que el agente nunca podrá volver a verlos, independientemente de si la carpeta está incluida en la configuración de sincronización. Nota: si alguna vez cambias trash_folder a un nombre de carpeta diferente, la carpeta de papelera anterior ya no se excluirá y su contenido volverá a ser visible para el agente en la próxima sincronización. Asegúrate de vaciar manualmente la carpeta anterior antes de cambiar.

http_bearer_token: Un token secreto que protege el endpoint HTTP de MCP. Cada solicitud del agente de IA debe incluirlo como Authorization: Bearer <token>. Sin esto, cualquiera que pueda acceder al puerto puede hablar con tu servidor MCP, así que siempre configúralo cuando se ejecute con transporte http. Genera un token aleatorio seguro con:

# Linux / macOS / WSL
openssl rand -hex 32
# Windows PowerShell
[System.Convert]::ToBase64String((1..32 | ForEach-Object { [byte](Get-Random -Max 256) }))

Copia la salida en la configuración y pasa el mismo valor a tu agente de IA (ver Paso 4).

Paso 3 — Inicia el contenedor

docker run -d \
  --name mail-shadow-mcp \
  --restart unless-stopped \
  -v ./config:/config:ro \
  -v ./data:/data \
  -e WORK_IMAP_PASS=your_password_here \
  -p 8080:8080 \
  ghcr.io/dryas/mail-shadow-mcp:latest

El servidor MCP ahora es accesible en http://localhost:8080/mcp.

Las imágenes multiarquitectura precompiladas (linux/amd64, linux/arm64) se publican en el Registro de Contenedores de GitHub en cada versión:

docker pull ghcr.io/dryas/mail-shadow-mcp:latest

Paso 4 — Conecta tu agente de IA

Dado que estamos ejecutando con Docker, el servidor MCP es accesible a través de HTTP, y eso también funciona con Claude Desktop, no solo con agentes remotos. Agrega lo siguiente a la configuración de tu agente:

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "mail_shadow": {
      "url": "http://localhost:8080/mcp",
      "headers": {
        "Authorization": "Bearer your-secret-token"
      }
    }
  }
}

Reemplaza localhost con la IP o el nombre de host de tu servidor si mail-shadow-mcp se ejecuta en una máquina diferente.

Hermes Agent (config.yaml):

  mail-shadow:
    url: http://localhost:8080/mcp
    headers:
      Authorization: Bearer your-secret-token

OpenClaw (~/.openclaw/openclaw.json):

{
  "mcp": {
    "servers": {
      "mail_shadow": {
        "url": "http://localhost:8080/mcp",
        "transport": "streamable-http",
        "headers": {
          "Authorization": "Bearer your-secret-token"
        }
      }
    }
  }
}

Alternativa: stdio local (binario precompilado, sin Docker)

Si elegiste ejecutar el binario directamente en lugar de Docker, usa la forma command:

{
  "mcpServers": {
    "mail_shadow": {
      "command": "/path/to/mail-shadow-mcp",
      "args": ["serve", "--config", "/path/to/config.yaml"]
    }
  }
}

Eso es todo: tu IA ahora puede buscar y leer tus correos de manera segura.


Seguridad: Nada se elimina realmente

mail-shadow-mcp les da a los agentes de IA una herramienta delete_mail, pero esta herramienta nunca emite un comando IMAP destructivo. Esto es exactamente lo que sucede cuando un agente la llama:

  1. El servidor MCP busca el correo en la base de datos local.
  2. Abre una conexión IMAP de corta duración y ejecuta IMAP MOVE, moviendo el mensaje a la trash_folder que especifiques en config.yaml (por ejemplo, "llm_delete").
  3. La entrada de la base de datos local se elimina, y la carpeta de papelera se excluye permanentemente de todos los resultados de consulta MCP: el agente nunca podrá volver a ver el correo movido, independientemente de si la carpeta está sincronizada.
  4. El correo permanece intacto en el servidor IMAP, guardado de manera segura en la carpeta de papelera. Puedes inspeccionarlo, restaurarlo o eliminarlo permanentemente tú mismo en cualquier momento.

El agente de IA no tiene acceso directo a IMAP. No puede purgar mensajes, vaciar carpetas ni emitir ningún comando de escritura aparte de este movimiento controlado. Si trash_folder no está configurado para una cuenta, delete_mail devuelve un error y no hace nada.


Inmersión técnica profunda

Herramientas MCP

HerramientaDescripción
list_accounts_and_foldersLista todas las cuentas sincronizadas y sus carpetas
get_recent_activityLos N correos más recientes con filtros opcionales (is_read, has_attachments, paginación)
get_email_contentTexto completo del cuerpo, estado de leído/respondido y lista de archivos adjuntos para un solo correo
search_emailsBúsqueda de texto completo FTS5 con filtros de asunto/remitente/fecha/carpeta/is_read/sent_by
get_threadTodos los correos en el mismo hilo que un correo dado, ordenados por fecha ascendente
download_attachmentsObtener archivos adjuntos de IMAP y guardarlos en disco
get_download_linkGenerar una URL de descarga HTTP temporal para archivos adjuntos (respaldo opcional)
delete_mailEliminación suave de un correo moviéndolo a una carpeta de papelera configurada (IMAP MOVE, sin eliminación permanente)

Resumen de características

  • Base de datos sombra local — los correos se sincronizan en una base de datos SQLite local; el agente de IA nunca se conecta directamente a tu servidor IMAP
  • Sincronización de solo lectura — el motor de sincronización solo emite comandos de lectura (SELECT, UID FETCH); nunca se envía STORE, APPEND o EXPUNGE a tu servidor de correo
  • Sincronización incremental — solo obtiene mensajes más recientes que el último UID conocido
  • Búsqueda de texto completo — índice SQLite FTS5 para consultas rápidas de texto del cuerpo
  • Multi-cuenta — sincroniza cualquier número de cuentas IMAP simultáneamente
  • IMAP IDLE — notificaciones push opcionales en tiempo real; correo nuevo detectado en segundos en lugar de esperar el siguiente intervalo de sondeo
  • Estado de leído/respondido — banderas is_read y is_replied sincronizadas desde IMAP y expuestas como filtros
  • Vista de hilo — get_thread recorre conversaciones de correo completas mediante los encabezados Message-ID / In-Reply-To
  • Resultados paginados — todas las herramientas de lista devuelven total_count para que los agentes puedan paginar a través de grandes conjuntos de resultados
  • Archivos adjuntos bajo demanda — los archivos adjuntos se obtienen de IMAP solo cuando se solicitan explícitamente
  • Transporte flexible — stdio para herramientas locales (Claude Desktop), http (StreamableHTTP) o sse para implementaciones remotas y Docker
  • Listo para Docker — imagen oficial multiarquitectura (linux/amd64, linux/arm64) publicada en ghcr.io en cada versión

Referencia completa de configuración

sync_interval_min: 15

database:
  path: "data/mail.db"      # path to the local SQLite shadow database

attachment_dir: "data/attachments"  # base directory for downloaded attachments

# Optional: log file and level. Omit log_file to write to stderr (default).
# log_file: "logs/mail-shadow-mcp.log"  # append mode; directory is created automatically
# log_level: info                        # debug | info (default) | warn | error
# log_format: text                       # text (default) | json

# MCP transport mode.
# stdio (default) — stdin/stdout, used by Claude Desktop and most local tools.
# http            — StreamableHTTP, recommended for Docker and remote deployments.
# sse             — legacy SSE transport (prefer http unless your client requires SSE).
# transport: stdio
# http_addr: ":8080"                      # bind address for http/sse (default: :8080)
# http_base_url: "http://localhost:8080"  # sse only: externally reachable base URL
# http_bearer_token: ""                  # recommended: set a secret token to protect the HTTP endpoint
                                         # generate one with: openssl rand -hex 32

# Optional: lightweight HTTP server for temporary attachment download links.
# fileserver_port: 8787               # TCP port to listen on (disabled if omitted)
# fileserver_ttl_min: 15              # minutes before a link expires (default: 15)
# fileserver_host: "localhost"        # hostname/IP shown in generated URLs

accounts:
  - id: "work@example.com"
    host: "imap.example.com"
    port: 993
    username: "work@example.com"
    password: "$WORK_IMAP_PASS"     # or plain text; prefix with $ to read from env var
    tls_mode: tls                   # tls (default, implicit TLS, port 993)
                                    # starttls (STARTTLS upgrade, port 143)
                                    # none (no encryption — localhost/testing only)
    tls_skip_verify: false          # set true for self-signed certificates
    folders: ["INBOX", "Archive"]   # optional: omit to sync all folders
    # idle_folders: ["INBOX"]       # optional: folders watched via IMAP IDLE for instant new-mail notification
    # trash_folder: "llm_delete"    # optional: target folder for delete_mail (soft-delete via IMAP MOVE)

Docker Compose

services:
  mail-shadow-mcp:
    image: ghcr.io/dryas/mail-shadow-mcp:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./config/config.yaml:/config/config.yaml:ro   # your config — mount read-only
      - ./data:/data                                  # persistent DB + attachments
    environment:
      - WORK_IMAP_PASS=your_password_here             # referenced as $WORK_IMAP_PASS in config

Contraseñas como variables de entorno: En config.yaml puedes hacer referencia a contraseñas como $ENV_VAR — el servidor las resuelve al inicio. Pásalas mediante environment: en docker-compose o mediante -e con docker run. De esta manera, ninguna contraseña en texto plano termina en el archivo de configuración.

Modos TLS

tls_modePuertoDescripción
tls993TLS implícito (predeterminado)
starttls143Actualización STARTTLS
none143Sin cifrado — solo localhost/pruebas

Establece tls_skip_verify: true para aceptar certificados autofirmados.

Autenticación (Token Bearer)

Cuando uses el transporte http o sse, siempre establece http_bearer_token — de lo contrario, el endpoint MCP es accesible para cualquiera que pueda acceder al puerto.

Genera un token criptográficamente seguro:

# Linux / macOS / WSL
openssl rand -hex 32

# PowerShell
[System.Convert]::ToBase64String((1..32 | ForEach-Object { [byte](Get-Random -Max 256) }))

IMAP IDLE (Push en tiempo real)

De forma predeterminada, mail-shadow-mcp sondea nuevos mensajes cada sync_interval_min minutos. Para carpetas donde quieras notificaciones casi instantáneas, habilita IMAP IDLE:

accounts:
  - id: "work@example.com"
    # ...
    idle_folders: ["INBOX"]   # IDLE runs on top of regular polling
  • Se abre una conexión IMAP dedicada por cada entrada en idle_folders
  • Cuando el servidor envía una notificación EXISTS, se activa una sincronización inmediatamente
  • El sondeo regular continúa sin cambios para todas las demás carpetas
  • Vuelve al sondeo automáticamente si el servidor no admite IDLE
  • Retroceso exponencial (30 s → 5 min) en errores de conexión persistentes

Servidor de descarga de adjuntos

El servidor HTTP integrado opcional permite que el agente de IA genere enlaces de descarga temporales de un solo uso para archivos adjuntos, útil como alternativa cuando el agente no puede transferir archivos a través de sus canales normales.

Habilítalo en config.yaml:

fileserver_port: 8787        # TCP port to listen on
fileserver_ttl_min: 15       # minutes before a link expires (default: 15)
fileserver_host: "localhost" # hostname/IP shown in generated URLs

Compilación desde el código fuente

make build          # current platform
make release        # cross-compile for all platforms into dist/

Requiere Go 1.25+.

Comandos de CLI

Además de ejecutarse como servidor MCP, mail-shadow-mcp expone algunos comandos de CLI útiles para operaciones manuales, scripting o depuración, sin necesidad de un agente de IA.

Activar una sincronización única (obtiene nuevos correos en la base de datos local y sale):

./mail-shadow-mcp sync

Consultar la base de datos local (la salida es JSON delimitado por líneas, adecuado para canalizaciones de jq):

# Search by subject and body keyword
./mail-shadow-mcp query --subject "invoice" --body "Q1"

# Full-text search with attachment filter
./mail-shadow-mcp query -q "budget" --attachments only

# Most recent emails, paginated
./mail-shadow-mcp query --recent --limit 10 --offset 10

Descargar adjuntos de un correo específico por su ID (formato account:folder:uid):

./mail-shadow-mcp attachments --id "work@example.com:INBOX:42"

Licencia

Apache 2.0 — consulta LICENSE para más detalles.
Copyright (c) 2026 Benjamin Kaiser.