Queríamos conectar nuestro servidor MCP de n8n a ChatGPT y nos encontramos con un muro: n8n solo sabe autenticar con un token estático, y ChatGPT solo acepta OAuth. En este artículo te contamos cómo lo resolvimos, por qué la solución que parecía obvia no servía, y los cuatro fallos silenciosos que nos costaron horas de depuración. Si estás intentando lo mismo, esto te ahorrará la tarde que nosotros perdimos.
El punto de partida: un MCP que ya funcionaba
Teníamos un servidor MCP montado en n8n con el nodo MCP Server Trigger, exponiendo herramientas de solo lectura sobre nuestra operativa interna. Funcionaba perfectamente con Claude: autenticación mediante Bearer token, el mismo token configurado en el cliente, y listo.
El siguiente paso parecía trivial: hacer lo mismo con ChatGPT.
El muro: ChatGPT no acepta tokens estáticos
Al crear una app MCP personalizada, ChatGPT ofrece tres opciones de autenticación: OAuth, ninguna o mixta. En ninguna de ellas puedes pegar un Bearer token estático.
Y del otro lado, el MCP Server Trigger de n8n (versión 2, en n8n 2.17) solo soporta tres modos:
none— sin autenticaciónbearerAuth— token estáticoheaderAuth— cabecera personalizada
No hay OAuth. Y las dos listas no se cruzan en ningún punto útil.
La tentación evidente es seleccionar “ninguna” en ChatGPT y dejar el endpoint abierto. No lo hagas: eso publica tus datos internos en una URL accesible por cualquiera que la conozca. La seguridad por oscuridad de una URL larga no es seguridad, y los endpoints acaban apareciendo en logs, historiales y capturas de pantalla.
La pista falsa: n8n sí tiene un servidor OAuth
Aquí es donde perdimos el primer rato. Investigando, descubrimos que n8n expone un servidor de autorización OAuth 2.1 completo:
GET /.well-known/oauth-authorization-server
{
"issuer": "https://tu-n8n.example.com",
"authorization_endpoint": ".../mcp-oauth/authorize",
"token_endpoint": ".../mcp-oauth/token",
"registration_endpoint": ".../mcp-oauth/register",
"code_challenge_methods_supported": ["S256"],
"scopes_supported": ["tool:listWorkflows", "tool:getWorkflowDetails"]
}
Tiene todo lo que ChatGPT necesita: registro dinámico de clientes (RFC 7591), PKCE con S256, refresh tokens. Parecía resuelto.
No lo estaba. Ese servidor OAuth está cableado exclusivamente al MCP de instancia de n8n, en /mcp-server/http. No protege los endpoints /mcp/<ruta> que crean tus workflows. Se comprueba fácil:
# El MCP de instancia: protegido por OAuth, lo anuncia correctamente
curl -i -X POST https://tu-n8n.example.com/mcp-server/http
→ 401 www-authenticate: Bearer realm="n8n MCP Server"
# Tu MCP de workflow: ni siquiera anuncia un flujo OAuth
curl -i -X POST https://tu-n8n.example.com/mcp/tu-ruta
→ 403 (sin cabecera www-authenticate)
Y los metadatos del recurso protegido lo confirman: /.well-known/oauth-protected-resource/mcp-server/http devuelve JSON válido, mientras que la ruta equivalente para tu workflow devuelve el HTML del panel de n8n. Es decir, no existe.
¿Y usar directamente el MCP de instancia?
Fue nuestra siguiente idea: si ese endpoint ya habla OAuth, apuntemos ChatGPT ahí. Lo descartamos rápido, y conviene que sepas por qué antes de intentarlo.
El MCP de instancia de n8n publica alrededor de 25 herramientas, de las cuales unas 13 son de escritura: crear workflows, actualizarlos, archivarlos, ejecutarlos, y operaciones sobre data tables. No es un catálogo que puedas recortar: los scopes anunciados son solo dos, ambos de lectura, y no gobiernan el resto de herramientas. No existe un scope que conceder o retener para “solo lectura”.
La alternativa sería limitar por permisos de usuario, pero ahí topas con dos cosas: el catálogo de herramientas que ve el cliente es estático (las verá aunque fallen al ejecutarse), y la herramienta de creación de workflows opera por defecto sobre el proyecto personal del usuario, donde cualquier miembro tiene permisos completos. Aislarlo de verdad requiere la funcionalidad de Projects con control de acceso por roles, que no está disponible en todas las licencias.
Resumiendo: no podíamos garantizar que ChatGPT no tuviera capacidad de escritura sobre la instancia. Descartado.
La solución: una pasarela OAuth delante
Si n8n no puede hablar OAuth y ChatGPT no puede hablar Bearer, hace falta un traductor en medio. La arquitectura queda así:
ChatGPT ──OAuth 2.1 (DCR + PKCE)──▶ pasarela
│ inyecta el Bearer aquí,
│ del lado del servidor
▼
n8n /mcp/tu-ruta
▼
tus subworkflows
La pasarela hace dos papeles a la vez: es Authorization Server (autentica a la persona y emite sus propios tokens) y Resource Server (valida esos tokens antes de dejar pasar nada). Cuando la petición está autorizada, la reenvía a n8n añadiendo el Bearer token del lado del servidor.
La propiedad importante: el token de n8n nunca sale de tu servidor. ChatGPT nunca lo ve, ni lo almacena, ni puede filtrarlo.
Qué tiene que implementar
Para que un cliente como ChatGPT pueda conectarse solo, la pasarela necesita cuatro piezas:
- RFC 8414 — metadatos del Authorization Server en
/.well-known/oauth-authorization-server - RFC 9728 — metadatos del recurso protegido, y devolver
WWW-Authenticateconresource_metadataen las respuestas 401 - RFC 7591 — registro dinámico de clientes, para que ChatGPT se dé de alta solo sin que tengas que crear credenciales a mano
- OAuth 2.1 — flujo de código de autorización con PKCE S256 obligatorio, y refresh tokens con rotación
Además debe reenviar correctamente el streaming SSE y propagar la cabecera mcp-session-id en ambos sentidos, o el cliente perderá la sesión MCP entre llamadas.
Antes de escribir código: mira lo que ya existe
Nosotros construimos la nuestra, pero seamos honestos: este problema ya tiene soluciones publicadas, y probablemente te sirvan mejor que empezar de cero.
Hay varios proyectos open source que hacen exactamente esto. El más consolidado en el momento de escribir este artículo es sigbit/mcp-auth-proxy: escrito en Go, se distribuye como binario, gestiona el certificado TLS automáticamente y — lo más relevante — soporta proveedores OIDC (Google, GitHub, Okta, Auth0, Azure AD, Keycloak) además de autenticación por contraseña. Su README documenta compatibilidad verificada con Claude, Claude Code, ChatGPT, GitHub Copilot y Cursor.
Otras alternativas que merece la pena mirar antes de escribir nada: atrawog/mcp-oauth-gateway, obot-platform/mcp-oauth-proxy y, si trabajas en Go y prefieres integrarlo como librería en lugar de como proxy, tuannvm/oauth-mcp-proxy.
¿Cuándo tiene sentido hacerla tú? Básicamente en un caso: cuando prefieres cero dependencias externas, un único fichero que puedas auditar de una sentada, y no añadir superficie de cadena de suministro a tu capa de autenticación. Es un razonamiento defendible, pero valóralo con calma: mantener un servidor de autorización tiene un coste, y estos proyectos ya han pasado por más ojos que el tuyo.
Los cuatro fallos silenciosos que nos costaron horas
Esta es la parte que no encontrarás documentada en ningún sitio, y la razón real de este artículo. Todos comparten un patrón: fallan sin dar error.
1. n8n te asigna una credencial equivocada sin avisar
Al crear workflows mediante la API de n8n, la plataforma autoasigna la primera credencial que encuentra del tipo correcto. El riesgo es evidente: puede acabar poniendo como Bearer de tu servidor MCP una credencial de otro servicio que no tiene nada que ver. Sin errores y sin avisos: el workflow se crea “correctamente” y el endpoint queda aceptando un token que no toca.
Qué hacer: después de crear cualquier workflow por API, verifica explícitamente qué credencial ha quedado asignada en cada nodo. No lo des por hecho.
2. La API puede devolver 204 y no haber hecho nada
Este es el más peligroso. Muchas APIs REST (nos pasó con la de nuestro gestor de incidencias) responden 204 No Content a una petición PUT aunque hayan descartado silenciosamente los campos que enviaste, por falta de permisos.
El resultado: nuestra herramienta reportaba “operación completada con éxito” sin haber escrito absolutamente nada. Un asistente de IA respondiendo “ya está hecho” cuando no lo está es bastante peor que uno que falla.
Qué hacer: en cualquier herramienta de escritura, no te fíes del código HTTP. Vuelve a leer el recurso después de escribir y comprueba que el cambio está realmente ahí. Nosotros añadimos un paso de verificación explícito, y fue lo que destapó el problema.
3. Los permisos pueden tardar en aplicarse
Cambiamos los permisos de un rol, reintentamos, seguía fallando. Concluimos que el permiso no era el correcto y nos fuimos por un camino equivocado durante un buen rato. En realidad el permiso sí era el correcto: la aplicación mantenía los permisos en caché y tardó en recargarlos.
Qué hacer: tras cambiar permisos, si algo falla, reintenta más tarde antes de concluir nada. Y desconfía de las correlaciones: nosotros atribuimos la solución a un cambio que hicimos justo cuando la caché se refrescó, y sacamos una conclusión falsa con bastante confianza.
4. El cliente cachea la lista de herramientas
Añadimos dos herramientas nuevas al servidor MCP, verificamos por línea de comandos que se anunciaban correctamente… y ChatGPT seguía viendo solo la original. No era un fallo: los clientes MCP capturan el catálogo de herramientas al conectar el conector y no lo vuelven a pedir por su cuenta.
Qué hacer: abre una conversación nueva, o desconecta y reconecta el conector. Si añades herramientas, avisa a quien lo use de que tiene que reconectar.
Qué tener en cuenta en seguridad
Si montas algo así, estos puntos no deberían ser opcionales:
- Credenciales separadas por capa. Un token distinto para cada cliente, de forma que revocar el acceso de uno no tumbe a los demás.
- Invalida el código de autorización ante cualquier intento fallido de canje, no solo cuando se usa bien. Impide hacer fuerza bruta contra el
code_verifier. - Rota los refresh tokens: usar uno debe invalidar el anterior.
- Restringe la credencial a su dominio si tu plataforma lo permite, para que no sirva para llamar a ningún otro sitio.
- Si añades herramientas de escritura, usa un usuario dedicado con permisos mínimos y marca lo que crea con un prefijo identificable. Así puedes filtrarlo y revertirlo en bloque si algo sale mal.
- Y que la pantalla de consentimiento diga la verdad. Cuando añadimos escritura, nuestro texto seguía prometiendo acceso de solo lectura. Una pantalla de consentimiento que miente sobre el alcance es un problema de integridad, no un detalle de copy.
Conclusión
La incompatibilidad entre servidores MCP con token estático y clientes que solo hablan OAuth no es exclusiva de n8n ni de ChatGPT: es un desajuste generalizado en el ecosistema ahora mismo. El token estático es el patrón habitual en servidores MCP autoalojados, mientras la especificación empuja hacia OAuth 2.1 y los clientes grandes ya solo aceptan eso.
Una pasarela OAuth es hoy la forma limpia de salvarlo, y lo bueno es que se resuelve una vez: la misma pasarela sirve para cualquier servidor MCP que tengas detrás.
Pero si te llevas una sola cosa de este artículo, que sea la del punto 2: en las herramientas de escritura, verifica siempre releyendo. Un asistente que afirma haber hecho algo que no ha hecho erosiona la confianza mucho más rápido de lo que la construye una herramienta que funciona.