Skip to main content
Glama
dnlbertoni

zimbra-mcp

by dnlbertoni

zimbra-mcp

Servidor MCP en Python que expone tu casilla Zimbra (IMAP + SMTP + LDAP/GAL) como herramientas para Claude / Cowork.

🚀 Start Rápido

¿Primera vez? → Seguí QUICKSTART.md (5 minutos)

¿Querés ejemplos detallados? → Ver INTEGRATION_EXAMPLES.md

Incluye:

  • 📘 Claude Desktop (Windows, macOS, Linux)

  • 🟢 ChatGPT con Bridge API

  • ☁️ Deployment en AWS, DigitalOcean, Fly.io

  • 🔐 Seguridad en producción

Probado contra mcp SDK v2.0.0 (API MCPServer, no la vieja FastMCP). Si en tu máquina pip install mcp te trae una versión distinta y algo no importa, fijate el changelog del SDK — la clase clave hoy es mcp.server.MCPServer.

📚 Documentación

Documento

Para qué

INSTALL_CLAUDE_DESKTOP.md

🎯 Instalar en Claude Desktop (método actual con .mcpb)

QUICKSTART.md

⚡ Setup alternativo (Docker, venv local)

INTEGRATION_EXAMPLES.md

📖 Ejemplos para ChatGPT, AWS, DigitalOcean, Fly.io

REFERENCE.md

📋 Tabla de herramientas, variables, configuración

README.md

📘 Overview general (este archivo)

Herramientas expuestas

Tool

Qué hace

list_folders

Lista las carpetas IMAP

search_messages

Busca por remitente, asunto, texto, no-leídos, rango de fechas

get_message

Trae el contenido completo (texto/html/adjuntos) de un mensaje

mark_message

Pone/saca flags: seen, flagged, answered, deleted

move_message

Mueve/archiva un mensaje a otra carpeta

delete_message

Por defecto mueve a Trash (recuperable); permanent=True hace expunge real

download_attachment

Descarga un adjunto al volumen /data/attachments

send_email

Envía correo por SMTP (texto/html, cc/bcc, adjuntos, threading)

search_contacts

Busca en la Libreta Global (GAL) por LDAP

get_contact

Trae el detalle de un contacto GAL por su DN

get_access_token

(auth) Genera un JWT access token a partir de una API key

⚠️ Sobre LDAP/GAL — leé esto antes de asumir que va a andar

El LDAP interno de Zimbra (OpenLDAP embebido) generalmente solo escucha en localhost del propio servidor de correo y no está expuesto hacia afuera por defecto. Si tu Zimbra no tiene el puerto LDAP (389/636) abierto para vos desde donde corra este contenedor, search_contacts/get_contact van a fallar con un error explicando por qué — no es un bug del código. Antes de invertir tiempo en esto:

  1. Preguntale a tu admin de Zimbra si el LDAP de GAL está expuesto externamente y con qué host/puerto/base DN.

  2. Si no lo está, la alternativa típica es CardDAV (no implementado acá todavía) o la API SOAP/REST de Zimbra — avisame si querés que lo agregue.

Setup rápido (sin Docker, para probar)

cd zimbra-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env   # completá ZIMBRA_USERNAME, ZIMBRA_PASSWORD, ZIMBRA_IMAP_HOST, ZIMBRA_SMTP_HOST

# 1) Primero verificá que las credenciales/host andan, SIN pasar por MCP:
python scripts/check_connection.py

# 2) Si eso dio OK, probá el server MCP en modo stdio:
ZIMBRA_MCP_TRANSPORT=stdio python -m zimbra_mcp.server

Datos que necesitás para el .env

  • ZIMBRA_IMAP_HOST / puerto: normalmente mail.tudominio.com puerto 993 con SSL. Podés confirmarlo mirando la config de tu cliente actual (Thunderbird/Outlook: cuenta → configuración del servidor).

  • ZIMBRA_SMTP_HOST: casi siempre el mismo host, puerto 587 con STARTTLS (o 465 con SSL directo — ajustá ZIMBRA_SMTP_SSL/ZIMBRA_SMTP_STARTTLS).

  • ZIMBRA_USERNAME / ZIMBRA_PASSWORD: tu login normal. Si tu Zimbra soporta contraseñas de aplicación, mejor usar una en vez de tu password principal.

Correr con Docker

cp .env.example .env   # completar antes de levantar
docker compose up --build

Esto deja el server escuchando http://localhost:8000/mcp (streamable-http). El Dockerfile no pude probarlo en este sandbox porque no tenía acceso al demonio de Docker, pero es un build estándar (python:3.11-slim + pip install -e .) — corré docker compose up --build vos y avisame si algo rompe.

