MCP Emails

Servidor de correo alojado para Gmail, Fastmail, iCloud, Yahoo, Zoho, Yandex y cualquier buzón IMAP/SMTP: lee, busca, envía, organiza, redacta y programa correos desde cualquier cliente MCP, obtenidos en vivo y nunca almacenados. Documentación en https://mcpemails.com/docs

Documentación

MCPEmails

Dale a tu agente de IA una bandeja de entrada. Un servidor alojado de Model Context Protocol que permite a Claude, Cursor o cualquier cliente compatible con MCP leer, buscar, enviar, organizar y programar correos electrónicos a través de tus buzones existentes, sin almacenar tu correo.

Glama quality grade npm version MCP registry License: AGPL-3.0

Conecta un buzón una vez, pega una URL en tu agente y podrá trabajar tu bandeja de entrada en vivo. El correo se obtiene bajo demanda y nunca se retiene; las credenciales se cifran en reposo y solo se descifran en el momento de la llamada dentro de una función de borde aislada.

🔗 mcpemails.com · 📚 Docs · 💳 Precios


Contenido


Cómo funciona

  1. Conecta un buzón. Inicia sesión en mcpemails.com y conecta Outlook / Microsoft 365 (Iniciar sesión con Microsoft, a través de Microsoft Graph), Gmail (una contraseña de aplicación de Google por IMAP por defecto, o Iniciar sesión con Google), o cualquier cuenta IMAP/SMTP (contraseña de aplicación). Las credenciales se cifran con AES‑256‑GCM antes de tocar la base de datos.
  2. Obtén acceso. Los clientes compatibles con OAuth (claude.ai, Claude Desktop, Cursor) se conectan con un clic mediante OAuth 2.0 + PKCE. Todo lo demás usa una clave de API con ámbito (mcpe_…).
  3. Apunta tu cliente al servidor. El endpoint de MCP es una única URL:
    https://mcpemails.com/api/mcp
    
  4. Tu agente trabaja la bandeja de entrada. Llama a herramientas como inbox_list, email_read (action: "search"), email_compose (action: "send") y schedule (action: "create"). Cada solicitud obtiene datos en vivo de tu proveedor: nada se refleja ni se almacena en caché en el servidor.

Los permisos se limitan por clave, por lo que puedes dar a un agente solo read:email, o concederle envío y gestión de carpetas sin exponer nunca la eliminación.

Inicio rápido (conectar un agente)

Claude Desktop / Cursor (OAuth): añade un servidor MCP remoto apuntando a https://mcpemails.com/api/mcp y aprueba la pantalla de consentimiento. Elige los ámbitos que debe tener el agente.

Clave de API (cualquier cliente MCP): crea una clave en el panel, elige sus ámbitos y (opcionalmente) restringe a buzones específicos, luego envíala como token de portador:

// Example MCP client config
{
  "mcpServers": {
    "mcpemails": {
      "url": "https://mcpemails.com/api/mcp",
      "headers": { "Authorization": "Bearer mcpe_your_key_here" }
    }
  }
}

El protocolo es JSON‑RPC 2.0 sobre HTTP (MCP 2025-06-18, transporte Streamable). Inicia cada sesión con inbox_list: devuelve los buzones a los que la clave puede acceder, sus capacidades por proveedor y un perfil de compatibilidad versionado. El perfil marca las operaciones normalizadas como exact, different o unavailable, para que los agentes puedan preservar las diferencias del proveedor en lugar de debilitar silenciosamente una solicitud.

Guías de configuración

Instrucciones de copiar y pegar por cliente, incluido dónde guarda cada uno su archivo de configuración: mcpemails.com/docs/clients.

Claude · Claude Code · ChatGPT · Cursor · VS Code · Cline · Windsurf · Gemini CLI · Zed · JetBrains · Raycast · Warp · curl

Capacidades

  • En vivo, nunca almacenado — el correo se lee directamente de tu proveedor en cada llamada; no se persisten cuerpos de mensajes.
  • Multi‑proveedor — Outlook / Microsoft 365 a través de Microsoft Graph (Iniciar sesión con Microsoft), Gmail mediante contraseña de aplicación de Google o Iniciar sesión con Google, además de cualquier buzón IMAP/SMTP (Fastmail, iCloud, Yahoo, Zoho, Yandex, autoalojado…) con contraseña de aplicación.
  • Sin retransmisión — el correo saliente se envía a través del SMTP/API de tu proveedor, desde tu dirección real.
  • Ámbitos granulares — ocho ámbitos de permiso, otorgables de forma independiente por clave de API y por buzón.
  • Lote y buscar‑y‑actuar — lee, mueve, elimina o marca hasta cientos de mensajes en una sola llamada, incluidos combinadores de "buscar y luego mover/eliminar".
  • Borradores y programación — redacta borradores y pon mensajes en cola para envío futuro (despacho en el servidor).
  • Búsqueda independiente del proveedor — la sintaxis de Gmail, KQL de Microsoft Graph y SEARCH de IMAP se normalizan detrás de una interfaz email_read (action: "search").
  • Listo para equipos: espacios de trabajo, miembros, roles, SSO y un registro de auditoría en el plan Team.

Herramientas

17 herramientas que llamas directamente. La mayoría están orientadas a recursos y toman un argumento action que selecciona la operación específica (y, para acciones que necesitan privilegios diferentes, el ámbito requerido):

  • inbox_list - Lista los buzones a los que la clave puede acceder, con las capacidades del proveedor de cada uno.
  • email_read - Lista, lee y busca mensajes, en lotes, además de adjuntos, texto extraído de adjuntos y el .eml original.
  • email_organize - Mueve, copia, marca y archiva mensajes que nombras por id, individualmente o en lotes.
  • email_search_and_move - Mueve cada mensaje que coincida con una búsqueda a una carpeta. Es su propia herramienta, y la destructiva, porque un filtro incorrecto reubica una bandeja de entrada completa.
  • email_delete - Envía a la papelera o elimina permanentemente mensajes, individualmente, en lotes o por búsqueda.
  • email_compose - Envía, responde y reenvía a través de tu propio proveedor, desde tu dirección real.
  • folder_list - Lista carpetas (etiquetas en Gmail) con sus IDs nativos del proveedor y recuentos de mensajes. Solo lectura.
  • folder - Crea, renombra y elimina carpetas (etiquetas en Gmail).
  • draft_list - Lista los borradores guardados en la bandeja de entrada, con sus IDs de borrador. Solo lectura.
  • draft - Crea, actualiza, envía y elimina borradores, incluidas respuestas nativas del proveedor.
  • schedule_list - Lista lo que está en cola para entrega futura. Solo lectura.
  • schedule - Pone un mensaje en cola para entrega futura y cancela uno que esté en cola.
  • signature_get - Lee la firma y el nombre del remitente configurados para un buzón. Solo lectura.
  • signature_set - Establece la firma que se añade al correo saliente y el nombre del remitente.
  • automation_read - Lista reglas de triaje, lee una, muestra el historial de ejecución y hace una prueba en seco de un filtro. Solo lectura.
  • automation - Crea, actualiza, habilita, deshabilita y elimina reglas de triaje automáticas, sin modelo en el bucle.
  • contact_search - Busca contactos escaneando correo reciente en vivo, sin libreta de direcciones almacenada.
HerramientaAccionesÁmbito(s)
inbox_list(acción única)read:email
email_readlist, read, read_batch, search, attachment, extract, originalread:email (search también acepta search:email)
email_organizemove, move_batch, copy, copy_batch, flag, archivemanage:folders
email_search_and_move(acción única)manage:folders
email_deletedelete, delete_batch, search_and_deletedelete:email
email_composesend, reply, forwardsend:email
folder_list(acción única)read:email
foldercreate, rename, deletemanage:folders
draft_list(acción única)manage:drafts
draftcreate, reply, update, send, deletemanage:drafts (crear/responder/actualizar/eliminar), read:email (responder también), send:email (enviar)
schedule_list(acción única)schedule:email
schedulecreate, cancelschedule:email
signature_get(acción única)read:email
signature_set(acción única)send:email
automation_readlist, get, runs, previewmanage:automations
automationcreate, update, enable, disable, deletemanage:automations
contact_search(acción única)manage:contacts (también acepta read:email)

Una clave de ámbito completo ve 22 herramientas en tools/list: las 16 anteriores más seis herramientas solo de aplicación (approval_review, approval_decide, approval_update, approval_schedule, bulk_execute, bulk_cancel). Esas llevan _meta.ui.visibility: ["app"] y controlan la tarjeta de revisión que un cliente MCP muestra para un envío retenido o una operación masiva previsualizada, en lugar de componerse a mano.

Notas:

  • Las herramientas aceptan un inbox_id explícito (UUID) o una dirección de correo inbox; las claves de un solo buzón resuelven el destino automáticamente.
  • Las acciones por lotes tienen un límite de 50 (email_read's read_batch) a 500 (mover/eliminar/marcar) mensajes por llamada.
  • Para una mutación específica, primero usa email_read con action: "search", luego pasa el message_id o message_ids devuelto a email_organize o email_delete. Los campos de búsqueda solo los aceptan email_search_and_move y la acción search_and_delete de email_delete.
  • contact_search escanea correo reciente en vivo, por lo que no hay libreta de direcciones almacenada.
  • La acción original de email_read devuelve un mensaje MIME completo almacenado por el proveedor como archivo .eml portátil (hasta 25 MB). Es de solo lectura y nunca marca el mensaje como leído.
  • La acción send de draft requiere send:email, no manage:drafts, para que una clave que solo puede gestionar borradores no pueda usarlos para eludir el consentimiento de envío de correo.
  • La acción reply de draft crea una respuesta nativa del proveedor sin enviar en la conversación de origen. Necesita tanto manage:drafts como read:email, y por defecto responde solo al remitente.
  • Las mitades de solo lectura (folder_list, draft_list, schedule_list, signature_get, automation_read) se separaron de sus herramientas de escritura el 2026-09-09, para que una clave de solo lectura nunca vea una herramienta de escritura. Las formas combinadas antiguas (folder action: "list", draft action: "list", schedule action: "list", signature action: "get"/"set", automation action: "list"/"get"/"runs"/"preview") todavía se aceptan en el cable para clientes ya conectados, pero ya no se anuncian.
  • automation gestiona reglas de triaje programadas automáticas: una búsqueda almacenada más una acción fija, evaluadas en una cadencia sin modelo en el bucle. No hay acción de eliminar correo, un forward siempre espera aprobación humana, y draft_reply solo escribe un borrador. Ver docs/automations-trust-boundary.md.
  • tools/list solo devuelve las herramientas para las que tu clave (o token OAuth) tiene ámbito real.

Ámbitos de OAuth

AlcanceOtorga
read:emailListar bandejas de entrada y carpetas; listar, leer y buscar mensajes; leer la firma de una bandeja de entrada; buscar contactos
search:emailAlternativa más restringida que otorga solo la acción search de email_read
send:emailEnviar, responder y reenviar; establecer la firma y el nombre del remitente; también se requiere para enviar un borrador
manage:foldersCrear/renombrar/eliminar carpetas; mover, copiar, marcar y archivar mensajes
delete:emailMover a la papelera o eliminar permanentemente mensajes
manage:draftsCrear, editar y eliminar borradores (enviar uno también requiere send:email)
manage:contactsBúsqueda de contactos en vivo desde el correo reciente
schedule:emailPoner mensajes en cola para entrega futura
manage:automationsCrear y gestionar reglas de triaje programadas sin supervisión (sin acción de eliminación; los reenvíos permanecen sujetos a aprobación)

Proveedores compatibles

ProveedorConexión medianteLeer/BuscarEnviarCarpetasEliminación permanenteBorradores
Gmail / Google WorkspaceContraseña de aplicación (IMAP/SMTP) por defecto, u OAuth 2.0 (Iniciar sesión con Google)✅✅EtiquetasSolo papelera✅
FastmailContraseña de aplicación (IMAP/SMTP)✅✅✅✅✅
iCloud, Yahoo, AOL, GMX, Zoho, YandexContraseña de aplicación (IMAP/SMTP)✅✅✅✅✅
IONOS, STRATO, One.com, OVHcloud, Namecheap Private Email, Hostinger, Infomaniak, HetznerContraseña del buzón (IMAP/SMTP)✅✅✅✅✅
cPanel, Plesk, SiteGround, Bluehost y otros hosts compartidosContraseña del buzón (IMAP/SMTP)✅✅✅✅✅
Cualquier otro buzón IMAP/SMTPContraseña de aplicación o contraseña del buzón✅✅✅✅✅

El correo en tu propio dominio en un host web se conecta como cualquier buzón IMAP, y un espacio de trabajo puede contener varios de ellos (info@, sales@, support@). Configuración por host y problemas conocidos para 100 proveedores en mcpemails.com/connect. | Outlook / Microsoft 365 | OAuth 2.0 (Microsoft Graph) | ✅ | ✅ | ✅ (anidadas) | ✅ | ✅ |

Outlook usa Microsoft Graph con "Iniciar sesión con Microsoft", no IMAP. Las cuentas personales de Microsoft (outlook.com, hotmail.com, live.com, msn.com) se conectan directamente. En inquilinos de Microsoft 365 de trabajo o escuela, la política de consentimiento predeterminada de Microsoft impide que los empleados aprueben permisos de correo por sí mismos, por lo que un administrador de TI aprueba la aplicación una vez para la organización; el panel le da al usuario un enlace de aprobación compartible para enviarles (/auth/outlook/admin-consent), y el administrador no necesita una cuenta de MCP Emails. Una cuenta de Microsoft sin buzón de Exchange Online es rechazada, con una indicación hacia IMAP. Las herramientas de etiquetas son solo de Gmail (Outlook usa carpetas), excepto que la acción de etiqueta de una automatización aplica una categoría de Outlook; y Graph no puede combinar una búsqueda de texto con los filtros de no leído, adjunto, marcado o fecha.

Precios

La métrica de valor son buzones conectados. Gratis conecta un buzón, Personal conecta hasta tres, Pro conecta todos los buzones que poseas, y Team añade personas, roles y un espacio de trabajo separado por cliente. La facturación anual ahorra alrededor del 20%.

GratisPersonalProTeam
Precio$0$9/mes · $86.40/año ($7.20/mes)$15/mes · $144/año ($12/mes)$79/mes · $756/año ($63/mes)
Buzones conectados13IlimitadosIlimitados
Acciones de correo / mes150 (los primeros 7 días no se cuentan)Sin límite mensual (uso justo)Sin límite mensual (uso justo)Sin límite mensual (uso justo)
Claves APIIlimitadasIlimitadasIlimitadasIlimitadas
Miembros1 (solo propietario)1 (solo propietario)1 (solo propietario)Ilimitados, con roles
Límite de tasa de uso justo60 req/min120 req/min300 req/min1,000 req/min
Roles y espacios de trabajo de equipoNoNoNo✅
SSO (SAML/OIDC) + registro de auditoríaNoNoNo✅
SoporteComunidadCorreo electrónicoCorreo electrónicoPrioritario

También se aplican límites por clave API (100 req/min · 1,000/hora · 10,000/día). Los límites de tasa se pueden reintentar: regresan como error JSON-RPC -32003 con data.retry_after en segundos.

Los espacios de trabajo gratuitos obtienen 150 acciones de correo por mes calendario (UTC). Los primeros 7 días después del registro no se cuentan, y inbox_list y el panel nunca se cuentan. Cuando se alcanza la asignación, cada otra acción de correo es rechazada hasta el día 1 del mes siguiente, las automatizaciones sin supervisión se pausan y reanudan automáticamente el día 1, y el propietario recibe un correo al 80% y al 100%. Personal, Pro y Team no tienen límite mensual, sujeto a uso justo (sus techos son protecciones contra abuso, no características del plan, y no se imprimen en ningún lugar). Un rechazo no se puede reintentar y no es un error JSON-RPC: regresa como un resultado de herramienta normal con isError: true, texto que comienza con el conteo y la fecha de reinicio, y un bloque _meta["com.mcpemails/usage_limit"] que se limpia en reset_at.

Los ids internos de planes preceden a los nombres: solo se vende como Pro y pro se vende como Team. El id más nuevo personal es el único que coincide con su nombre mostrado, Personal. Cada usuario que existía antes del reajuste de precios del 2026-08-19 mantiene buzones ilimitados gratis, permanentemente, y cada espacio de trabajo creado antes del lanzamiento de la asignación de acciones del 2026-09-12 es un miembro temprano que no se mide contra ella. Ver apps/web/src/lib/stripe/plans.ts.

Arquitectura

flowchart LR
    Agent["MCP client<br/>(Claude, Cursor, …)"] -->|"JSON-RPC / OAuth or API key"| Web

    subgraph Vercel["Vercel — Next.js 16"]
      Web["/api/mcp route<br/>+ marketing site + dashboard"]
    end

    subgraph Supabase
      Edge["mcp-server<br/>edge function (Deno)"]
      DB[("Postgres<br/>RLS + encrypted creds")]
      Cron["token-refresh<br/>edge functions"]
    end

    Web -->|proxies| Edge
    Edge -->|decrypt creds, fetch live| Providers["Email providers<br/>Gmail API · Microsoft Graph · IMAP/SMTP"]
    Edge --> DB
    Cron --> DB
    Web --> Stripe[("Stripe<br/>billing")]
  • /api/mcp es un manejador de rutas delgado de Next.js que actúa como proxy a la función edge de Supabase mcp-server — la implementación real de MCP, donde se descifran las credenciales y se realizan las llamadas al proveedor.
  • La base de datos Postgres almacena espacios de trabajo, miembros, buzones (tokens/contraseñas cifrados), claves API con hash, clientes OAuth, envíos programados y un registro de actividad — todo protegido por Seguridad a Nivel de Fila.
  • Funciones edge cron actualizan los tokens OAuth de Gmail/Outlook antes de que expiren.

Stack: Next.js 16 (App Router) · React 19 · next‑intl 4 · Supabase (Auth, Postgres, Edge Functions) · Stripe · Resend · TypeScript. Análisis/saneamiento de correo mediante mailparser, jsdom y isomorphic-dompurify.

Estructura del repositorio

.
├── apps/
│   └── web/                     # Next.js 16 app (marketing, dashboard, /api/mcp proxy)
│       ├── app/                 # App Router routes ([locale], dashboard, api, auth)
│       ├── components/          # marketing/ + dashboard/ React components
│       ├── messages/            # next-intl translations (en, nb, es, fr, zh)
│       ├── src/lib/             # stripe/, supabase/, blog/, crypto helpers
│       └── proxy.ts             # middleware: i18n + Supabase session + CDN cache
├── supabase/
│   ├── functions/
│   │   ├── mcp-server/          # the MCP server (tools, auth, scopes)
│   │   ├── gmail-token-refresh/
│   │   └── outlook-token-refresh/
│   └── migrations/              # SQL migrations (schema + RLS)
└── package.json                 # npm workspaces (apps/*)

Desarrollo local

Requisitos previos: Node.js 20+, npm y la CLI de Supabase (para migraciones y funciones edge).

# 1. Install (npm workspaces — run from the repo root)
npm install

# 2. Configure environment
cp .env.example apps/web/.env.local
#   then fill in the values (see below) and generate the two secrets:
openssl rand -hex 32   # ENCRYPTION_KEY
openssl rand -hex 32   # CSRF_SECRET

# 3. Run the web app (http://localhost:3000)
npm run dev

# 4. Production build
npm run build

next.config.js valida las variables de entorno requeridas en compilación/inicio y rechaza valores débiles de ENCRYPTION_KEY, por lo que un entorno mal configurado falla rápidamente en lugar de en tiempo de ejecución.

Variables de entorno

Copia .env.example y completa con valores reales. Requeridas en todos los entornos:

VariablePropósito
NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEYCliente de Supabase (público)
SUPABASE_SERVICE_ROLE_KEYClave de administración del lado del servidor (omite RLS) — secreto
NEXT_PUBLIC_APP_URLURL base canónica; impulsa las URI de redirección OAuth
GOOGLE_SITE_VERIFICATION (opcional)Token de verificación de etiqueta HTML de Google Search Console; configurar solo en producción
ENCRYPTION_KEYClave AES‑256‑GCM de 64 hex para credenciales en reposo — secreto
CSRF_SECRETClave HMAC de 64 hex para tokens CSRF (distinta de la anterior) — secreto

Dependientes de funciones:

Variable(s)Necesaria para
GMAIL_CLIENT_ID / GMAIL_CLIENT_SECRETOAuth de Gmail (gmail.readonly, gmail.send, gmail.modify)
OUTLOOK_CLIENT_ID / OUTLOOK_CLIENT_SECRET / OUTLOOK_TENANT_IDOAuth de Outlook (Mail.ReadWrite, Mail.Send, offline_access, openid, profile, email). OUTLOOK_TENANT_ID es opcional y por defecto es common
NEXT_PUBLIC_OAUTH_VERIFICATION_PENDINGMuestra la advertencia de aplicación no verificada hasta que se complete la verificación de Google (el editor de Microsoft ya está verificado)
STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET / NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYFacturación
STRIPE_PRICE_PERSONAL_MONTHLY / _YEARLY, STRIPE_PRICE_SOLO_MONTHLY / _YEARLY, STRIPE_PRICE_PRO_MONTHLY / _YEARLYIDs de precios de planes (personal = Personal, solo = Pro, pro = Team)
STRIPE_WEBHOOK_PROXY_KEYOpcional. Restringe /api/stripe/webhook a la cola de entrega delante de él. Sin configurar = sin restricción. Configúralo SOLO DESPUÉS de que la cola esté enviando la clave, o cada entrega fallará con 401 y se enviará a la cola de mensajes muertos.
STRIPE_WEBHOOK_TOLERANCE_SECONDSOpcional. Límite de antigüedad de firma de Stripe, por defecto 7 días. Amplio porque una reproducción en cola lleva su firma original; el valor predeterminado de 300s de Stripe rechazaría cada reintento retenido.

Fastmail y otros proveedores IMAP se conectan mediante contraseña de aplicación y no necesitan credenciales OAuth.

Los webhooks de Stripe se entregan a través de una cola. Stripe publica en el ingreso de Queuey, que reenvía a /api/stripe/webhook. Dos configuraciones en esa cola son críticas: la carga útil debe ser paso directo sin procesar (la firma es sobre bytes exactos), y un encabezado mapeado debe reenviar header:Stripe-Signature. Sin el encabezado mapeado, cada entrega falla con Missing stripe-signature header.. Ten en cuenta que STRIPE_WEBHOOK_SECRET debe ser el secreto de firma del endpoint de Stripe apuntado al ingreso, no de cualquier endpoint directo anterior.

Base de datos y migraciones

El esquema y las políticas de Seguridad a Nivel de Fila viven en supabase/migrations/. Tablas principales: workspaces, workspace_members, inboxes (credenciales cifradas, con borrado suave), api_keys (con hash, con alcance, restringido a buzón), oauth_clients, scheduled_sends, workspace_invites y un activity_log particionado por mes.

# Apply one migration to the linked project, then record it in the history
npx supabase db query --linked -f supabase/migrations/<file>.sql
npx supabase migration repair --status applied <version> --linked

# Regenerate TypeScript types from the live schema
npm run gen:types

La CLI de Supabase es la fuente de verdad para cambios de base de datos en este proyecto.

apps/web/src/types/database.types.ts es GENERADO

Está escrito en su totalidad por npm run gen:types (supabase gen types typescript --linked), que lee el proyecto vinculado en vivo, no los archivos de migración. No lo edites a mano: una columna añadida manualmente se elimina silenciosamente en la siguiente regeneración, y una columna añadida manualmente que nunca existió en la base de datos compila limpiamente y falla con 500 en producción. Regenera en el mismo cambio que aplica una migración, y confirma el resultado.

Las tablas, vistas y funciones RPC están todas cubiertas, y cada cliente de Supabase declarado en .ts/.tsx de apps/web (que es todo el programa verificado por tipos) es SupabaseClient<Database>, por lo que .from(), .select(), .insert() y .rpc() están verificados por tipos contra el esquema real. Si una tabla o columna parece faltante, la solución es npm run gen:types, nunca un as any local en el cliente de Supabase. Los casts que permanecen son para cosas que el generador genuinamente no puede expresar: formas de carga útil jsonb, argumentos de función anulables y un helper que despacha muchos RPC a través de una sola firma. Cada uno de esos lleva un comentario que lo dice.

El calificador .ts/.tsx es crítico. apps/web/tsconfig.json no establece checkJs y su include es **/*.ts y **/*.tsx, por lo que un archivo .js como app/dashboard/[[...section]]/page.js está completamente fuera del programa: sus tipos JSDoc @param son documentación y nada los verifica. Están escritos como SchemaTypedClient (un @typedef para SupabaseClient<Database>) para que la documentación al menos coincida con lo que los llamadores pasan, pero mantenerlo honesto es un trabajo manual.

Nunca escribas un SupabaseClient desnudo. Sin argumento de tipo se resuelve a SupabaseClient<any, "public", any>, que es un as any que ningún grep de as any encontrará: una función declarada db: SupabaseClient no obtiene verificación de columnas en absoluto, y una columna inexistente en un .insert() compila limpiamente. SupabaseClient<any> es el mismo agujero dicho en voz alta, y también lo son SupabaseClient<any | Database> y SupabaseClient<Alias> donde el alias es any. apps/web/eslint.config.mjs por lo tanto no busca any; requiere Database, y npm run lint da error en cualquier referencia de tipo SupabaseClient que no lo lleve, más un createServerClient(...) / createBrowserClient(...) sin parametrizar. Esos son selectores sintácticos (el repositorio no ejecuta linting consciente de tipos), por lo que coinciden con la ortografía en el sitio de uso y tres cosas podrían pasarlos por alto: import { SupabaseClient as SB }, import * as Supa y luego Supa.SupabaseClient, y const mk = createServerClient; mk(...). Ningún selector puede ver a través de ninguno de esos, por lo que la configuración los cierra un nivel más arriba: renombrar la importación SupabaseClient e importar el espacio de nombres @supabase/ssr o @supabase/supabase-js son en sí mismos errores, y no-restricted-imports mantiene createClient / createServerClient / createBrowserClient fuera de cada archivo excepto los envoltorios en src/lib/supabase/, que son el único lugar que construye un cliente y siempre pasa <Database>. Todo lo demás importa esos envoltorios.

Las reglas no están limitadas a **/*.ts(x), por lo que las restricciones de importación y llamada también se aplican en .js/.jsx/.mjs. Lo que no pueden hacer allí es leer un tipo JSDoc: un selector sintáctico no ve ningún nodo AST para él. Ese es el límite conocido mencionado anteriormente, no una brecha que las reglas pretendan cubrir.

Dos cosas que un tsc verde aún no te dice:

  • --linked lee producción, no supabase/migrations/. Lo que el proyecto en vivo realmente tiene es lo que llega al archivo, incluida la deriva, y una migración que existe localmente pero no se ha enviado es invisible para él. Regenerar requiere credenciales para el proyecto vinculado, por lo que CI no puede reproducir este archivo solo desde el repositorio. Verifica supabase migration list --linked antes de creer que los tipos describen lo que dicen las migraciones. A partir de 2026-09-16 ese comando reporta ocho desajustes en ambas direcciones.
  • Un cast aún desactiva la verificación. (row as any).some_column y client as unknown as SupabaseClient<Database> ambos compilan lo que escribas. Las reglas de lint anteriores detectan la declaración del cliente, no un cliente que se convierte a any en el sitio de llamada; @typescript-eslint/no-explicit-any es lo que detecta esos, y un eslint-disable en él es una elección deliberada que debería explicar por qué.

Despliegue

Aplicación web → Vercel (proyecto mcp-emails-web):

vercel --prod --yes

Los encabezados de seguridad y los tiempos de espera de funciones están definidos en vercel.json. Las rutas de marketing se sirven con un Cache-Control cacheable por CDN (establecido en proxy.ts) para que los rastreadores y visitantes recurrentes lleguen a la caché perimetral; el panel, la autenticación y las rutas API permanecen no-store.

Servidor MCP → función perimetral de Supabase:

npx supabase functions deploy mcp-server --project-ref <your-project-ref> --no-verify-jwt

Migraciones primero, función después. PostgREST no devuelve undefined para una columna que no conoce — da error — y la proyección de bandeja de entrada compartida del servidor (INBOX_SELECT_COLUMNS) es utilizada por cada herramienta de correo, que todas leen un error de consulta como "bandeja de entrada no encontrada". Desplegar la función antes de su migración puede, por lo tanto, derribar toda la superficie de correo, no solo la función que quería la nueva columna. Las columnas de bandeja de entrada recién migradas se leen deliberadamente en sus propias consultas pequeñas (readSendReviewMode, readBulkReviewMode, readInboxDraftEditorHidden) para que un despliegue fuera de orden degrade esa única función en lugar de romper todo — eso es una red de seguridad, no una licencia para saltarse el orden.

Autoalojamiento

¿No quieres confiar tu correo al servicio alojado? Ejecuta el mismo servidor MCP en tu propia máquina. self-host/ incluye una pila contenerizada (Postgres + PostgREST + el servidor Deno, sin Supabase/Stripe/panel), por lo que tus credenciales se cifran con una clave que solo tú tienes y se descifran solo dentro de tu propio contenedor.

cd self-host
make setup      # generate secrets (.env)
make up         # build + start the stack
export IMAP_PASSWORD='your-app-password'
make provision EMAIL=you@example.com IMAP_HOST=imap.fastmail.com SMTP_HOST=smtp.fastmail.com SERVICE=fastmail
make key NAME="my agent"   # mint an mcpe_ key, then point your client at http://localhost:8787

Es primero IMAP/SMTP (Fastmail, iCloud, Yahoo, Zoho, Yandex, genérico) mediante contraseña de aplicación; OAuth de Gmail/Outlook y el panel web siguen siendo solo alojados (Outlook también requeriría tu propio registro de aplicación de Microsoft Entra). El contenedor ejecuta supabase/functions/mcp-server/ sin modificar; consulta self-host/README.md para la guía completa.

Internacionalización

Construido con next‑intl (localePrefix: 'as-needed', localeDetection: false para URLs canónicas estables). El inglés se sirve en /; otros idiomas llevan un prefijo (/nb, /es, /fr, /zh). Las traducciones viven en apps/web/messages/.

Idiomas admitidos: Inglés, Noruego Bokmål, Español, Francés, Chino (Simplificado).

Modelo de seguridad

  • Credenciales cifradas en reposo con AES‑256‑GCM; descifradas solo dentro de la función perimetral en el momento de la llamada.
  • Sin almacenamiento de mensajes — los cuerpos de correo y los adjuntos se obtienen en vivo y nunca se persisten. La extracción de texto de adjuntos se ejecuta de forma transitoria en la solicitud y no devuelve bytes de adjuntos sin procesar.
  • Las claves API están hasheadas (solo se almacena un prefijo para mostrar) y se limitan por permiso y por bandeja de entrada, con caducidad opcional.
  • OAuth 2.0 + PKCE para autorización de clientes; Registro Dinámico de Clientes (RFC 7591) para clientes MCP.
  • Seguridad a nivel de fila aísla los datos de cada espacio de trabajo en la capa de base de datos.
  • CSP estricto, HSTS, X-Frame-Options: DENY y encabezados relacionados en cada respuesta.

Licencia

MCP Emails es de código abierto bajo la GNU Affero General Public License v3.0 (AGPL‑3.0). El servicio alojado en mcpemails.com ejecuta el mismo servidor que puedes autoalojar, para que puedas leer el código, verificarlo y ejecutarlo tú mismo. Consulta /security para el modelo de confianza.


Envía y recibe correo desde cualquier agente. © MCPEmails, AGPL‑3.0.