Déclencheur du serveur MCP : l'outil de création échoue avec "erreur d'analyse JSON" derrière un proxy inverse (EasyPanel/Traefik)

Bonjour à tous. J’exécute n8n auto-hébergé (v2.21.0) sur EasyPanel, une seule réplica, derrière Traefik. J’utilise le nœud MCP Server Trigger (Streamable HTTP) sur le chemin /mcp, avec Retell AI en tant que client MCP.
Les outils à réponse courte (Get many events) fonctionnent parfaitement et s’affichent dans Executions. Mais les outils à réponse plus longue (Create event) retournent « error parsing json response from mcp server » au client, et le nœud Create ne s’exécute jamais. Les données envoyées par le client sont correctes (Start/End valides avec fuseau horaire).
Cela a commencé juste après que j’aie réinstallé le serveur. Selon la documentation n8n, cela nécessite la désactivation de la mise en mémoire tampon du proxy et de la compression gzip pour le point de terminaison /mcp. Quelle est la bonne façon de configurer cela sur EasyPanel/Traefik ? Un exemple fonctionnant des labels/middleware serait vraiment apprécié. Merci !

@Luis_Morello tu as essentiellement identifié la cause, c’est juste une question de précision, c’est spécifiquement du côté gzip/compress, pas du buffering. Le middleware compress de traefik ne s’active que sur les réponses de plus de ~1KB (minResponseBodyBytes par défaut à 1024), donc ta sortie Get-many passe en dessous et traverse sans problème, mais la plus grande réponse Create la dépasse, se fait gzipper, et Retell ne peut pas parser le flux compressé donc tu obtiens « error parsing json » et le node ne s’exécute jamais. C’est exactement ta séparation short-works long-fails, et ça correspond aussi à la réinstallation si les paramètres par défaut du proxy sont revenus.

Donc la correction c’est juste de s’assurer que les réponses /mcp ne sont pas gzippées. Sur easypanel c’est dans un fichier traefik personnalisé à /etc/easypanel/traefik/config/custom.yaml, puis redémarre traefik depuis les paramètres. Le point clé c’est d’exclure les types de contenu mcp de la compression :

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

les deux types sont là parce que streamable-HTTP peut répondre en l’un ou l’autre selon la taille de la réponse, donc exclure seulement event-stream parfois la rate. Le plus propre c’est de s’assurer que les routes /mcp passent par quelque chose qui utilise ça (ou pas de middleware compress du tout) plutôt que le compress par défaut d’easypanel.

Comment tu exposes n8n dans easypanel en ce moment, la boîte de domaine intégrée ou tes propres étiquettes personnalisées ? ça détermine si tu tweakes juste le compress existant ou si tu ajoutes un router /mcp dédié, dis-moi lequel et je te donne les lignes exactes à mettre dedans.

Salut @Luis_Morello

Ajoutez les étiquettes suivantes à votre service n8n dans la section EasyPanel → Service → Advanced → Custom Labels :

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

Cela indique à Traefik de compresser tout sauf le flux MCP.

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

Cela garantit qu’aucun autre proxy ou cache entre Traefik et Retell AI ne tente de modifier le flux.

Étape cruciale : Vous devez trouver le nom de votre routeur (visible dans le tableau de bord Traefik si vous en avez un, ou qui suit généralement un modèle comme https-n8n-your-project). Cependant, un moyen courant d’appliquer cela dans EasyPanel/Traefik est :

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

(Remplacez n8n-router par le nom du routeur réel utilisé par EasyPanel pour votre service. Si vous ne pouvez pas trouver le nom du routeur, consultez l’onglet « Labels » dans EasyPanel pour voir ce qui est actuellement défini dans traefik.http.routers.XXXX.ruleXXXX est le nom de votre routeur.)

Merci @achamm, cette explication du seuil de 1 KB est très claire et correspond exactement à ma répartition entre les courts textes qui fonctionnent et les longs qui échouent. J’expose n8n via la boîte de domaine intégrée d’EasyPanel (le domaine auto-généré *.easypanel.host), et non via des étiquettes Docker personnalisées — le champ « Middleware 1 » que j’ai trouvé se trouve sous Domains → edit → Middlewares sur ce domaine intégré. Une seule réplique, HTTP diffusable (Streamable HTTP) sur /mcp. Avec cette configuration, quelles lignes exactes je dois ajouter dans custom.yaml, et comment je m’assure que /mcp contourne la compression par défaut d’EasyPanel plutôt que de simplement s’ajouter dessus ? Je préférerais ne pas mettre le domaine hors ligne en devinant. Merci !