Nota de red: el contenedor tiene que poder llegar al host de Zimbra por IMAP(S)/SMTP(S)/LDAP. Si Zimbra solo es alcanzable dentro de tu VPN/red interna, corré el contenedor en una máquina que ya tenga esa conectividad (tu PC, o un VPS que ya esté en la VPN) — no en un entorno cloud aislado.

Integración con Claude Desktop / Cowork / ChatGPT

🔵 Claude Desktop — Opción A: Local sin Docker (recomendado para probar)

Paso 1: Ubicá el archivo de configuración de Claude Desktop según tu SO:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

  • Linux: ~/.config/Claude/claude_desktop_config.json

Si el archivo no existe, crealo en esa ubicación.

Paso 2: Editá el archivo y agregá la configuración del servidor Zimbra:

{
  "mcpServers": {
    "zimbra": {
      "command": "/ruta/absoluta/al/.venv/bin/python",
      "args": ["-m", "zimbra_mcp.server"],
      "env": {
        "ZIMBRA_MCP_TRANSPORT": "stdio",
        "ZIMBRA_USERNAME": "tu@email.com",
        "ZIMBRA_PASSWORD": "tu-contraseña",
        "ZIMBRA_IMAP_HOST": "mail.tudominio.com",
        "ZIMBRA_IMAP_PORT": "993",
        "ZIMBRA_SMTP_HOST": "mail.tudominio.com",
        "ZIMBRA_SMTP_PORT": "465",
        "ZIMBRA_AUTO_MARK_READ": "false",
        "ZIMBRA_AUTH_ENABLED": "false"
      },
      "cwd": "/ruta/absoluta/a/zimbra-mcp"
    }
  }
}

Ejemplo en Windows:

{
  "mcpServers": {
    "zimbra": {
      "command": "C:\\Users\\tuusuario\\Projects\\zimbra-mcp\\.venv\\Scripts\\python.exe",
      "args": ["-m", "zimbra_mcp.server"],
      "env": {
        "ZIMBRA_MCP_TRANSPORT": "stdio",
        "ZIMBRA_USERNAME": "dani@empresa.com",
        "ZIMBRA_PASSWORD": "MiPassword123",
        "ZIMBRA_IMAP_HOST": "mail.empresa.com",
        "ZIMBRA_IMAP_PORT": "993",
        "ZIMBRA_SMTP_HOST": "mail.empresa.com",
        "ZIMBRA_SMTP_PORT": "465"
      },
      "cwd": "C:\\Users\\tuusuario\\Projects\\zimbra-mcp"
    }
  }
}

Paso 3: Reiniciá Claude Desktop para cargar la configuración.

Paso 4: Abrí una conversación en Claude y escribí algo como:

Listá los correos en mi INBOX de Zimbra

Claude debería poder acceder a tus herramientas de Zimbra automáticamente.


🔵 Claude Desktop — Opción B: Docker con conexión remota

Paso 1: Asegurate que Docker está corriendo:

docker compose up -d

El servidor estará disponible en http://localhost:8000/mcp.

Paso 2: En Claude Desktop, usa la opción "Agregar conector remoto" (Remote Connector) o "Custom MCP Server":

  • URL del servidor: http://localhost:8000/mcp

  • Tipo de transporte: streamable-http (seleccionar automáticamente)

Paso 3: Si tu servidor tiene autenticación (ZIMBRA_AUTH_ENABLED=true):

Antes de usar cualquier herramienta, ejecutá primero:

get_access_token(api_key="tu-api-key-aqui")

Esto te dará un token JWT que será válido por 1 hora. Guardalo para referencia.


🟢 ChatGPT + OpenAI

⚠️ Nota importante: ChatGPT usa su propio sistema de "Custom GPT" y no soporta directamente MCP (Model Context Protocol). Sin embargo, tenés estas opciones:

Opción 1: Usar OpenAI API + MCP Server Bridge (avanzado)

Si querés que un Custom GPT acceda a Zimbra, necesitás crear un "bridge" que exponga el MCP como una API REST. Eso requiere:

  1. Un servidor FastAPI/Flask que envuelva las herramientas MCP

  2. Configurar una "Action" en tu Custom GPT apuntando a ese servidor

Ejemplo mínimo:

# bridge_server.py
from fastapi import FastAPI, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthCredentials
import sys
sys.path.insert(0, 'src')

from zimbra_mcp.server import create_server
from zimbra_mcp.config import load_settings

app = FastAPI()
security = HTTPBearer()

settings = load_settings()
mcp_server = create_server(settings)

@app.post("/api/search_messages")
async def search_emails(
    credentials: HTTPAuthCredentials,
    folder: str = "INBOX",
    query: str = None,
    limit: int = 10
):
    # Validar token si auth está habilitada
    if settings.auth_enabled:
        # Verificar token aquí
        pass
    
    # Llamar herramienta MCP
    results = mcp_server.search_messages(folder=folder, query=query, limit=limit)
    return {"emails": results}

