zimbra-mcp
by dnlbertoni
README.md
# 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](QUICKSTART.md) (5 minutos)
**¿Querés ejemplos detallados?** → Ver [INTEGRATION_EXAMPLES.md](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](INSTALL_CLAUDE_DESKTOP.md)** | 🎯 Instalar en Claude Desktop (método actual con `.mcpb`) |
| **[QUICKSTART.md](QUICKSTART.md)** | ⚡ Setup alternativo (Docker, venv local) |
| **[INTEGRATION_EXAMPLES.md](INTEGRATION_EXAMPLES.md)** | 📖 Ejemplos para ChatGPT, AWS, DigitalOcean, Fly.io |
| **[REFERENCE.md](REFERENCE.md)** | 📋 Tabla de herramientas, variables, configuración |
| **[README.md](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)
```bash
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
```bash
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:
```json
{
"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:**
```json
{
"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:
```bash
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:
```python
# 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.):
```bash
# 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):
```nginx
server {
listen 443 ssl;
server_name zimbra-mcp.tudominio.com;
location / {
proxy_pass http://localhost:8000;
}
}
```
- **Con Cloudflare Tunnel** (sin exponer IP pública):
```bash
cloudflared tunnel run zimbra-mcp
```
**Paso 3:** En Claude Desktop, usá la URL remota:
```json
{
"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](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:
```bash
python scripts/generate_auth_keys.py
```
2. Completá tu `.env`:
```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)
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues