MCP Server Trigger: La creación de herramienta falla con "error parsing json" detrás de reverse proxy (EasyPanel/Traefik)

Hola a todos. Estoy ejecutando n8n autohospedado (v2.21.0) en EasyPanel, una única réplica, detrás de Traefik. Utilizo el nodo MCP Server Trigger (Streamable HTTP) en la ruta /mcp, con Retell AI como cliente MCP.
Las herramientas de respuesta corta (Get many events) funcionan perfectamente y aparecen en Executions. Pero las herramientas de respuesta larga (Create event) devuelven “error parsing json response from mcp server” al cliente, y el nodo Create nunca se ejecuta. Los datos enviados por el cliente son correctos (Start/End válidos con zona horaria).
Esto comenzó justo después de reinstalar el servidor. Según la documentación de n8n, esto requiere deshabilitar el almacenamiento en búfer de proxy y la compresión gzip para el endpoint /mcp. ¿Cuál es la forma correcta de configurar esto en EasyPanel/Traefik? ¿Algún ejemplo funcional de las etiquetas/middleware sería muy apreciado? ¡Gracias!

@Luis_Morello básicamente has acertado la causa, solo estrechando el margen, es específicamente el lado de gzip/compress, no el buffering. El middleware compress de traefik solo se dispara en respuestas superiores a ~1KB (minResponseBodyBytes por defecto es 1024), así que tu salida Get-many se queda por debajo y pasa limpia, pero la respuesta Create más grande la cruza, se comprime con gzip, y Retell no puede parsear el stream comprimido así que obtienes “error parsing json” y el nodo nunca se ejecuta. Eso es exactamente tu división short-works long-fails, y alinearse con la reinstalación tiene sentido también si los defaults del proxy volvieron.

entonces el fix es solo asegurar que las respuestas /mcp no se compriman con gzip. en easypanel eso vive en un archivo traefik personalizado en /etc/easypanel/traefik/config/custom.yaml, luego reinicia traefik desde settings. lo importante es excluir los tipos de contenido mcp de la compresión:

http:
  middlewares:
    mcp-nocompress:
      compress:
        excludedContentTypes:
          - text/event-stream
          - application/json

ambos tipos están ahí porque streamable-HTTP puede responder como uno u otro dependiendo del tamaño de respuesta, así que excluir solo event-stream a veces lo pierde. lo más limpio es asegurar que las rutas /mcp pasen a través de algo que use esto (o ningún middleware compress en absoluto) en lugar del compress default de easypanel.

¿cómo estás exponiendo n8n en easypanel ahora mismo, la caja de dominio integrada o tus propias etiquetas personalizadas? eso decide si solo ajustas el compress existente o añades un router /mcp dedicado, dime cuál es y te doy las líneas exactas para insertar.

Hola @Luis_Morello

Añade las siguientes etiquetas a tu servicio n8n en la sección EasyPanel → Service → Advanced → Custom Labels:

traefik.http.middlewares.n8n-mcp-compress.compress=true
traefik.http.middlewares.n8n-mcp-compress.compress.excludedcontenttypes=text/event-stream

Esto le indica a Traefik que comprima todo excepto el stream de MCP.

traefik.http.middlewares.n8n-mcp-headers.headers.customResponseHeaders.Cache-Control=no-transform

Esto garantiza que ningún otro proxy o caché entre Traefik y Retell AI intente modificar el stream.

Paso Crucial: Debes encontrar el nombre de tu router (visible en el panel de control de Traefik si lo tienes, o generalmente sigue un patrón como https-n8n-your-project). Sin embargo, una forma común de aplicar esto en EasyPanel/Traefik es:

traefik.http.routers.n8n-router.middlewares=n8n-mcp-compress,n8n-mcp-headers

(Reemplaza n8n-router con el nombre de router actual utilizado por EasyPanel para tu servicio. Si no puedes encontrar el nombre del router, consulta la pestaña “Labels” en EasyPanel para ver qué traefik.http.routers.XXXX.rule está configurado actualmente—la XXXX es el nombre de tu router.)

¡Gracias @achamm, esa explicación del umbral de 1KB tiene total sentido y coincide exactamente con mi división de trabajos-cortos/fallos-largos. Estoy exponiendo n8n a través de la caja de dominio integrada de EasyPanel (el dominio generado automáticamente *.easypanel.host), no con etiquetas Docker personalizadas — el campo «Middleware 1» que encontré está bajo Dominios → editar → Middlewares en ese dominio integrado. Una única réplica, Streamable HTTP en /mcp. Con esa configuración, ¿qué líneas exactas debería poner en custom.yaml, y cómo me aseguro de que /mcp evita la compresión predeterminada de EasyPanel en lugar de solo apilarse encima? Prefiero no derribar todo el dominio adivinando. ¡Gracias!

@Luis_Morello sí, apilar otro compress ahí no funcionará, el middleware de dominios integrado se aplica a cada ruta, así que traefik sigue ejecutando el compress predeterminado junto con él, por eso /mcp no lo está omitiendo. ya que tienes una única réplica y el editor de n8n en realidad no necesita gzip, la solución más simple sin downtime es eliminar compress de ese dominio completamente en lugar de luchar contra él por ruta. ¿ese campo Middlewares te permite limpiar o reemplazar el compress predeterminado, o solo agregar encima? eso es lo que determina si esto es un cambio de un campo o un pequeño router custom.yaml solo para /mcp.

