Skip to main content
Glama
DerechoVirtual

outlook-mcp

README.md
# outlook-mcp · MCP de Outlook / Microsoft 365 para Claude

Servidor **MCP (Model Context Protocol)** que da a un agente (Claude Desktop, Claude Code,
Cowork…) **control completo sobre el correo de una cuenta de Outlook.com, Hotmail, Live o
Microsoft 365 / Office 365**: leer, buscar, ver conversaciones, descargar adjuntos, crear
carpetas y borradores, mover, archivar, enviar, responder y reenviar.

Usa la API oficial **Microsoft Graph** con OAuth2 — no IMAP, porque Microsoft desactivó la
autenticación básica tanto en Exchange Online como en Outlook.com.

> 🔒 **Sin credenciales en el repositorio.** Todo se configura por variables de entorno.
> La sesión se crea con `python authorize.py` y se guarda en `token.json`, que está en
> `.gitignore`. Aquí no hay ningún secreto.

---

## 🧰 Herramientas (18)

**Lectura (siempre disponibles)**
| Tool | Qué hace |
|---|---|
| `outlook_estado` | Estado de la cuenta: usuario, candados y carpetas con nº de mensajes/no leídos |
| `outlook_listar_carpetas` | Todas las carpetas y subcarpetas, con su id |
| `outlook_listar` | Lista los mensajes más recientes de una carpeta (paginado, no marca leído) |
| `outlook_buscar` | Busca por remitente, destinatario, asunto, texto, fechas, no leídos, con adjuntos |
| `outlook_buscar_kql` | Busca con la **sintaxis KQL** de Outlook (`from:`, `hasAttachment:true`, `received>=…`, AND/OR/NOT) |
| `outlook_leer` | Lee un mensaje completo (cabeceras, cuerpo en texto, adjuntos) |
| `outlook_conversacion` | Muestra el hilo entero al que pertenece un mensaje |
| `outlook_descargar_adjunto` | Descarga un adjunto (base64 o a disco) |

**Escritura reversible (siempre disponibles)**
| Tool | Qué hace |
|---|---|
| `outlook_marcar_leido` | Marca leído / no leído |
| `outlook_destacar` | Marca para seguimiento (bandera) / quita la marca |
| `outlook_crear_carpeta` | Crea una carpeta (o subcarpeta) |
| `outlook_guardar_borrador` | Guarda un borrador en Borradores (no envía) |

**Mover / archivar / eliminados** — requieren `OUTLOOK_ALLOW_MODIFY=1`
| Tool | Qué hace |
|---|---|
| `outlook_mover` | Mueve un mensaje a otra carpeta |
| `outlook_archivar` | Mueve el mensaje a la carpeta Archivo (reversible) |
| `outlook_eliminar` | Envía a **Elementos eliminados** (nunca borra permanente; recuperable) |

**Envío** — requieren `OUTLOOK_ALLOW_SEND=1`
| Tool | Qué hace |
|---|---|
| `outlook_enviar` | Envía un correo nuevo (con adjuntos opcionales) |
| `outlook_responder` | Responde al remitente o a todos (mantiene el hilo) |
| `outlook_reenviar` | Reenvía un mensaje con sus adjuntos |

---

## 🔒 Seguridad

- **Candados por variable de entorno, apagados por defecto**: enviar (`OUTLOOK_ALLOW_SEND`) y
  mover/archivar/eliminar (`OUTLOOK_ALLOW_MODIFY`). Con ellos apagados, esas tools devuelven un
  error claro y no hacen nada.
- **Leer nunca marca como leído** (Graph no altera `isRead` al leer un mensaje).
- **No existe borrado permanente**: no hay ninguna tool que haga `DELETE` en Graph;
  «eliminar» mueve a Elementos eliminados, recuperable.
- El token (`token.json`) y el `.env` están en `.gitignore` y **no se suben**.

---

## ⚙️ Instalación

### 1) Requisitos
- Python 3.9+
- `pip install -r requirements.txt` (solo el SDK `mcp`; el resto es librería estándar)

### 2) Iniciar sesión (una vez, 1 minuto) — sin registrar nada en Azure
```bash
python authorize.py       # muestra un código -> microsoft.com/devicelogin
```
Por defecto usa el cliente público de Microsoft **«Microsoft Graph Command Line Tools»**, así que
**no hay que registrar ninguna aplicación**: abres el enlace, pegas el código, inicias sesión con
tu cuenta de Outlook/Microsoft 365 y ya está. `authorize.py` guarda `token.json` y a partir de ahí
el servidor **refresca el token solo**.

