Docs: migração MCP Server nativo n8n (Z-PRO) validada em produção
- Seção 13 do runbook: arquitetura nova (MCP Server Trigger + Call n8n Sub-Workflow Tool, sem node comunitário/processo externo pro Z-PRO) - Documenta os 2 gotchas reais de ativação e a causa raiz do 403 em produção (ApiID e token vêm de integrações diferentes no Z-PRO, não é bug de formato de header nem token expirado) - Teste real de ponta a ponta confirmado (webhook -> AI Agent -> MCP nativo -> Z-PRO), agendamento fictício criado e apagado - Status final atualizado: workflow + 3 sub-workflows do MCP nativo ativos em produção Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
8641d68f4f
commit
786a97083e
@@ -254,10 +254,116 @@ explícita no `systemMessage`.
|
|||||||
certo para fuso de Brasília. Se uma clínica futura estiver em outro fuso,
|
certo para fuso de Brasília. Se uma clínica futura estiver em outro fuso,
|
||||||
ajustar o offset (e o `$now.setZone(...)` do prompt) de acordo.
|
ajustar o offset (e o `$now.setZone(...)` do prompt) de acordo.
|
||||||
|
|
||||||
## Status final (10/08/2026)
|
## 13. Migração — MCP Server nativo no n8n (substitui o node comunitário, só Z-PRO)
|
||||||
|
|
||||||
Testado de ponta a ponta com sucesso, com a chave real da OpenAI
|
**Data:** 11/08/2026. Ver design completo em
|
||||||
(`gpt-4o-mini`): telefone correto, data correta, um único agendamento por
|
`docs/superpowers/specs/2026-08-10-mcp-server-nativo-n8n-zpro-design.md` e
|
||||||
teste, confirmado visualmente no Z-PRO. Workflow deixado **desativado**
|
plano em `docs/superpowers/plans/2026-08-10-mcp-server-nativo-n8n-zpro.md`.
|
||||||
propositalmente — só ativar quando o Z-PRO de uma clínica real for
|
|
||||||
configurado para apontar pra esse webhook.
|
**Motivação**: o node comunitário (`n8n-nodes-mcp`, seções 1–2 acima) exigiu
|
||||||
|
depuração pesada (bug de credencial STDIO, variável de ambiente do processo,
|
||||||
|
`toolParameters`/`$fromAI` não documentado) e não é editável visualmente —
|
||||||
|
qualquer manutenção de memória/prompt/tool exige mexer em processo externo.
|
||||||
|
A alternativa: reconstruir o mesmo "MCP Server" **inteiramente dentro do
|
||||||
|
n8n**, com nodes **oficiais** (`MCP Server Trigger` + `Call n8n Sub-Workflow
|
||||||
|
Tool` do lado servidor, `MCP Client Tool` oficial via HTTP Streamable do
|
||||||
|
lado cliente) — sem processo Node.js externo, sem pacote comunitário.
|
||||||
|
|
||||||
|
**Arquitetura nova** (3 workflows adicionais, o workflow de agendamento
|
||||||
|
existente só trocou o node MCP):
|
||||||
|
|
||||||
|
- `MCP Server - ZPRO` (`qjSaKllvneBIZ7mC`) — `MCP Server Trigger`
|
||||||
|
(`path: mcp-server-zpro-clinica-exemplo`) + 2 `Call n8n Sub-Workflow Tool`
|
||||||
|
(`agendar`, `consultar_horarios`).
|
||||||
|
- `MCP Server - ZPRO - agendar` (`5ZEOqTOk4Xex6jUQ`) — porta fiel da lógica
|
||||||
|
já testada em `gti-scheduling-mcp` (`zpro.mapper.ts`/`zpro.adapter.ts`/
|
||||||
|
`zpro.errors.ts`) para nodes `Set`/`Code`/`HTTP Request`: monta o corpo,
|
||||||
|
chama `POST /v2/api/external/{apiId}/appointment/create` com
|
||||||
|
`neverError: true` + `fullResponse: true` (captura manual de status/body,
|
||||||
|
nunca deixa o n8n abortar em 4xx/5xx), classifica o resultado (qualquer
|
||||||
|
2xx é sucesso operacional — mesma proteção contra duplicidade de sempre).
|
||||||
|
- `MCP Server - ZPRO - consultar_horarios` (`yfKkhSTDZaIYCPqP`) — sempre
|
||||||
|
retorna `NOT_SUPPORTED` (mesma decisão de produto de sempre, Z-PRO não
|
||||||
|
expõe esse endpoint).
|
||||||
|
- No workflow de agendamento (`yG2mi6ECBpPv4Hmn`): saiu o node comunitário
|
||||||
|
`MCP - gti-scheduling-mcp` (`n8n-nodes-mcp.mcpClientTool`, stdio), entrou
|
||||||
|
`MCP - ZPRO (nativo n8n)` (`@n8n/n8n-nodes-langchain.mcpClientTool`,
|
||||||
|
`serverTransport: httpStreamable`, apontando pra URL do `MCP Server
|
||||||
|
Trigger` acima). Nada mais no workflow mudou (prompt, memória, fallback de
|
||||||
|
erro).
|
||||||
|
|
||||||
|
**Gotcha 1 — todos os workflows envolvidos precisam estar `active: true`**,
|
||||||
|
inclusive os dois sub-workflows (`agendar`/`consultar_horarios`) chamados
|
||||||
|
via `Call n8n Sub-Workflow Tool` — não só o servidor MCP e o workflow de
|
||||||
|
agendamento. O erro sintoma é `"Workflow is not active and cannot be
|
||||||
|
executed."` no node `MCP Client Tool` do lado do AI Agent.
|
||||||
|
|
||||||
|
**Gotcha 2 — diagnóstico via chamada MCP crua (`curl`), sem depender do AI
|
||||||
|
Agent**: pra isolar se o problema está na cadeia de sub-workflows ou no
|
||||||
|
transporte/roteamento do AI Agent, dá pra chamar o endpoint MCP diretamente:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Handshake — captura o mcp-session-id no header da resposta
|
||||||
|
curl -s -i "https://devn8n.gtigrupo.com.br/mcp/mcp-server-zpro-clinica-exemplo" -X POST \
|
||||||
|
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
|
||||||
|
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl-test","version":"1.0"}}}'
|
||||||
|
|
||||||
|
# 2. tools/call — usa o mcp-session-id do passo 1
|
||||||
|
curl -s "https://devn8n.gtigrupo.com.br/mcp/mcp-server-zpro-clinica-exemplo" -X POST \
|
||||||
|
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
|
||||||
|
-H "mcp-session-id: <session-id>" \
|
||||||
|
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"agendar","arguments":{"startAt":"...","endAt":"...","patientName":"...","patientPhone":"..."}}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Isso foi o que revelou que a cadeia de sub-workflows já funcionava (chegava
|
||||||
|
até o Z-PRO de verdade) enquanto o caminho via AI Agent ainda reportava
|
||||||
|
"not active" — depois de reativar os 3 workflows envolvidos e aguardar um
|
||||||
|
pouco, o caminho via AI Agent voltou a funcionar igual ao teste direto
|
||||||
|
(não ficou claro se foi só o tempo/cache do n8n resolvendo, ou a
|
||||||
|
reativação — mas o sintoma não voltou a aparecer depois disso).
|
||||||
|
|
||||||
|
**Gotcha 3 — causa raiz real do primeiro `403` em produção**: não foi
|
||||||
|
formato de header nem token expirado — foi **ApiID e token de integrações
|
||||||
|
diferentes**. A clínica tem mais de uma integração externa cadastrada no
|
||||||
|
Z-PRO (ex.: uma pro canal de WhatsApp "Canal QR", outra pro agendamento),
|
||||||
|
cada uma com seu próprio `ApiID` (segmento da URL,
|
||||||
|
`/v2/api/external/{ApiID}/...`) **e** seu próprio Bearer token — não são
|
||||||
|
intercambiáveis. O node `Config ZPRO` precisa ter o `apiId` da **mesma**
|
||||||
|
integração de onde veio o token salvo na credencial `httpHeaderAuth`. Os
|
||||||
|
sintomas por tipo de descasamento, na ordem em que apareceram:
|
||||||
|
|
||||||
|
| Corpo de erro do Z-PRO (403) | Causa |
|
||||||
|
| --- | --- |
|
||||||
|
| `{"error": "ERR_SESSION_NOT_AUTH_TOKEN"}` | token nunca usado/nunca válido pra nenhuma integração |
|
||||||
|
| `{"error": "Invalid token."}` | token de uma integração, `apiId` de outra (ou vice-versa) |
|
||||||
|
| (sucesso, `200`) | `apiId` e token da **mesma** integração |
|
||||||
|
|
||||||
|
Ao duplicar este padrão pra uma nova clínica: sempre confirmar, na tela de
|
||||||
|
integrações do Z-PRO daquela clínica, que o `ApiID` copiado pra URL e o
|
||||||
|
Bearer token copiado pra credencial vêm da **mesma linha/integração**.
|
||||||
|
|
||||||
|
**Teste real de validação (11/08/2026)**: um agendamento fictício foi
|
||||||
|
criado de ponta a ponta pelo caminho de produção completo (webhook →
|
||||||
|
Normalizar entrada → AI Agent → `MCP - ZPRO (nativo n8n)` → `MCP Server -
|
||||||
|
ZPRO` → sub-workflow `agendar` → Z-PRO), com `startAt` local correto
|
||||||
|
(`2026-08-12T11:00:00-03:00`, sem bug de timezone), retorno `200` do
|
||||||
|
Z-PRO, `id` de agendamento real mapeado, e resposta final coerente pro
|
||||||
|
cliente. Conferido visualmente no Z-PRO e apagado logo em seguida.
|
||||||
|
|
||||||
|
**Resultado**: o node comunitário `n8n-nodes-mcp` não é mais necessário
|
||||||
|
pro Z-PRO (segue instalado no servidor, mas sem uso nesse workflow). As
|
||||||
|
seções 1–2 deste runbook (instalação do node comunitário, bugs da
|
||||||
|
credencial STDIO) ficam como **referência histórica** — não se aplicam
|
||||||
|
mais a este workflow, mas continuam relevantes se algum dia o padrão nativo
|
||||||
|
não for suficiente e for necessário voltar ao processo externo
|
||||||
|
(`gti-scheduling-mcp`, monorepo TypeScript pausado).
|
||||||
|
|
||||||
|
## Status final (11/08/2026)
|
||||||
|
|
||||||
|
Testado de ponta a ponta com sucesso, tanto com a chave real da OpenAI
|
||||||
|
(`gpt-4o-mini`) quanto com o MCP Server nativo do n8n (seção 13): telefone
|
||||||
|
correto, data correta, um único agendamento por teste, confirmado
|
||||||
|
visualmente no Z-PRO. Workflow **ativo em produção** (`yG2mi6ECBpPv4Hmn`),
|
||||||
|
junto com os 3 workflows do MCP Server nativo (`qjSaKllvneBIZ7mC`,
|
||||||
|
`5ZEOqTOk4Xex6jUQ`, `yfKkhSTDZaIYCPqP`) — todos precisam permanecer
|
||||||
|
`active: true`.
|
||||||
|
|||||||
Reference in New Issue
Block a user