Snapshot: gti-scheduling-mcp (Z-PRO + Klingo adapters) e workflow n8n de agendamento funcionando de ponta a ponta

- gti-scheduling-mcp: MCP server com ZProAdapter e KlingoAdapter (agendar() completo pros dois)
- Workflow n8n 'Agendamento - GChat - Z-PRO': webhook -> AI Agent -> MCP -> Z-PRO, testado com sucesso real
- Documentacao: specs, plano, runbook de problemas reais e export do workflow

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Gustavo
2026-08-10 17:23:10 -03:00
co-authored by Claude Sonnet 5
commit 257afe98c0
48 changed files with 12465 additions and 0 deletions
@@ -0,0 +1,164 @@
# Design — Workflow n8n de Agendamento via GChat/Z-PRO + gti-scheduling-mcp
**Data:** 2026-08-10
**Status:** Aprovado pelo usuário, aguardando plano de implementação.
## Objetivo
Construir o primeiro workflow n8n que recebe mensagens de clientes via
GChat (webhook do Z-PRO), conduz a conversa com um agente de IA para
capturar os dados necessários e realiza o agendamento de fato, chamando a
tool `agendar` do `gti-scheduling-mcp` (que por sua vez delega ao Adapter
do sistema da clínica — Z-PRO neste MVP).
Escopo do MVP: **só agendamento** (`agendar`). Consulta de disponibilidade,
cancelamento e remarcação ficam fora desta etapa.
## Contexto verificado (não inventado)
Estes fatos vêm de um workflow real já em produção no n8n de referência
("Enforcer - GLPI"/fluxo de suporte via Z-PRO, código do node `1 - Decide`
compartilhado pelo usuário) e de consultas diretas ao n8n
(`devn8n.gtigrupo.com.br`) e ao registro de nodes via `n8n-mcp`:
- O Z-PRO chama o webhook do n8n **uma vez por mensagem do cliente** — não
agrupa/enfileira mensagens.
- O corpo da requisição (`req = $json.body`) tem os campos: `step`
(esperado `"process"`), `entrada` (texto da mensagem do cliente),
`number` (telefone), `contactName`, `protocol` (identificador único do
**atendimento**, não do telefone — o mesmo cliente pode ter vários
atendimentos/protocolos ao longo do tempo).
- **Se o workflow segurar a resposta** (esperando mais mensagens antes de
responder), o Z-PRO **descarta** as mensagens seguintes do cliente
(confirmado em teste real: 5 mensagens em sequência → 1 execução no
n8n). O workflow precisa responder a cada execução, sempre.
- A resposta ao Z-PRO é **texto puro** (não JSON), via node `Respond to
Webhook` em modo texto.
- O node oficial `MCP Client Tool` (`@n8n/n8n-nodes-langchain`) só suporta
transporte HTTP Streamable/SSE — **não** suporta rodar um comando local
via stdio.
- O node comunitário `n8n-nodes-mcp` (`mcpClient`/`mcpClientTool`) suporta
conexão via linha de comando (stdio) — é o caminho escolhido para não
precisar alterar o transporte do `gti-scheduling-mcp` (que hoje só
implementa `StdioServerTransport`).
- O `gti-scheduling-mcp` (`ZProAdapter`/`KlingoAdapter`) já está pronto e
testado para `agendar()` — nenhuma mudança de arquitetura nele é
necessária para este workflow.
## Arquitetura
```
[Cliente WhatsApp]
│
▼
[Z-PRO/GChat] ──webhook──▶ [n8n: Webhook] → [Normalizar entrada] → [AI Agent] → [Respond to Webhook]
│ ▲
(tool call) │ │ (memória de sessão)
▼ │
[MCP Client Tool] [Simple Memory]
(stdio, agendar) (sessionId = protocol)
│
▼
[gti-scheduling-mcp: tool "agendar"]
│
▼
[AdapterFactory → ZProAdapter/KlingoAdapter]
│
▼
[Sistema real da clínica: Z-PRO/Klingo]
```
O `gti-scheduling-mcp` não sofre nenhuma alteração de arquitetura para
este workflow — o n8n é só mais um cliente MCP, como qualquer outro.
## Componentes (nós do n8n)
1. **Webhook (Z-PRO)** — `POST`, recebe `{step, entrada, number,
contactName, protocol}`.
2. **Normalizar entrada** (`Set`/`Code`) —
- Valida `step === "process"`; caso contrário, responde com um texto
mínimo e encerra (mesma defesa do fluxo de referência).
- Monta as variáveis usadas a seguir: `sessionId = protocol`,
`mensagem = entrada`, `nomeContato = contactName`, `telefone =
number`.
- **Nó de configuração da clínica** (fixo por cópia do workflow, não
dinâmico em runtime): `provider` (ex.: `"zpro"`), `clinicId`, e
referência de qual Credential do n8n / config do MCP Client Tool
usar para esta clínica. Cada clínica nova = uma cópia deste workflow
com esses valores ajustados e seu próprio webhook cadastrado no
Z-PRO — não há branching dinâmico de provider dentro de uma mesma
execução.
3. **AI Agent** (`@n8n/n8n-nodes-langchain.agent`) —
- Chat Model: OpenAI (credencial a configurar no n8n).
- System prompt cobre: confirmar o nome completo do paciente (mesmo já
tendo `contactName`), perguntar data/horário desejado, motivo
(opcional), nunca chamar `agendar` mais de uma vez por atendimento,
responder sempre em português, tom cordial, nunca inventar dado que
o cliente não informou.
- **Memória**: `Simple Memory` (`memoryBufferWindow`), `sessionId =
protocol`. Trade-off aceito para o MVP: essa memória vive na RAM do
processo do n8n — um restart do n8n no meio de um atendimento perde
o histórico da conversa. Evolução futura, se necessário: Postgres ou
Redis Chat Memory (durável, mas exige infraestrutura adicional).
- **Tool**: `MCP Client Tool` (via `n8n-nodes-mcp`, transporte stdio),
expondo a tool `agendar` do `gti-scheduling-mcp` (comando: `node
dist/index.js`, variáveis de ambiente = credenciais da clínica,
vindas de uma Credential do n8n — nunca hardcoded no node/JSON do
workflow).
4. **Respond to Webhook** — modo texto simples; devolve só a resposta em
linguagem natural produzida pelo AI Agent.
## Tratamento de erro
Quando `agendar` falha (`VALIDATION_ERROR`, `AUTHENTICATION_ERROR`,
`NOT_FOUND`, `ZPRO_API_ERROR`/`KLINGO_API_ERROR`, timeout, etc.), o MCP já
devolve uma resposta estruturada (`success:false` + código/mensagem) — o
AI Agent recebe isso como resultado da tool e decide, em linguagem
natural, como comunicar isso ao cliente (pedir os dados de novo, avisar
que vai encaminhar para um atendente humano, etc.), dentro do que o
system prompt permitir. Não há tratamento hard-coded por código de erro
neste workflow — isso fica deliberadamente a cargo do agente, para manter
o MVP simples.
## Risco de agendamento duplicado (mitigação no nível do workflow)
O `ZProAdapter`/`KlingoAdapter` já trata qualquer HTTP 2xx do provider
como sucesso operacional (sem risco de duplicidade por reinterpretação de
resposta ambígua — ver `docs/zpro-api-mapping.md`). O risco adicional
neste workflow é de outra natureza: o **próprio agente** decidir chamar a
tool `agendar` mais de uma vez na mesma conversa (ex.: o cliente confirma
duas vezes, ou o agente se confunde). Mitigação adotada para o MVP:
instrução explícita no system prompt para nunca chamar `agendar` mais de
uma vez por atendimento (`protocol`). Isto é uma mitigação por prompt, não
uma garantia determinística — se isso se mostrar insuficiente em uso real,
a evolução natural é adicionar uma marcação de "já agendado" no estado da
sessão, verificada por código antes de permitir uma nova chamada da tool.
## Fora de escopo (explicitamente adiado)
- Consulta de disponibilidade (`consultar_horarios`) — não implementada
para nenhum provider neste MVP (Z-PRO não suporta; Klingo tem lacuna de
mapeamento de resposta).
- Cancelamento/remarcação de agendamento.
- Transferência automática de fila/atendimento humano no Z-PRO após o
agendamento (padrão existente no fluxo de referência via
`updateticketinfo`) — pode ser adicionado depois, não é necessário para
o MVP funcionar.
- Suporte a múltiplas clínicas com providers diferentes atendidas por uma
única execução/webhook compartilhado — cada clínica é uma cópia
dedicada do workflow.
- Memória de conversa durável entre restarts do n8n (Postgres/Redis Chat
Memory).
## Testes
Este workflow vive no n8n, fora do repositório `gti-scheduling-mcp` — não
há testes automatizados de código aqui. A validação é funcional/manual:
- Testar o fluxo completo com uma conversa real (ou simulada via chamada
direta ao webhook) contra o Z-PRO, com dados fictícios, seguindo a mesma
disciplina de segurança contra duplicidade já usada nos testes manuais
do `ZProAdapter` (execução única, verificação visual no Z-PRO antes de
qualquer nova tentativa).
- Confirmar que o `Respond to Webhook` devolve texto puro, sem envelope
JSON, compatível com o que o Z-PRO espera exibir ao cliente.