<details>
<summary>Opcional: usar una aplicación propia de Entra ID</summary>

1. **https://entra.microsoft.com** → *Aplicaciones* → **Registros de aplicaciones** → **Nuevo registro**.
2. Nombre: `outlook-mcp`. Tipos de cuenta: **«Cuentas en cualquier directorio organizativo y
   cuentas personales de Microsoft»** (o solo personales, según tu caso).
3. Copia el **Id. de aplicación (cliente)** → `OUTLOOK_CLIENT_ID`.
4. **Autenticación** → *Configuración avanzada* → **«Permitir flujos de cliente público» = Sí**.
5. (Opcional) **Permisos de API** → *Microsoft Graph* → *Delegados*: `Mail.ReadWrite`,
   `Mail.Send`, `User.Read`, `offline_access`.
</details>

### 3) Configuración
```bash
cp .env.example .env      # candados y, si quieres, tu propia app o ruta del token
```

### 4a) Registrar en Claude Desktop
En `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "outlook": {
      "command": "python",
      "args": ["C:/ruta/a/outlook-mcp/server.py"],
      "env": {
        "PYTHONUTF8": "1",
        "OUTLOOK_TENANT": "common",
        "OUTLOOK_TOKEN_PATH": "C:/ruta/a/outlook-mcp/token.json",
        "OUTLOOK_ALLOW_SEND": "0",
        "OUTLOOK_ALLOW_MODIFY": "0"
      }
    }
  }
}
```
Reinicia Claude Desktop después de editarlo.

### 4b) Instalar en Cowork / Claude Code por URL (como plugin)
Este repo incluye `.claude-plugin/marketplace.json`:
1. **Directorio → Plugins → Añadir marketplace** → pega la URL de este repositorio → **Sincronizar**.
2. **Instala** el plugin `outlook`.
3. Configura las variables de entorno en el cliente y ejecuta `python authorize.py` una vez.

---

## 🧪 Validación

```bash
python test_offline.py    # sin credenciales: no necesita cuenta ni red
python test_gate.py       # contra la cuenta real (solo lectura)
```

- `test_offline.py` comprueba, con la red simulada, que cada tool construye la llamada correcta a
  Graph: que **ninguna hace `DELETE`**, que «eliminar» y «archivar» son movimientos de carpeta, el
  mapeo de nombres de carpeta (`papelera` → `deleteditems`…), la construcción de KQL, los
  destinatarios, el HTML→texto y los adjuntos.
- `test_gate.py` descubre todas las tools por el protocolo MCP, prueba las de lectura contra la
  cuenta real, comprueba que los candados bloquean envío y eliminación, y hace el handshake por
  stdio. **No envía nada a terceros ni borra ningún correo.**

---

## 💡 Ejemplos de uso

- «¿Qué me ha llegado hoy sin leer?» → `outlook_listar` / `outlook_buscar`
- «Busca los correos del cliente X con adjunto desde junio» →
  `outlook_buscar_kql("from:X hasAttachment:true received>=2026-06-01")`
- «Enséñame el hilo completo de esta reclamación» → `outlook_conversacion`
- «Guárdame el PDF del último correo» → `outlook_descargar_adjunto`
- «Prepárame un borrador de respuesta» → `outlook_guardar_borrador`

---

## ❓ Problemas frecuentes

| Síntoma | Causa / solución |
|---|---|
| `No hay sesion de Outlook` | Ejecuta `python authorize.py` una vez |
| `AADSTS7000218` o *client_assertion* | Falta **«Permitir flujos de cliente público» = Sí** en Autenticación |
| `AADSTS50194` / cuenta no admitida | El registro no admite cuentas personales: cámbialo a multiinquilino + personales, o usa `OUTLOOK_TENANT=consumers` |
| `Graph 403` al enviar | Falta el permiso `Mail.Send` o el candado `OUTLOOK_ALLOW_SEND=1` |
| Token caducado tras meses sin uso | Vuelve a ejecutar `python authorize.py` |

---

*Genérico y sin datos personales en el código. Configúralo con tu propia cuenta.*