Oi a todos. Estou rodando n8n auto-hospedado (v2.21.0) no EasyPanel, com uma única réplica, atrás do Traefik. Uso o nó MCP Server Trigger (Streamable HTTP) no caminho /mcp, com Retell AI como cliente MCP.
As ferramentas com respostas curtas (Get many events) funcionam perfeitamente e aparecem em Executions. Mas ferramentas com respostas mais longas (Create event) retornam “error parsing json response from mcp server” ao cliente, e o nó Create nunca é executado. Os dados enviados pelo cliente estão corretos (Start/End válidos com timezone).
Isso começou logo após eu reinstalar o servidor. De acordo com a documentação do n8n, isso requer que o buffering de proxy e a compressão gzip sejam desabilitados para o endpoint /mcp. Qual é a maneira correta de configurar isso no EasyPanel/Traefik? Algum exemplo funcionando dos labels/middleware seria muito apreciado. Obrigado!
@Luis_Morello você basicamente identificou a causa, só afunilando, é especificamente o lado gzip/compress, não o buffering. O middleware de compress do traefik só funciona em respostas maiores que ~1KB (minResponseBodyBytes padrão é 1024), então sua saída Get-many passa por baixo disso e passa limpa, mas a resposta Create maior cruza o limite, fica compactada, e o Retell não consegue fazer parse da stream compactada então você recebe “error parsing json” e o node nunca executa. Isso é exatamente seu split short-works long-fails, e se alinhar com a reinstalação faz sentido também se os padrões do proxy voltaram.
então o fix é só garantir que respostas /mcp não sejam gzipadas. no easypanel isso fica em um arquivo traefik customizado em /etc/easypanel/traefik/config/custom.yaml, aí restart o traefik nas settings. o detalhe importante é excluir os content types do mcp da compressão:
http:
middlewares:
mcp-nocompress:
compress:
excludedContentTypes:
- text/event-stream
- application/json
os dois tipos estão aí porque streamable-HTTP pode responder como qualquer um dependendo do tamanho da resposta, então excluir só event-stream às vezes não pega. o mais limpo é garantir que rotas /mcp passem por algo que use isso (ou nenhum middleware compress) ao invés do compress padrão do easypanel.
como você está expondo n8n no easypanel agora, a caixa de domínio built-in ou seus próprios labels customizados? isso decide se você só faz tweak no compress existente ou adiciona um router /mcp dedicado, me fala qual e eu dou as linhas exatas pra colar.
Adicione os seguintes rótulos ao seu serviço n8n na seção EasyPanel → Service → Advanced → Custom Labels:
traefik.http.middlewares.n8n-mcp-compress.compress=true
traefik.http.middlewares.n8n-mcp-compress.compress.excludedcontenttypes=text/event-stream
Isso informa ao Traefik para comprimir tudo exceto o stream MCP.
traefik.http.middlewares.n8n-mcp-headers.headers.customResponseHeaders.Cache-Control=no-transform
Isso garante que nenhum outro proxy ou cache entre o Traefik e o Retell AI tente modificar o stream.
Etapa Crucial: Você deve encontrar o nome do seu roteador (visível no painel do Traefik se você o tiver, ou geralmente segue um padrão como https-n8n-seu-projeto). Porém, uma maneira comum de aplicar isso no EasyPanel/Traefik é:
traefik.http.routers.n8n-router.middlewares=n8n-mcp-compress,n8n-mcp-headers
(Substitua n8n-router pelo nome do roteador real usado pelo EasyPanel para seu serviço. Se não conseguir encontrar o nome do roteador, verifique a aba “Labels” no EasyPanel para ver qual traefik.http.routers.XXXX.rule está atualmente configurado—o XXXX é o nome do seu roteador.)
Obrigado @achamm, aquela explicação do limite de 1KB faz total sentido e combina perfeitamente com minha divisão entre works curtos e long-fails. Estou expondo o n8n através da caixa de domínio integrada do EasyPanel (o domínio auto-gerado *.easypanel.host), não de rótulos Docker customizados — o campo “Middleware 1” que encontrei fica em Domains → edit → Middlewares naquele domínio integrado. Uma única réplica, HTTP Streamable em /mcp. Com essa configuração, quais linhas exatas devo colocar em custom.yaml, e como garantir que /mcp contorne a compressão padrão do EasyPanel em vez de apenas se empilhar em cima dela? Prefiro não derrubar o domínio inteiro chutando. Obrigado!
@Luis_Morello yeah stacking another compress ali não vai resolver, o middleware de domínios built-in se aplica a todo path, então o traefik ainda roda o compress padrão junto, é por isso que /mcp não tá burlando. como você tem single replica e o editor do n8n na verdade não precisa de gzip, o fix mais simples sem downtime é remover compress desse domínio inteiro em vez de ficar brigando por path. esse campo Middlewares deixa você limpar ou substituir o compress padrão, ou só adiciona por cima? isso é que decide se é uma mudança de um campo só ou um custom.yaml router pequeno só pra /mcp.
Obrigado @kjooleng, isso é muito útil e se alinha com o diagnóstico de compressão. Duas coisas que quero ter certeza de entender antes de mexer em qualquer coisa, já que estou usando a caixa de domínio integrada da EasyPanel (não rótulos de roteador personalizados) e prefiro não quebrar o domínio inteiro chutando:
- A linha
traefik.http.routers.<router>.middlewares=...— isso não substitui a lista completa de middlewares no roteador em vez de apenas adicionar? Minha preocupação é que a EasyPanel já gerencia seus próprios middlewares nesse roteador (redirecionamento HTTPS, etc.) nos bastidores, então sobrescrever a lista pode remover esses. Existe uma forma segura de adicionar esses dois middlewares sem apagar os gerenciados pela EasyPanel? - @achamm mencionou que o HTTP Streamable do n8n pode responder como tanto
text/event-streamquantoapplication/jsondependendo do tamanho da resposta, e sugeriu excluir ambos os tipos de conteúdo. Seu snippet apenas excluitext/event-stream— seria mais seguro adicionarapplication/jsonaexcludedcontenttypestambém?
Eu realmente gosto da ideia do header Cache-Control: no-transform, vou manter isso independentemente. Só quero acertar a parte do roteador para não derrubar o domínio. Obrigado novamente!
@Luis_Morello você tem razão em se preocupar, a linha .middlewares= define toda a lista ordenada para aquele router, não é um append, então sobrescrever isso no router gerenciado do easypanel removeria o https-redirect e qualquer outra coisa que eles colocaram lá. é exatamente por isso que eu deixaria aquela cadeia de middleware do router sozinha no domínio built-in. o mais seguro é um router separado com prioridade maior para /mcp no custom.yaml que não toca no router do easypanel, /mcp apenas corresponde ao seu primeiro sem compress e todos os outros caminhos mantêm sua cadeia gerenciada intacta. se você colar o nome do seu serviço n8n (easypanel mostra isso na configuração do serviço) eu posso escrever esse bloco de router exato para você.
Com base nas suas preocupações, aqui estão os rótulos exatos para usar.
Etapa A: Defina os Middlewares (Estes são seguros; eles não sobrescrevem 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
Etapa B: Anexe ao Router (A Etapa de “Cuidado”) Verifique seus rótulos existentes. Se você vir traefik.http.routers.XYZ.middlewares=ABC, use:
traefik.http.routers.XYZ.middlewares=ABC,n8n-mcp-compress,n8n-mcp-headers
Uma verificação final: Depois de fazer o deploy, se você quiser ter 100% de certeza de que está funcionando, use um comando curl em uma ferramenta que você sabe que retorna uma resposta „longa": curl -I -H "Accept: application/json" https://your-n8n-domain.com/mcp/your-tool-path Procure pelo cabeçalho Content-Encoding. Se disser gzip, o middleware não foi anexado corretamente. Se esse cabeçalho estiver ausente, você venceu.
Oi @Luis_Morello, já que você está no domínio integrado do EasyPanel e @achamm confirmou que um roteador /mcp separado é o caminho mais seguro, aqui está o bloco custom.yaml exato para colocar em /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(`seu-instancia.easypanel.host`) && PathPrefix(`/mcp`)"
priority: 100
service: "seu-servico-n8n@docker"
middlewares:
- mcp-nocompress
- mcp-notransform
tls: {}
Substituir seu-instancia.easypanel.host pelo seu domínio real e seu-servico-n8n@docker pelo nome do serviço mostrado no EasyPanel (geralmente -<serviço>@docker). O priority: 100 garante que este roteador encontre /mcp primeiro, antes do roteador gerenciado do EasyPanel pegá-lo, então o redirecionamento HTTPS e outros middlewares deles continuam completamente intactos.
Depois de salvar, reinicie o Traefik nas Configurações do EasyPanel, depois execute a verificação curl -I do @kjooleng para confirmar que Content-Encoding: gzip desapareceu da resposta.
Resolvido — afinal NÃO era um problema do Traefik. Verifiquei com wget que o endpoint MCP retornou respostas idênticas internamente (localhost:5678) e externamente (URL pública através do Traefik): mesmo text/event-stream, chunked, sem gzip, sem truncamento. A causa real estava no lado do Retell — meu número de telefone estava vinculado a uma versão antiga do agente que ainda usava uma URL n8n morta, então chamadas reais recebiam um 404 no handshake do MCP. Re-vincular o número à versão publicada atual resolveu. Nenhuma alteração no Traefik foi necessária. Obrigado pelas dicas!