- 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>
165 lines
8.8 KiB
Markdown
165 lines
8.8 KiB
Markdown
# 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.
|