# Más endpoints para get_message, send_email, etc.

Luego:

  1. Deployá este bridge en un servidor (Heroku, Replit, tu VPS, etc.)

  2. En Custom GPT → "Configure" → "Actions" → agrega tu servidor

  3. Define un OpenAPI schema para que el GPT sepa qué parámetros usar

Opción 2: Usar Cowork (recomendado para ChatGPT users)

Si querés usar Zimbra desde algo como ChatGPT, considerá Cowork (plataforma agnóstica de MCP):

  1. Instalar Cowork: https://cowork.anthropic.com

  2. Agregar el servidor Zimbra usando la misma config de Claude Desktop

  3. Usar Cowork con ChatGPT u otros modelos


Cuando lo llevés a la nube

Paso 1: Deployá el Docker en tu servidor (AWS, DigitalOcean, tu VPS, etc.):

# En tu servidor
git clone <repo>
cd zimbra-mcp
cp .env.example .env
# Completá el .env con tus credenciales
docker compose up -d

Paso 2: Exponé el servidor de forma segura:

  • Con HTTPS + Nginx reverse proxy (recomendado):

    server {
      listen 443 ssl;
      server_name zimbra-mcp.tudominio.com;
      
      location / {
        proxy_pass http://localhost:8000;
      }
    }
  • Con Cloudflare Tunnel (sin exponer IP pública):

    cloudflared tunnel run zimbra-mcp

Paso 3: En Claude Desktop, usá la URL remota:

{
  "mcpServers": {
    "zimbra": {
      "command": "python",
      "args": ["-m", "mcp.client.http", "https://zimbra-mcp.tudominio.com/mcp"],
      "env": {
        "ZIMBRA_AUTH_ENABLED": "true",
        "ZIMBRA_AUTH_API_KEY": "tu-api-key"
      }
    }
  }
}

Point importante: El servidor que corre en la nube necesita conectividad a tu Zimbra (IMAP/SMTP/LDAP). Si tu Zimbra está en una VPN privada:

  • Deployá el servidor en una máquina que ya tenga acceso (tu router, una Raspberry Pi en tu oficina)

  • O expone Zimbra con seguridad (firewall + certificados SSL)


📚 Ejemplos Detallados de Integración

Para instrucciones paso a paso con ejemplos específicos según tu SO y caso de uso, consultá:

INTEGRATION_EXAMPLES.md

Incluye:

  • ✅ Claude Desktop (Windows, macOS, Linux)

  • ✅ ChatGPT (con Bridge FastAPI)

  • ✅ Cowork (agnóstico a LLM)

  • ✅ AWS EC2, DigitalOcean, Fly.io

  • ✅ Troubleshooting común

Seguridad

  • .env nunca se commitea (está en .gitignore) ni se hornea en la imagen.

  • Las conexiones IMAP/SMTP son por TLS (SSL directo o STARTTLS según config).

  • delete_message por defecto NO borra permanente — mueve a Trash. Solo pasa a expunge real si vos (o el modelo, con tu confirmación explícita) pasás permanent=True.

  • Considerá usar una contraseña de aplicación en vez de tu password principal de Zimbra, si tu instalación lo soporta.

Autenticación (opcional)

Para proteger el servidor MCP con API keys y access tokens JWT:

  1. Generá una API key y JWT secret:

    python scripts/generate_auth_keys.py
  2. Completá tu .env:

    ZIMBRA_AUTH_ENABLED=true
    ZIMBRA_AUTH_API_KEYS=<tu-api-key>
    ZIMBRA_AUTH_JWT_SECRET=<tu-jwt-secret>
    ZIMBRA_AUTH_TOKEN_TTL=3600
  3. Antes de usar otras herramientas, obtené un access token:

    get_access_token(api_key="<tu-api-key>")
  4. El servidor devuelve un JWT válido por el tiempo especificado en ZIMBRA_AUTH_TOKEN_TTL.

Nota: En versiones futuras se agregará validación de tokens en cada request HTTP.

Estado / qué falta

  • ✅ IMAP: listar carpetas, buscar, leer, flags, mover, borrar, adjuntos

  • ✅ SMTP: enviar (texto/html, cc/bcc, adjuntos, threading headers)

  • ✅ LDAP: búsqueda GAL (sujeto a que tu Zimbra la exponga — ver aviso arriba)

  • ✅ Dockerfile + docker-compose

  • ⬜ CardDAV como alternativa a LDAP si el GAL no es alcanzable

  • ⬜ Paginación real en search_messages (hoy es un limit simple)

  • ⬜ Tests automatizados (por ahora: scripts/check_connection.py a mano)