Spec: MCP Server nativo no n8n para o Z-PRO (substitui node comunitario stdio)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
257afe98c0
commit
3f10ab5efd
@@ -0,0 +1,139 @@
|
|||||||
|
# Design — MCP Server nativo no n8n para o Z-PRO
|
||||||
|
|
||||||
|
**Data:** 2026-08-10
|
||||||
|
**Status:** Aprovado pelo usuário, aguardando plano de implementação.
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Reconstruir o "MCP Server" do Z-PRO **dentro do n8n**, usando nodes oficiais
|
||||||
|
(`MCP Server Trigger` + `Call n8n Sub-Workflow Tool`), em vez de um processo
|
||||||
|
Node.js externo (`gti-scheduling-mcp`) conectado via node comunitário stdio.
|
||||||
|
|
||||||
|
Motivação: o node comunitário (`n8n-nodes-mcp`) exigiu um dia inteiro de
|
||||||
|
depuração (ver `docs/n8n-agendamento-runbook.md`) — campo de credencial
|
||||||
|
quebrado, caminho absoluto de binário, mecanismo `toolParameters`/`$fromAI`
|
||||||
|
não documentado. Um MCP Server nativo do n8n elimina essa camada inteira:
|
||||||
|
usa só nodes oficiais dos dois lados (servidor e cliente), tudo editável
|
||||||
|
visualmente, sem deploy de processo separado, sem SSH para manutenção.
|
||||||
|
|
||||||
|
## Relação com o trabalho anterior
|
||||||
|
|
||||||
|
Este design **substitui, para o Z-PRO**, o plano de monorepo
|
||||||
|
TypeScript (`packages/zpro-mcp`, `packages/klingo-mcp`, etc.) discutido
|
||||||
|
horas antes nesta mesma sessão. Aquele plano fica pausado — se a
|
||||||
|
abordagem nativa do n8n se confirmar boa na prática, o mesmo padrão é
|
||||||
|
replicado para Klingo/ClinicAll/SysLife depois; o monorepo TypeScript só
|
||||||
|
volta a fazer sentido se algo aqui não funcionar bem.
|
||||||
|
|
||||||
|
O `gti-scheduling-mcp` (TypeScript, testado, com `ZProAdapter` e
|
||||||
|
`KlingoAdapter` funcionando) **não é apagado** — fica como referência da
|
||||||
|
lógica de negócio já validada (mapeamento de request/response, classificação
|
||||||
|
de erro HTTP, proteção contra duplicidade) a ser replicada nos nodes do
|
||||||
|
n8n. Este design é, na prática, uma **porta** dessa lógica já testada para
|
||||||
|
nodes n8n — não um redesenho da regra de negócio em si.
|
||||||
|
|
||||||
|
## Contexto verificado (nodes reais, confirmados via n8n-mcp)
|
||||||
|
|
||||||
|
- **`MCP Server Trigger`** (`@n8n/n8n-nodes-langchain.mcpTrigger`, v2) —
|
||||||
|
trigger baseado em webhook, expõe um `path` como endpoint MCP. Nó
|
||||||
|
**oficial**, não comunitário.
|
||||||
|
- **`Call n8n Sub-Workflow Tool`** (`@n8n/n8n-nodes-langchain.toolWorkflow`,
|
||||||
|
v2.2) — empacota outro workflow inteiro como uma tool exposta ao MCP,
|
||||||
|
com `name`, `description`, e `workflowInputs` (schema dos parâmetros que
|
||||||
|
a tool aceita). O sub-workflow chamado precisa começar com um
|
||||||
|
`Execute Workflow Trigger`.
|
||||||
|
- Do lado cliente (o workflow de agendamento existente), o node oficial
|
||||||
|
`MCP Client Tool` (`@n8n/n8n-nodes-langchain.mcpClientTool`) suporta
|
||||||
|
conexão via **HTTP Streamable/SSE** — exatamente o transporte que o
|
||||||
|
`MCP Server Trigger` expõe. Não precisa de nenhum pacote comunitário.
|
||||||
|
|
||||||
|
## Arquitetura
|
||||||
|
|
||||||
|
```
|
||||||
|
[MCP Server Trigger] ──Tools──┬── [Call Sub-Workflow Tool: "agendar"] ──▶ "MCP Server - ZPRO - agendar"
|
||||||
|
(workflow "MCP Server - ZPRO") │
|
||||||
|
└── [Call Sub-Workflow Tool: "consultar_horarios"] ──▶ "MCP Server - ZPRO - consultar_horarios"
|
||||||
|
```
|
||||||
|
|
||||||
|
Três workflows no total. O workflow de agendamento existente (AI Agent +
|
||||||
|
prompt + memória) **não muda nada**, exceto o node MCP: sai o comunitário
|
||||||
|
(stdio), entra o `MCP Client Tool` oficial (HTTP), apontando pra URL do
|
||||||
|
`MCP Server Trigger`.
|
||||||
|
|
||||||
|
## Componentes
|
||||||
|
|
||||||
|
### Workflow "MCP Server - ZPRO" (o servidor)
|
||||||
|
|
||||||
|
- `MCP Server Trigger` — define o `path` do endpoint (ex.:
|
||||||
|
`mcp-server-zpro-clinica-exemplo`).
|
||||||
|
- Dois nodes `Call n8n Sub-Workflow Tool`, um por tool:
|
||||||
|
- `agendar` → aponta pro sub-workflow "MCP Server - ZPRO - agendar".
|
||||||
|
- `consultar_horarios` → aponta pro sub-workflow "MCP Server - ZPRO -
|
||||||
|
consultar_horarios".
|
||||||
|
|
||||||
|
### Sub-workflow "MCP Server - ZPRO - agendar"
|
||||||
|
|
||||||
|
```
|
||||||
|
[Execute Workflow Trigger] → [Config ZPRO] → [Montar corpo] → [HTTP Request] → [Classificar resultado]
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Execute Workflow Trigger**: recebe os parâmetros da tool — `clinicId`,
|
||||||
|
`startAt`, `endAt`, `patient` (nome obrigatório; telefone, id, documento
|
||||||
|
opcionais), `title` opcional. Mesmo contrato de hoje
|
||||||
|
(`CreateAppointmentInput`/`agendarInputSchema`), definido no
|
||||||
|
`workflowInputs` do node pai.
|
||||||
|
- **Config ZPRO** (`Set`): `baseUrl` e `apiId` fixos desta clínica — ajustar
|
||||||
|
ao duplicar pra outra clínica (mesmo espírito do `clinicId` fixo no
|
||||||
|
"Normalizar entrada" do workflow de agendamento).
|
||||||
|
- **Montar corpo** (`Code`): porta de `zpro.mapper.ts` —
|
||||||
|
`title` default (`"Consulta - {nome}"` se não informado pelo cliente),
|
||||||
|
inclui `contactId`/`contactPhone` só quando existirem no input,
|
||||||
|
`status: "pending"` fixo.
|
||||||
|
- **HTTP Request**: `POST {baseUrl}/v2/api/external/{apiId}/appointment/create`,
|
||||||
|
Bearer token vindo de uma Credential do n8n. **Resposta completa/"Never
|
||||||
|
Error" habilitado** — por padrão o n8n trata 4xx/5xx como falha e aborta
|
||||||
|
o workflow; a classificação de erro precisa ser feita manualmente no
|
||||||
|
próximo node, replicando exatamente o comportamento já validado.
|
||||||
|
- **Classificar resultado** (`Code`): porta de `zpro.adapter.ts` +
|
||||||
|
`zpro.errors.ts`:
|
||||||
|
- **Qualquer HTTP 2xx é sucesso operacional**, sem exceção — mesma
|
||||||
|
proteção contra duplicidade já validada em produção. Tenta mapear o
|
||||||
|
envelope real conhecido (`{success:true, data:{id,startAt,endAt,status}}`,
|
||||||
|
ver `docs/zpro-api-mapping.md`); se o corpo não bater com esse
|
||||||
|
formato, devolve um resultado "aceito, mapeamento pendente" construído
|
||||||
|
só com os dados do input (nunca inventa campos do corpo).
|
||||||
|
- Fora do intervalo 2xx: classifica em `AUTHENTICATION_ERROR` (401/403),
|
||||||
|
`NOT_FOUND` (404), `VALIDATION_ERROR` (400/422), ou um erro genérico
|
||||||
|
para o resto — mesmos códigos já usados hoje.
|
||||||
|
|
||||||
|
### Sub-workflow "MCP Server - ZPRO - consultar_horarios"
|
||||||
|
|
||||||
|
```
|
||||||
|
[Execute Workflow Trigger] → [Code: retorna NOT_SUPPORTED]
|
||||||
|
```
|
||||||
|
|
||||||
|
Sem chamada HTTP — mesma decisão de produto de hoje (o Z-PRO não expõe
|
||||||
|
endpoint de disponibilidade de horários).
|
||||||
|
|
||||||
|
## Credenciais
|
||||||
|
|
||||||
|
Uma Credential HTTP (Bearer/Header Auth) no n8n, só com o
|
||||||
|
`ZPRO_API_TOKEN`. `baseUrl`/`apiId` ficam no node `Config ZPRO` — não são
|
||||||
|
segredo, precisam só ficar visíveis/editáveis por clínica ao duplicar o
|
||||||
|
conjunto de workflows.
|
||||||
|
|
||||||
|
## Fora de escopo (adiado)
|
||||||
|
|
||||||
|
- Klingo, ClinicAll, SysLife via este mesmo padrão — replicar depois que o
|
||||||
|
Z-PRO nativo estiver validado.
|
||||||
|
- O monorepo TypeScript (`packages/*-mcp`) fica pausado, não descartado.
|
||||||
|
- `consultar_horarios` continua não suportado pro Z-PRO (mesma decisão de
|
||||||
|
produto já tomada, sem mudança).
|
||||||
|
|
||||||
|
## Testes
|
||||||
|
|
||||||
|
Sem testes automatizados (workflows do n8n, não código com framework de
|
||||||
|
teste). Validação manual, seguindo a mesma disciplina já usada no projeto
|
||||||
|
inteiro: dado fictício, execução única por vez, conferência visual no
|
||||||
|
Z-PRO antes de qualquer nova tentativa — evitar duplicar agendamento
|
||||||
|
durante os testes desta migração.
|
||||||
Reference in New Issue
Block a user