@Luis_Morello ouais, empiler un autre compress là-dessus ne suffira pas, le middleware de domaines intégré s’applique à chaque chemin donc traefik exécute toujours le compress par défaut à côté, c’est pour ça que /mcp ne le contourne pas. puisque tu as une seule réplica et que l’éditeur n8n n’a pas vraiment besoin de gzip, la solution la plus simple sans temps d’arrêt est de supprimer complètement compress de ce domaine au lieu de le combattre par chemin. est-ce que ce champ Middlewares te permet d’effacer ou de remplacer le compress par défaut, ou tu peux juste en ajouter par-dessus ? c’est ça qui détermine si c’est un changement d’un champ ou une petite routeur custom.yaml juste pour /mcp.

Merci @kjooleng, c’est vraiment utile et cela correspond au diagnostic de compression. Deux choses que je veux bien comprendre avant de toucher à quoi que ce soit, puisque je suis sur la boîte de domaine intégrée d’EasyPanel (et non sur des libellés de routeur personnalisés) et je préférerais ne pas casser tout le domaine en devinant :

  1. La ligne traefik.http.routers.<router>.middlewares=... — ne fait-elle pas remplacer la liste complète des middlewares sur le routeur plutôt que de les ajouter ? Je crains qu’EasyPanel ne gère déjà ses propres middlewares sur ce routeur (redirection HTTPS, etc.) en arrière-plan, donc écraser la liste pourrait les supprimer. Y a-t-il un moyen sûr d’ajouter ces deux middlewares sans écraser ceux gérés par EasyPanel ?
  2. @achamm a mentionné que le Streamable HTTP de n8n peut répondre soit en text/event-stream soit en application/json selon la taille de la réponse, et a suggéré d’exclure les deux types de contenu. Votre extrait exclut seulement text/event-stream — serait-il plus sûr d’ajouter aussi application/json à excludedcontenttypes ?

J’aime vraiment l’idée du en-tête Cache-Control: no-transform, je la garderai de toute façon. Je veux juste bien faire la partie du routeur pour ne pas mettre le domaine hors ligne. Merci encore !

@Luis_Morello tu as raison de t’inquiéter, la ligne .middlewares= définit la liste complète ordonnée pour ce routeur, ce n’est pas un ajout, donc la réécrire sur le routeur géré par easypanels éliminerait leur redirection https et tout ce qu’ils ont mis là. c’est exactement pour ça que je laisserais seule la chaîne de middleware de ce routeur sur le domaine intégré. le plus sûr c’est un routeur séparé avec une priorité plus élevée pour /mcp dans custom.yaml qui ne touche pas du tout au routeur d’easypanels, /mcp correspond simplement à la tienne en premier sans compression et tous les autres chemins gardent leur chaîne gérée intacte. si tu mets le nom de ton service n8n (easypanel l’affiche dans la config du service) je peux t’écrire ce bloc de routeur exact.

@Luis_Morello

En fonction de vos préoccupations, voici les étiquettes exactes à utiliser.

Étape A : Définir les Middlewares (Ceux-ci sont sûrs ; ils ne réécrivent rien)

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

Étape B : Attacher au Routeur (L’étape « Attention ») Vérifiez vos étiquettes existantes. Si vous voyez traefik.http.routers.XYZ.middlewares=ABC, utilisez :

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

Vérification finale : Après votre déploiement, si vous voulez être 100% sûr que ça fonctionne, utilisez une commande curl sur un outil dont vous savez qu’il retourne une réponse « longue » : curl -I -H "Accept: application/json" https://your-n8n-domain.com/mcp/your-tool-path Cherchez l’en-tête Content-Encoding. S’il dit gzip, le middleware n’est pas attaché correctement. Si cet en-tête est absent​, vous avez gagné.

Salut @Luis_Morello, puisque tu utilises le domaine intégré d’EasyPanel et que @achamm a confirmé qu’un routeur /mcp séparé est la solution la plus sûre, voici le bloc custom.yaml exact à ajouter dans /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: {}

Remplace your-instance.easypanel.host par ton domaine réel et your-n8n-service@docker par le nom du service affiché dans EasyPanel (généralement -@docker). La priorité priority: 100 garantit que ce routeur correspond d’abord à /mcp, avant que le routeur géré d’EasyPanel le détecte, de sorte que leur redirection HTTPS et les autres middlewares restent complètement intacts.

Après avoir enregistré, redémarre Traefik depuis les paramètres d’EasyPanel, puis exécute la vérification curl -I de @kjooleng pour confirmer que Content-Encoding: gzip a disparu de la réponse.

Je ferme ce ticket — il s’avère que ce n’était PAS un problème Traefik. J’ai vérifié avec wget que le point de terminaison MCP retournait des réponses identiques en interne (localhost:5678) et en externe (URL publique via Traefik) : même text/event-stream, par chunks, sans gzip, sans troncature. La véritable cause venait du côté Retell — mon numéro de téléphone était épinglé à une ancienne version d’agent qui utilisait toujours une URL n8n morte, donc les vrais appels recevaient une erreur 404 lors de la négociation MCP. Relier le numéro à la version publiée actuelle a résolu le problème. Aucune modification Traefik n’était nécessaire. Merci pour les indices !