¡Gracias @kjooleng, esto es realmente útil y se alinea con el diagnóstico de compresión. Dos cosas que quiero asegurarme de entender antes de tocar algo, ya que estoy en la caja de dominio integrada de EasyPanel (no en etiquetas de enrutador personalizado) y prefiero no romper todo el dominio adivinando:

  1. La línea traefik.http.routers.<router>.middlewares=... — ¿no es verdad que reemplaza la lista completa de middleware en el enrutador en lugar de añadirla? Mi preocupación es que EasyPanel ya administre sus propios middleware en ese enrutador (redirección HTTPS, etc.) detrás de escenas, así que sobrescribir la lista podría eliminar esos. ¿Hay alguna forma segura de añadir estos dos middleware sin borrar los administrados por EasyPanel?
  2. @achamm mencionó que el HTTP Streamable de n8n puede responder como cualquiera text/event-stream o application/json dependiendo del tamaño de la respuesta, y sugirió excluir ambos tipos de contenido. Tu fragmento solo excluye text/event-stream — ¿sería más seguro añadir también application/json a excludedcontenttypes?

Realmente me gusta la idea del encabezado Cache-Control: no-transform, lo mantendré independientemente. Solo quiero hacer bien la parte del enrutador para no dejar el dominio fuera de servicio. ¡Gracias de nuevo!

@Luis_Morello tienes razón en preocuparte, la línea .middlewares= establece toda la lista ordenada para ese router, no es un append, así que sobrescribirlo en el router administrado por easypanels eliminaría su https-redirect y cualquier otra cosa que hayan puesto ahí. exactamente por eso dejaría esa cadena de middlewares del router sola en el dominio integrado. lo más seguro es un router separado de mayor prioridad para /mcp en custom.yaml que no toque el router de easypanels en absoluto, /mcp simplemente coincide con el tuyo primero sin compress y cada otro path mantiene su cadena administrada intacta. si pegas el nombre de tu servicio n8n (easypanel lo muestra en la configuración del servicio) puedo escribirte ese bloque de router exacto.

@Luis_Morello

Según tus preocupaciones, aquí están las etiquetas exactas a utilizar.

Paso A: Definir los Middlewares (Son seguros; no sobrescriben nada)

traefik.http.middlewares.n8n-mcp-compress.compress=true
traefik.http.middlewares.n8n-mcp-compress.compress.excludedcontenttypes=text/event-stream,application/json
traefik.http.middlewares.n8n-mcp-headers.headers.customResponseHeaders.Cache-Control=no-transform

Paso B: Adjuntar al Router (El paso de “Precaución”) Verifica tus etiquetas existentes. Si ves traefik.http.routers.XYZ.middlewares=ABC, utiliza:

traefik.http.routers.XYZ.middlewares=ABC,n8n-mcp-compress,n8n-mcp-headers

Una verificación final: Después de desplegar, si quieres estar 100% seguro de que funciona, utiliza un comando curl en una herramienta que sabes que devuelve una respuesta “larga”: curl -I -H "Accept: application/json" https://your-n8n-domain.com/mcp/your-tool-path Busca el encabezado Content-Encoding. Si dice gzip, el middleware no está adjunto correctamente. Si ese encabezado falta, ¡has ganado!

Oye @Luis_Morello, ya que estás en el dominio integrado de EasyPanel y @achamm confirmó que un router /mcp separado es el camino más seguro, aquí está el bloque custom.yaml exacto que debes copiar en /etc/easypanel/traefik/config/

http:

  middlewares:

    mcp-nocompress:

      compress:

        excludedContentTypes:

          - text/event-stream

          - application/json

    mcp-notransform:

      headers:

        customResponseHeaders:

          Cache-Control: "no-transform"



  routers:

    n8n-mcp:

      rule: "Host(`your-instance.easypanel.host`) && PathPrefix(`/mcp`)"

      priority: 100

      service: "your-n8n-service@docker"

      middlewares:

        - mcp-nocompress

        - mcp-notransform

      tls: {}

Reemplaza your-instance.easypanel.host con tu dominio real y your-n8n-service@docker con el nombre del servicio que aparece en EasyPanel (normalmente -@docker). La prioridad priority: 100 garantiza que este router coincida con /mcp primero, antes de que el router gestionado de EasyPanel lo recoja, así que su redirección HTTPS y otros middlewares se mantienen completamente intactos.

Después de guardar, reinicia Traefik desde EasyPanel Settings, luego ejecuta la comprobación curl -I de @kjooleng para confirmar que Content-Encoding: gzip ha desaparecido de la respuesta.

Cerrando esto — resultó que NO era un problema de Traefik. Verifiqué con wget que el endpoint MCP devolvía respuestas idénticas internamente (localhost:5678) y externamente (URL pública a través de Traefik): el mismo text/event-stream, chunked, sin gzip, sin truncamiento. La causa real estaba en el lado de Retell — mi número de teléfono estaba vinculado a una versión antigua del agente que aún usaba una URL n8n inactiva, por lo que las llamadas reales obtuvieron un 404 en el handshake de MCP. Reconectar el número a la versión publicada actual lo solucionó. No fueron necesarios cambios en Traefik. ¡Gracias por las indicaciones!