Compare commits

...
10 Commits
Author SHA1 Message Date
GustavoandClaude Sonnet 5 5748888997 chore: add repository ignore rules
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 15:25:59 -03:00
GustavoandClaude Sonnet 5 e614763023 docs: registra incidentes de producao Z-PRO (endpoint MCP, horario passado, investigacao midia)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 22:17:13 -03:00
GustavoandClaude Sonnet 5 d873ee02dd docs: adiciona inventário geral dos workflows de exemplo (agendamento + confirmação, 4 providers)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:45:11 -03:00
GustavoandClaude Sonnet 5 da3b38551f docs: registra workflows de exemplo de AI Agent para agendamento (Klingo, ClinicAll, SysLife)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:39:30 -03:00
GustavoandClaude Sonnet 5 c9ffc580d6 Plano: workflows de exemplo de AI Agent para agendamento (Klingo, ClinicAll, SysLife)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:36:54 -03:00
GustavoandClaude Sonnet 5 e5f3d27230 Spec: workflows de exemplo de AI Agent para agendamento (Klingo, ClinicAll, SysLife)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:35:00 -03:00
GustavoandClaude Sonnet 5 69b34ead9e docs: adiciona resumo comparativo da confirmação de agenda nos 4 providers
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:27:17 -03:00
GustavoandClaude Sonnet 5 1e2b93c7be docs: registra MCP SysLife Confirmação e confirmação de agenda via WhatsApp
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:25:29 -03:00
GustavoandClaude Sonnet 5 48efbe478b Plano: confirmação de agenda via WhatsApp (SysLife)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:21:10 -03:00
GustavoandClaude Sonnet 5 f3e513a73a Spec: confirmação de agenda via WhatsApp (SysLife)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 16:17:35 -03:00
7 changed files with 1869 additions and 1 deletions
+25
View File
@@ -0,0 +1,25 @@
# Environment
.env
.env.*
!.env.example
# Dependencies / build output
node_modules/
dist/
# Logs
*.log
# OS / editor
.DS_Store
Thumbs.db
.vscode/
.idea/
# Temp / cache
*.tmp
*.bak
.cache/
# Documentação local de fornecedor aguardando revisão antes de versionamento
docs/API Clinicall.pdf
Binary file not shown.
+312 -1
View File
@@ -9,7 +9,21 @@
> nativo do n8n). A seção 14 cobre os outros três providers — **Klingo**,
> **SysLife** e **ClinicAll** — todos construídos com o mesmo padrão de
> MCP Server nativo, mas ainda sem clínica real pra testar (ver cada
> subseção pras specs/planos completos e pendências específicas).
> subseção pras specs/planos completos e pendências específicas). As
> seções 15-17 cobrem features transversais do Z-PRO (config de IA via
> Google Docs, memória via Postgres, MCP de mensageria standalone). As
> seções 18-20 cobrem a feature de **confirmação de agenda via
> WhatsApp**, replicada nos três providers adicionais (Klingo,
> ClinicAll, SysLife) — ver o resumo comparativo na seção 21. A seção 22
> cobre os workflows de exemplo de AI Agent para **agendamento** desses
> mesmos três providers (fechando a lacuna que só a confirmação tinha
> preenchido) — ver o inventário geral de todos os workflows de exemplo
> (agendamento + confirmação, nos 4 providers) no final da seção 22. A
> seção 23 registra três bugs reais encontrados em produção no Z-PRO
> depois que o gestor da clínica editou o AI Agent pela UI (endpoint MCP
> revertido pro servidor errado, agendamento em horário já passado) e o
> estado da investigação sobre suporte a imagem/áudio (ainda sem
> solução — depende do painel admin do Z-PRO).
## 1. Node MCP: qual usar e como instalar
@@ -800,3 +814,300 @@ exemplo, prontos pra ativar quando houver clínica ClinicAll real —
falta resolver a autenticação (mesma pendência do MVP de agendamento),
preencher o `baseUrl` real, e provisionar banco Postgres + credencial
pro cliente.
## 20. Confirmação de Agenda via WhatsApp (SysLife)
**Data:** 11/08/2026. Ver design completo em
`docs/superpowers/specs/2026-08-11-confirmacao-agenda-syslife-design.md`
e plano em
`docs/superpowers/plans/2026-08-11-confirmacao-agenda-syslife.md`.
**Motivação**: mesmo objetivo das seções 18 (Klingo) e 19 (ClinicAll),
agora para o SysLife. O recurso relevante, `AgendaWSApp`, já vem
descrito no manual (`Manual WS SysLife V3.4.pdf`, salvo em
`docs/Manual WS SysLife V3.4 (1).pdf`, relido nesta sessão — não
estava commitado no repositório antes) explicitamente como "retorna os
registros da agenda **para uso do WhatsApp**".
**MCP Server "SysLife - Confirmação de Agenda"** (`xq8CyqyewtENpIMW`) — 3 tools:
| Tool | Endpoint | Parâmetro | Workflow id |
| --- | --- | --- | --- |
| `listar_agendamentos_do_dia` | `GET /AgendaWSApp` | `QuantidadeDias` | `ezcqDpU4R4LuHldj` |
| `buscar_agendamento_por_telefone` | `GET /AgendaWSApp` | `NumeroCelular` | `sTLFa6VyUkBnM8C0` |
| `confirmar_presenca` | `POST /AgendaWSApp` | `CodigoAgenda` + `Resposta` (`"1"`/`"2"`) | `Pv0BbagqdeoBgENZ` |
**Ponto único deste provider**: um mesmo `GET /AgendaWSApp` serve três
propósitos diferentes conforme qual dos três parâmetros é enviado
(`QuantidadeDias`, `CodigoAgenda` ou `NumeroCelular` — o manual é
explícito: **"Deverá ser usado somente um dos 3 parâmetros"**). Duas
tools deste MCP (`listar_agendamentos_do_dia`,
`buscar_agendamento_por_telefone`) apontam pro mesmo endpoint via
sub-workflows diferentes, cada um montando só o parâmetro que lhe
cabe.
**Diferenças reais em relação a Klingo e ClinicAll**:
- **Autenticação já resolvida de verdade**: diferente dos outros dois,
a credencial Basic Auth (`httpBasicAuth`, `u8XXJ6wyrKuGJp4Y`,
`SysLife Basic Auth - clínica pendente`) **já existia**, criada
durante o MVP de agendamento do SysLife — usuário/senha fixos do
WebService, documentados literalmente no manual, não variam por
clínica. Foi só reaproveitada, nenhuma credencial nova criada.
- **`Resposta` é o mais simples dos três providers**: só `"1"` (SIM)
ou `"2"` (NÃO), documentado direto no manual — sem precisar de tools
de tabela de domínio como no ClinicAll, nem terceiro estado
("Sem Resposta") como no Klingo.
- **Resposta já vem com texto formatado pro WhatsApp**: os campos
`txWhatsappProcedimento`/`txWhatsappHorario`/`txWhatsappMedico` já
vêm prontos do próprio SysLife — usados no workflow de lembrete com
fallback pros campos brutos quando ausentes.
- **Telefone é campo direto do item** (`nuCelular`/`nuCelularDdd`),
sem objeto `Paciente` aninhado como no ClinicAll.
- **Fora de escopo**: `AgendaCentral` (central telefônica, não
WhatsApp — mesmo raciocínio do `/entrada` do Klingo), `AgendaRetorno`
(consultas de retorno), `AgendaStatus` (base pra NPS, sem endpoint
de submissão documentado), `AgendaConfirmado` (só consulta
informativa, sem ação).
**Workflow proativo "Lembrete de Confirmação - SysLife (exemplo)"**
(`LpRRZxTsM0Vc9PsV`): cron 8h → `listar_agendamentos_do_dia`
(`quantidadeDias: 1`, literal fixo — o próprio SysLife já calcula
"amanhã" a partir desse número, sem precisar de node de cálculo de
data) → loop → `enviar_texto` do MCP Mensageria ZPRO. Validado (0
erros), deixado **inativo de propósito**.
**Workflow de exemplo "Confirmação de Agenda - GChat - SysLife+Z-PRO
(exemplo)"** (`wBjXOZSEj5TopzfB`): mesmo padrão dos outros dois
(webhook → AI Agent → memória Postgres), `systemMessage` ajustado pro
fluxo mais simples (telefone → `buscar_agendamento_por_telefone` →
`confirmar_presenca` com `resposta: "1"`/`"2"`). Tools conectadas:
`buscar_agendamento_por_telefone`, `confirmar_presenca`
(`listar_agendamentos_do_dia` só serve ao workflow proativo). Validado
(0 erros), deixado **inativo de propósito**.
**Resultado**: MCP Server de confirmação de agenda (SysLife) completo
e validado estruturalmente, junto com os dois workflows de exemplo,
prontos pra ativar quando houver clínica SysLife real — diferente dos
outros dois providers, a autenticação já está pronta; falta só
preencher o `baseUrl` real (IP:9000) e provisionar banco Postgres +
credencial pro cliente. Com isso, os 4 providers (Z-PRO em produção
real, Klingo, ClinicAll, SysLife estruturalmente prontos) têm o mesmo
padrão de confirmação de agenda implementado.
## 21. Resumo — Confirmação de Agenda via WhatsApp nos 4 providers
Visão consolidada das seções 18-20 (Z-PRO usa a mensageria própria da
clínica exemplo, sem MCP de confirmação dedicado — a confirmação lá
seria uma extensão futura do AI Agent já em produção, não construída
nesta rodada).
| | **Klingo** | **ClinicAll** | **SysLife** |
| --- | --- | --- | --- |
| API/recurso | Klingo Telefonia (separada da de agendamento) | `TCalendarController`/`TDomainController` (mesma do agendamento) | `AgendaWSApp` (mesma API do agendamento) |
| Endpoint de confirmação | `POST /confirmar` | `POST /AgendamentoFlags` | `POST /AgendaWSApp` |
| Valor de confirmação | `status`: `"C"`/`"S"`/`"N"` (3 estados) | `estadoAgenda`+`situacaoAgenda`: strings longas exatas (tabela de domínio) | `Resposta`: `"1"`/`"2"` (2 estados, mais simples) |
| Busca de pendente | `GET /lista_ultimo_por_cpf` (CPF) | `GET /agendamentoSemPaciente` (CPF **+** data de nascimento) | `GET /AgendaWSApp` (telefone) |
| Autenticação | `X-APP-TOKEN` por clínica (token real confirmado, sem clínica de teste) | Não documentada (`authentication: none`, mesma pendência do MVP de agendamento) | **Já resolvida** — Basic Auth fixo, credencial reaproveitada do MVP de agendamento |
| Tools no MCP Server | 6 | 5 | 3 |
| Workflow servidor | `tSw2LGlOYVg9antR` | `lHU5H0cZP4BJ6dWp` | `xq8CyqyewtENpIMW` |
| Lembrete proativo (exemplo, inativo) | `IvLzmASwa9LGaMxf` | `liBLpRUmbcnWk05V` | `LpRRZxTsM0Vc9PsV` |
| AI Agent de exemplo (inativo) | `F5jEliFFE3K9cW14` | `ylc3Jcz239ra6XZK` | `wBjXOZSEj5TopzfB` |
**Padrão idêntico nos três**: `MCP Server Trigger` + N sub-workflows
(`Execute Workflow Trigger` → `Config` → montagem de request → `HTTP
Request` com `neverError`+`fullResponse` → `Classificar resultado`
com taxonomia genérica por status HTTP); workflow proativo de lembrete
via cron 8h chamando o MCP de Mensageria ZPRO (`enviar_texto`); workflow
de exemplo de AI Agent reativo (webhook Z-PRO/GChat → `AI Agent` com
`Postgres Chat Memory` → tools via `MCP Client Tool`) — os dois últimos
sempre criados **inativos de propósito**, já que nenhum dos três tem
clínica real disponível pra testar.
**Pendência comum aos três**: nenhum foi testado com chamada HTTP real.
Falta, por provider, quando houver clínica real: preencher `baseUrl`,
resolver autenticação (só pendente no Klingo — sem clínica de teste — e
no ClinicAll — sem mecanismo documentado; o SysLife já está resolvido),
provisionar banco Postgres + credencial, e então ativar os workflows de
lembrete e de AI Agent de exemplo.
## 22. Workflows de exemplo de AI Agent para Agendamento (Klingo, ClinicAll, SysLife)
**Data:** 11/08/2026. Ver design completo em
`docs/superpowers/specs/2026-08-11-workflows-exemplo-agente-agendamento-design.md`
e plano em
`docs/superpowers/plans/2026-08-11-workflows-exemplo-agente-agendamento.md`.
**Motivação**: os MCP Servers de agendamento do Klingo, ClinicAll e
SysLife (seção 14) existiam há tempo, mas nenhum tinha um workflow de
agente cliente — diferente da confirmação de agenda (seções 18-20), que
já nasceu com seu próprio exemplo. Esta seção fecha essa lacuna,
seguindo exatamente o mesmo esqueleto dos exemplos de confirmação
(webhook Z-PRO/GChat → `AI Agent` com `OpenAI Chat Model` real +
`Postgres Chat Memory` placeholder), mas conectando nas tools de
**agendamento** — decisão explícita do usuário de manter os dois
propósitos (agendar vs. confirmar) em agentes de exemplo separados por
enquanto, mesmo padrão do Z-PRO em produção (que também só tem
agendamento).
**Correção de contagem de tools**: durante o brainstorming desta
feature, o Klingo tinha sido citado por engano como tendo 8 tools de
agendamento (confundindo com as 6 tools da API de Telefonia usada na
confirmação, seção 18). Conferido direto no design real
(`docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-klingo-design.md`):
o MCP de agendamento do Klingo tem só **2 tools**
(`consultar_horarios`, `agendar`). ClinicAll tem 8, SysLife tem 7 —
esses dois já estavam corretos.
**Limitação real do Klingo, herdada por este exemplo**:
`consultar_horarios` sempre retorna `SLOT_MAPPING_UNAVAILABLE` — a API
do Klingo responde com sucesso, mas não documenta publicamente o
formato de cada horário individual, então `agendar` (que exige um
`slotId`) não tem como ser alimentado por essa integração hoje. Decisão
explícita do usuário: construir o exemplo mesmo assim, com o
`systemMessage` avisando o agente pra informar essa indisponibilidade
ao paciente em vez de inventar um horário — não é um bug desta
implementação, é uma lacuna documentada da API do Klingo (já registrada
na seção 14.1).
| Provider | Workflow de exemplo | Tools conectadas | MCP Server consumido |
| --- | --- | --- | --- |
| Klingo | `Agendamento - GChat - Klingo (exemplo)` (`ToilBwbsSdXMCvCI`) | 2 (`consultar_horarios`, `agendar`) | `3eiFEnfOTLnutP78` |
| ClinicAll | `Agendamento - GChat - ClinicAll (exemplo)` (`6E7dXKtG68mN8Xkv`) | 8 (todas) | `igaKjoHcPNYRAxPS` |
| SysLife | `Agendamento - GChat - SysLife (exemplo)` (`6tylTUf0CAWTnrhD`) | 7 (todas) | `TYu78UqIUr2yCBHK` |
Diferente dos exemplos de confirmação (que filtravam tools específicas
via `includeTools`), o `MCP Client Tool` dos três usa `include: "all"`
— o agente de agendamento precisa de todas as tools do provider pra
completar um fluxo de ponta a ponta. Nenhum sub-workflow de tool foi
criado ou modificado — só os 3 workflows de agente e a conexão via
`MCP Client Tool` aos servidores já existentes.
Validados estruturalmente (0 erros nos três), deixados **inativos de
propósito** — sem clínica real de nenhum dos três providers nem
credencial Postgres válida, ativá-los só geraria execuções com erro.
### Inventário geral — workflows de exemplo nos 4 providers
Com esta seção, os 4 providers passam a ter cobertura simétrica: cada
um com um caminho de **agendamento** e um de **confirmação de agenda**,
seja em produção real (só o Z-PRO) ou como esqueleto de exemplo pronto
pra duplicar (os outros três).
| Provider | Agendamento | Confirmação de agenda |
| --- | --- | --- |
| **Z-PRO** | `Agendamento - GChat - Z-PRO (clínica exemplo)` (`yG2mi6ECBpPv4Hmn`) — **produção real, ativo** | Não construída ainda — fica pra quando for demandada |
| **Klingo** | `Agendamento - GChat - Klingo (exemplo)` (`ToilBwbsSdXMCvCI`) — exemplo, inativo | `Confirmação de Agenda - GChat - Klingo+Z-PRO (exemplo)` (`F5jEliFFE3K9cW14`) — exemplo, inativo |
| **ClinicAll** | `Agendamento - GChat - ClinicAll (exemplo)` (`6E7dXKtG68mN8Xkv`) — exemplo, inativo | `Confirmação de Agenda - GChat - ClinicAll+Z-PRO (exemplo)` (`ylc3Jcz239ra6XZK`) — exemplo, inativo |
| **SysLife** | `Agendamento - GChat - SysLife (exemplo)` (`6tylTUf0CAWTnrhD`) — exemplo, inativo | `Confirmação de Agenda - GChat - SysLife+Z-PRO (exemplo)` (`wBjXOZSEj5TopzfB`) — exemplo, inativo |
Todos os seis workflows de exemplo (Klingo/ClinicAll/SysLife ×
agendamento/confirmação) seguem o mesmo esqueleto: `Webhook` (contrato
Z-PRO/GChat, seção 6) → `AI Agent` com `OpenAI Chat Model` (credencial
real e compartilhada `29vMIDah5DTIhUYJ`, "GPT") + `Postgres Chat
Memory` (credencial placeholder) + tools via `MCP Client Tool`
apontando pro respectivo MCP Server nativo já construído. Nenhum foi
ativado nem testado com chamada HTTP real — cada um fica pronto pra
duplicar assim que a clínica real correspondente e o banco Postgres do
cliente existirem.
## 23. Incidentes reais em produção (Z-PRO, 17/08/2026) — edição manual pela UI
Depois que o gestor da clínica exemplo editou o node `AI Agent` e o
`OpenAI Chat Model` diretamente pela UI do n8n (troca de modelo), o
agendamento em produção (`Agendamento - GChat - Z-PRO (clínica
exemplo)`, `yG2mi6ECBpPv4Hmn`) parou de funcionar. Três problemas reais
foram encontrados e corrigidos, nesta ordem:
### 23.1. `endpointUrl` do MCP Client Tool revertido pro servidor errado
**Sintoma**: toda mensagem caía no branch de erro padrão ("Desculpe,
tive um problema técnico..."). Execução mostrava
`"error": "Error in sub-node MCP - ZPRO (nativo n8n)"` /
`"Could not connect to your MCP server"`.
**Causa raiz**: o node `MCP - ZPRO (nativo n8n)` (o único `MCP Client
Tool` conectado ao AI Agent deste workflow) apontava pro endpoint de
**teste** do MCP de Mensageria
(`https://devn8n.gtigrupo.com.br/mcp-test/mcp-server-mensageria-zpro`)
em vez do MCP de **agendamento** de produção
(`https://devn8n.gtigrupo.com.br/mcp/mcp-server-zpro-clinica-exemplo`,
servidor `MCP Server - ZPRO` / `qjSaKllvneBIZ7mC`, tools `agendar` +
`consultar_horarios`). Confirmado via execução `248` (12/08, um dia
antes) que o agendamento real só funciona com esse endpoint correto —
o node havia sido apontado pro MCP errado (mensageria, não
agendamento) durante uma edição manual, e a correção foi **revertida
duas vezes** só de reabrir/salvar o node do modelo pela UI (o editor
recarrega o valor antigo em cache do campo `endpointUrl` e resalva o
workflow inteiro).
**Fix**: `endpointUrl` corrigido pra
`https://devn8n.gtigrupo.com.br/mcp/mcp-server-zpro-clinica-exemplo`.
**Risco de recorrência real** — documentado como aviso pro
gestor: qualquer edição futura do `AI Agent`/`OpenAI Chat Model` pela
UI deve conferir esse campo antes de salvar.
### 23.2. Modelo trocado para `gpt-5.6-luna`
O gestor trocou o modelo do `OpenAI Chat Model` de `gpt-4.1-mini` para
`gpt-5.6-luna` (veio do dropdown de modelos da credencial "GPT",
`cachedResultName` igual ao `value` — não foi digitado à mão). Mantido
a pedido do usuário; não identificado como causa de nenhum dos bugs
desta seção (o erro de conexão MCP acontece antes de qualquer chamada
ao modelo).
### 23.3. Agendamento aceito em horário já passado
**Sintoma**: paciente pediu "17/08 as 8:30" às 11:48 (mesmo dia) e o
agente agendou sem objeção, mesmo com o horário já tendo passado.
**Causa raiz**: nem o `systemMessage` do `AI Agent` nem o doc de
prompt da clínica (Google Docs) tinham qualquer regra comparando o
horário pedido com o horário atual — só validavam dia da semana e
horário comercial (seção 3 do doc). O `systemMessage` calculava
`$now` só com **data**, sem hora, então o modelo não tinha como
comparar.
**Fix**: `systemMessage` do `AI Agent` alterado para incluir data
**e hora** atuais (`yyyy-MM-dd (cccc) HH:mm`) e nova regra 8: nunca
agendar num horário já passado — comparar com o horário atual antes de
confirmar/agendar, e pedir outro horário se o pedido já passou.
Também revisado o doc de prompt da clínica (`docId`
`1NmYRIoF7yD_B6N160_6Bpfv4NyJiryTTO2LFr9xNlYY`, Google Docs) pra
remover a exigência de "consultar disponibilidade antes de agendar"
(o Z-PRO não oferece essa consulta — nunca ofereceu, mesmo nos
agendamentos que funcionaram — então a regra original só confundia o
modelo sem nunca ter sido cumprível).
### 23.4. Investigação em aberto — suporte a imagem/áudio (sem solução ainda)
Pedido do usuário: fazer o AI Agent entender imagens e áudios enviados
pelo paciente no WhatsApp. Testado enviando uma imagem e um áudio reais
pro número de produção:
- **Confirmado por teste direto**: o webhook `Webhook Z-PRO` recebe
ambos exatamente como uma mensagem de texto vazia —
`{"step":"process","entrada":"","number":...,"contactName":...,"protocol":...}`
— sem nenhum campo de mídia, URL, base64 ou tipo de mensagem.
- **Descartado como evidência**: uma mensagem encontrada num ticket
antigo ("No momento, consigo processar apenas mensagens em texto...")
**não é** um aviso de sistema do Z-PRO — vem do chatFlow nativo
`id 78`, nomeado **"GUSTAVO"**, criado em 14/07/2026 dentro do próprio
painel de chatbot do Z-PRO. É texto escrito manualmente por alguém da
equipe num flow separado, não evidência da API.
- A collection pública do Postman do Z-PRO
(`postman.com/comunidade-zdg/z-pro/collection/ksvu6vu`) documenta só
a API de saída (enviar mensagem, criar ticket, `appointment/*`,
etc.) — não tem nenhum endpoint de webhook de entrada nem de busca
de mídia recebida.
- Pista não seguida: o objeto de ticket retornado por
`showticketchatbot` tem campos `n8nStatus`/`n8nUrl` (hoje `false`/
`null` no ticket testado), sugerindo que o Z-PRO tem alguma
configuração de integração com n8n por ticket/canal cujas opções não
foram investigadas.
**Pendência real**: confirmar no painel administrativo do Z-PRO (quem
tem acesso) se a configuração do webhook usado por este workflow
(`agendamento-zpro-clinica-exemplo`) tem alguma opção pra incluir mídia
no payload. Sem isso, a feature de entender imagem/áudio não é
implementável só editando o workflow do n8n.
@@ -0,0 +1,792 @@
# Confirmação de Agenda via WhatsApp (SysLife) Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task (não subagent-driven-development — as tasks são chamadas de API do n8n via MCP, não commits de código; não há diff de git pra revisar por task). Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Construir o MCP Server "SysLife - Confirmação de Agenda" (3 tools) + o workflow proativo de lembrete de confirmação (cron diário) + um workflow de exemplo de AI Agent reativo que confirma presença via WhatsApp, todos estruturalmente validados (0 erros), sem clínica SysLife real disponível para teste de ponta a ponta — mesmo padrão já executado para Klingo (`docs/superpowers/plans/2026-08-11-confirmacao-agenda-klingo.md`) e ClinicAll (`docs/superpowers/plans/2026-08-11-confirmacao-agenda-clinicall.md`).
**Architecture:** Mesmo padrão de MCP Server nativo n8n dos outros providers: `MCP Server Trigger` + N × `Call n8n Sub-Workflow Tool`, cada um apontando pra um sub-workflow `Execute Workflow Trigger` → `Config SysLife` → `Montar query`/`Montar corpo` (Code) → `HTTP Request` → `Classificar resultado` (Code). Reaproveita **exatamente** o estilo de node já usado no MVP de agendamento do SysLife (`MCP Server - SysLife - consultar_horarios`, `GCbnkMM1JTnVXRSr`, lido nesta sessão como referência): `HTTP Request` com `authentication: "genericCredentialType"` + `genericAuthType: "httpBasicAuth"`, credencial `httpBasicAuth` já existente (`u8XXJ6wyrKuGJp4Y`), `sendBody: true` mesmo em métodos GET (documentado assim no manual do SysLife). O recurso `AgendaWSApp` é único e serve três propósitos diferentes conforme o parâmetro enviado — duas tools deste MCP (`listar_agendamentos_do_dia`, `buscar_agendamento_por_telefone`) apontam pra sub-workflows distintos que chamam o mesmo endpoint com parâmetros diferentes. O workflow de lembrete chama a tool via `Execute Workflow` direto (sem IA), reaproveitando o MCP de Mensageria (Z-PRO) já validado. O workflow de exemplo reativo usa `AI Agent` + `Postgres Chat Memory` + tools do MCP SysLife via `MCP Client Tool`.
**Tech Stack:** n8n (`devn8n.gtigrupo.com.br`), MCP tools do n8n (`n8n_create_workflow`, `n8n_update_partial_workflow`, `n8n_validate_workflow`, `n8n_get_workflow`), SysLife WebService (`http://<IP>:9000/AgendaWSApp`, Basic Auth), MCP Server - Mensageria ZPRO (`WsL4RlSD0hZ34gpB` → sub-workflow `enviar_texto` `Y4ndG7GuIUrmVRxV`, já em produção).
## Global Constraints
- Nenhum campo de request/response é inventado — usar só os campos confirmados no manual (`docs/Manual WS SysLife V3.4 (1).pdf`).
- **Credencial Basic Auth já existe e é reaproveitada**: `httpBasicAuth`, id `u8XXJ6wyrKuGJp4Y`, nome `SysLife Basic Auth - clínica pendente` — usuário/senha fixos do WebService (`WebSysLife`/`$Sys10Life`), documentados literalmente no manual, não variam por clínica. `baseUrl` fica com o mesmo placeholder já usado nos sub-workflows do MVP de agendamento: `"http://SUBSTITUIR-PELO-IP-REAL-DA-CLINICA:9000"`.
- **Lição da seção 17 do runbook — `$fromAI` só com um único `=` no início**: ao montar `workflowInputs.value` dos nodes `Call n8n Sub-Workflow Tool` do servidor, cada expressão deve ser exatamente `"={{ $fromAI(...) }}"` (um `=`). Como este plano cria os nodes via `n8n_create_workflow` diretamente, o bug do `==` duplicado não deve ocorrer — conferir mesmo assim com `n8n_get_workflow` (mode `filtered`) antes de validar.
- **Campos opcionais precisam de valor-padrão no `$fromAI`**: `$fromAI('nome', 'descrição', 'tipo', valorPadrão)` — senão o schema gerado da tool trata o campo como obrigatório. Neste plano, todos os campos das 3 tools são obrigatórios (o manual não documenta nenhum campo opcional em `AgendaWSApp`), então nenhum `$fromAI` precisa de 4º argumento — mas confira mesmo assim.
- Operações que trocam node + conexões devem ser feitas numa única chamada `n8n_update_partial_workflow`.
- Todo workflow (servidor + sub-workflows) precisa estar `active: true` para responder via protocolo MCP.
- Taxonomia de erro padrão (idêntica à já usada no MVP de agendamento do SysLife): `AUTHENTICATION_ERROR` (401/403), `NOT_FOUND` (404), `VALIDATION_ERROR` (400/422), `SYSLIFE_API_ERROR` (demais).
- `AgendaCentral`, `AgendaRetorno`, `AgendaStatus`, `AgendaConfirmado` ficam **fora de escopo** — não implementar tools para esses endpoints.
- **Regra do manual**: `GET /AgendaWSApp` aceita `QuantidadeDias` **ou** `CodigoAgenda` **ou** `NumeroCelular` — nunca mais de um ao mesmo tempo. Cada sub-workflow de leitura deste plano monta o body só com o parâmetro que lhe cabe, nunca os dois.
Spec de referência: `docs/superpowers/specs/2026-08-11-confirmacao-agenda-syslife-design.md`
---
## Campos confirmados no manual (`docs/Manual WS SysLife V3.4 (1).pdf`, já lido nesta sessão)
### `GET /AgendaWSApp`
- Body: **um único** de `QuantidadeDias` (number), `CodigoAgenda` (number) ou `NumeroCelular` (string, DDD + número).
- Resposta: array de objetos com `coAgenda`, `dtAtendimento`, `hrAtendimentoAlterado`, `nmPaciente`, `nmLogonWeb`, `nmSenhaWeb`, `coMedico`, `txTituloMedico`, `nmMedico`, `nmEspecialidade`, `nmOrigemDestino`, `coProcedimento`, `nmProcedimento`, `nuTelefone`, `nuTelefoneDdd`, `nuCelular`, `nuCelularDdd`, `txObservacao`, `txInstrucaoProc`, `txWhatsappProcedimento`, `txWhatsappHorario`, `txWhatsappMedico`, `txEndereco`, `txBairro`, `txComplemento`, `txCidade`, `txEstado`, `nmMsgSms`, `nmMsgSmsExtra`.
### `POST /AgendaWSApp`
- Body: `CodigoAgenda` (number, obrigatório), `Resposta` (string, obrigatório — `"1"` = SIM, `"2"` = NÃO).
- Resposta: `{ "Status": "?" }` (mensagem de sucesso ou erro).
---
## Pré-requisito
Nenhum — a credencial Basic Auth já existe no n8n (`u8XXJ6wyrKuGJp4Y`), criada durante o MVP de agendamento do SysLife. Quando houver clínica real: preencher o `baseUrl` real (IP:9000) nos 3 sub-workflows.
---
### Task 1: Sub-workflow `listar_agendamentos_do_dia`
**Interfaces:**
- Consumes: nenhuma.
- Produces: workflow `MCP Server - SysLife - Confirmação - listar_agendamentos_do_dia`, consumido pela Task 4 (servidor) e pela Task 6 (lembrete proativo).
- [ ] **Step 1: Criar o sub-workflow**
`n8n_create_workflow`:
```json
{
"name": "MCP Server - SysLife - Confirmação - listar_agendamentos_do_dia",
"nodes": [
{
"id": "trigger",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [0, 0],
"parameters": {
"workflowInputs": { "values": [{ "name": "quantidadeDias", "type": "number" }] }
}
},
{
"id": "config",
"name": "Config SysLife",
"type": "n8n-nodes-base.set",
"typeVersion": 3.5,
"position": [260, 0],
"parameters": {
"mode": "manual",
"includeOtherFields": true,
"assignments": {
"assignments": [
{ "id": "cfg-baseurl", "name": "baseUrl", "type": "string", "value": "http://SUBSTITUIR-PELO-IP-REAL-DA-CLINICA:9000" }
]
}
}
},
{
"id": "montar-query",
"name": "Montar query",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [520, 0],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const input = $json;\nreturn {\n json: {\n baseUrl: input.baseUrl,\n queryBody: {\n QuantidadeDias: input.quantidadeDias,\n },\n },\n};"
}
},
{
"id": "get-agendawsapp",
"name": "GET /AgendaWSApp",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [780, 0],
"parameters": {
"method": "GET",
"url": "={{ $json.baseUrl }}/AgendaWSApp",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"contentType": "json",
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify($json.queryBody) }}",
"options": {
"response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
"timeout": 15000
}
},
"credentials": {
"httpBasicAuth": { "id": "u8XXJ6wyrKuGJp4Y", "name": "SysLife Basic Auth - clínica pendente" }
}
},
{
"id": "classificar",
"name": "Classificar resultado",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1040, 0],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const status = $json.statusCode;\nconst rawBody = $json.body;\n\nfunction classifyError(status, context) {\n if (status === 401 || status === 403) {\n return { code: \"AUTHENTICATION_ERROR\", message: `Falha de autenticação na API do SysLife ao ${context} (status ${status}).` };\n }\n if (status === 404) {\n return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do SysLife ao ${context} (status ${status}).` };\n }\n if (status === 400 || status === 422) {\n return { code: \"VALIDATION_ERROR\", message: `A API do SysLife rejeitou os dados enviados ao ${context} (status ${status}).` };\n }\n return { code: \"SYSLIFE_API_ERROR\", message: `A API do SysLife retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n return { json: { success: false, error: classifyError(status, \"listar agendamentos do dia\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
}
}
],
"connections": {
"Execute Workflow Trigger": { "main": [[{ "node": "Config SysLife", "type": "main", "index": 0 }]] },
"Config SysLife": { "main": [[{ "node": "Montar query", "type": "main", "index": 0 }]] },
"Montar query": { "main": [[{ "node": "GET /AgendaWSApp", "type": "main", "index": 0 }]] },
"GET /AgendaWSApp": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
}
}
```
Anotar o `id` retornado — necessário nas Tasks 4 e 6.
- [ ] **Step 2: Validar**
`n8n_validate_workflow` com o id retornado. Esperado: `errorCount: 0`.
---
### Task 2: Sub-workflow `buscar_agendamento_por_telefone`
**Interfaces:**
- Consumes: nenhuma.
- Produces: workflow `MCP Server - SysLife - Confirmação - buscar_agendamento_por_telefone`, consumido pela Task 4 e pelo workflow de exemplo (Task 7).
- [ ] **Step 1: Criar o sub-workflow**
`n8n_create_workflow`:
```json
{
"name": "MCP Server - SysLife - Confirmação - buscar_agendamento_por_telefone",
"nodes": [
{
"id": "trigger",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [0, 0],
"parameters": {
"workflowInputs": { "values": [{ "name": "numeroCelular", "type": "string" }] }
}
},
{
"id": "config",
"name": "Config SysLife",
"type": "n8n-nodes-base.set",
"typeVersion": 3.5,
"position": [260, 0],
"parameters": {
"mode": "manual",
"includeOtherFields": true,
"assignments": {
"assignments": [
{ "id": "cfg-baseurl", "name": "baseUrl", "type": "string", "value": "http://SUBSTITUIR-PELO-IP-REAL-DA-CLINICA:9000" }
]
}
}
},
{
"id": "montar-query",
"name": "Montar query",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [520, 0],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const input = $json;\nreturn {\n json: {\n baseUrl: input.baseUrl,\n queryBody: {\n NumeroCelular: input.numeroCelular,\n },\n },\n};"
}
},
{
"id": "get-agendawsapp",
"name": "GET /AgendaWSApp",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [780, 0],
"parameters": {
"method": "GET",
"url": "={{ $json.baseUrl }}/AgendaWSApp",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"contentType": "json",
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify($json.queryBody) }}",
"options": {
"response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
"timeout": 15000
}
},
"credentials": {
"httpBasicAuth": { "id": "u8XXJ6wyrKuGJp4Y", "name": "SysLife Basic Auth - clínica pendente" }
}
},
{
"id": "classificar",
"name": "Classificar resultado",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1040, 0],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const status = $json.statusCode;\nconst rawBody = $json.body;\n\nfunction classifyError(status, context) {\n if (status === 401 || status === 403) {\n return { code: \"AUTHENTICATION_ERROR\", message: `Falha de autenticação na API do SysLife ao ${context} (status ${status}).` };\n }\n if (status === 404) {\n return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do SysLife ao ${context} (status ${status}).` };\n }\n if (status === 400 || status === 422) {\n return { code: \"VALIDATION_ERROR\", message: `A API do SysLife rejeitou os dados enviados ao ${context} (status ${status}).` };\n }\n return { code: \"SYSLIFE_API_ERROR\", message: `A API do SysLife retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n return { json: { success: false, error: classifyError(status, \"buscar agendamento por telefone\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
}
}
],
"connections": {
"Execute Workflow Trigger": { "main": [[{ "node": "Config SysLife", "type": "main", "index": 0 }]] },
"Config SysLife": { "main": [[{ "node": "Montar query", "type": "main", "index": 0 }]] },
"Montar query": { "main": [[{ "node": "GET /AgendaWSApp", "type": "main", "index": 0 }]] },
"GET /AgendaWSApp": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
}
}
```
Anotar o `id` retornado.
- [ ] **Step 2: Validar**
`n8n_validate_workflow` com o id retornado. Esperado: `errorCount: 0`.
---
### Task 3: Sub-workflow `confirmar_presenca`
**Interfaces:**
- Consumes: nenhuma.
- Produces: workflow `MCP Server - SysLife - Confirmação - confirmar_presenca`, consumido pela Task 4 e pelo workflow de exemplo (Task 7).
- [ ] **Step 1: Criar o sub-workflow**
`n8n_create_workflow`:
```json
{
"name": "MCP Server - SysLife - Confirmação - confirmar_presenca",
"nodes": [
{
"id": "trigger",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [0, 0],
"parameters": {
"workflowInputs": {
"values": [
{ "name": "codigoAgenda", "type": "number" },
{ "name": "resposta", "type": "string" }
]
}
}
},
{
"id": "config",
"name": "Config SysLife",
"type": "n8n-nodes-base.set",
"typeVersion": 3.5,
"position": [260, 0],
"parameters": {
"mode": "manual",
"includeOtherFields": true,
"assignments": {
"assignments": [
{ "id": "cfg-baseurl", "name": "baseUrl", "type": "string", "value": "http://SUBSTITUIR-PELO-IP-REAL-DA-CLINICA:9000" }
]
}
}
},
{
"id": "montar-corpo",
"name": "Montar corpo",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [520, 0],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const input = $json;\nreturn {\n json: {\n baseUrl: input.baseUrl,\n requestBody: {\n CodigoAgenda: input.codigoAgenda,\n Resposta: input.resposta,\n },\n },\n};"
}
},
{
"id": "post-agendawsapp",
"name": "POST /AgendaWSApp",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [780, 0],
"parameters": {
"method": "POST",
"url": "={{ $json.baseUrl }}/AgendaWSApp",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"contentType": "json",
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify($json.requestBody) }}",
"options": {
"response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
"timeout": 15000
}
},
"credentials": {
"httpBasicAuth": { "id": "u8XXJ6wyrKuGJp4Y", "name": "SysLife Basic Auth - clínica pendente" }
}
},
{
"id": "classificar",
"name": "Classificar resultado",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1040, 0],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const status = $json.statusCode;\nconst rawBody = $json.body;\n\nfunction classifyError(status, context) {\n if (status === 401 || status === 403) {\n return { code: \"AUTHENTICATION_ERROR\", message: `Falha de autenticação na API do SysLife ao ${context} (status ${status}).` };\n }\n if (status === 404) {\n return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do SysLife ao ${context} (status ${status}).` };\n }\n if (status === 400 || status === 422) {\n return { code: \"VALIDATION_ERROR\", message: `A API do SysLife rejeitou os dados enviados ao ${context} (status ${status}).` };\n }\n return { code: \"SYSLIFE_API_ERROR\", message: `A API do SysLife retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n return { json: { success: false, error: classifyError(status, \"confirmar presença\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
}
}
],
"connections": {
"Execute Workflow Trigger": { "main": [[{ "node": "Config SysLife", "type": "main", "index": 0 }]] },
"Config SysLife": { "main": [[{ "node": "Montar corpo", "type": "main", "index": 0 }]] },
"Montar corpo": { "main": [[{ "node": "POST /AgendaWSApp", "type": "main", "index": 0 }]] },
"POST /AgendaWSApp": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
}
}
```
`resposta` deve ser documentado na `description` da tool (Task 4) como
aceitando só `"1"` (SIM) ou `"2"` (NÃO), conforme o manual.
Anotar o `id` retornado.
- [ ] **Step 2: Validar**
`n8n_validate_workflow` com o id retornado. Esperado: `errorCount: 0`.
---
### Task 4: Servidor MCP "SysLife - Confirmação de Agenda" com as 3 tools
**Interfaces:**
- Consumes: os 3 workflow ids das Tasks 1–3.
- Produces: workflow `MCP Server - SysLife - Confirmação de Agenda` (servidor), path `mcp-server-syslife-confirmacao`, consumido pela Task 7 (workflow de exemplo).
- [ ] **Step 1: Criar o servidor com o `MCP Server Trigger` e os 3 nodes de tool**
`n8n_create_workflow` — substituir `ID_LISTAR`, `ID_BUSCAR_TELEFONE`,
`ID_CONFIRMAR` pelos ids reais anotados nas Tasks 1–3:
```json
{
"name": "MCP Server - SysLife - Confirmação de Agenda",
"nodes": [
{
"id": "mcp-trigger",
"name": "MCP Server Trigger",
"type": "@n8n/n8n-nodes-langchain.mcpTrigger",
"typeVersion": 1,
"position": [0, 256],
"parameters": { "path": "mcp-server-syslife-confirmacao", "authentication": "none" }
},
{
"id": "tool-listar",
"name": "listar_agendamentos_do_dia",
"type": "@n8n/n8n-nodes-langchain.toolWorkflow",
"typeVersion": 2.2,
"position": [-320, 448],
"parameters": {
"description": "Lista os agendamentos de uma data futura no SysLife, contando a partir de hoje. Usado como base do lembrete proativo de confirmação — use quantidadeDias=1 para os agendamentos de amanhã.",
"workflowId": { "value": "ID_LISTAR", "mode": "id" },
"workflowInputs": {
"mappingMode": "defineBelow",
"value": { "quantidadeDias": "={{ $fromAI('quantidadeDias', 'Quantidade de dias a partir de hoje (1 = amanhã, 2 = depois de amanhã, etc.)', 'number') }}" },
"matchingColumns": [],
"schema": [{ "id": "quantidadeDias", "displayName": "quantidadeDias", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "number" }],
"attemptToConvertTypes": false,
"convertFieldsToString": false
}
}
},
{
"id": "tool-buscar-telefone",
"name": "buscar_agendamento_por_telefone",
"type": "@n8n/n8n-nodes-langchain.toolWorkflow",
"typeVersion": 2.2,
"position": [-160, 448],
"parameters": {
"description": "Busca o(s) agendamento(s) pendente(s) de um paciente pelo número de celular (DDD + número, só dígitos). Use isso para descobrir qual agendamento o paciente está confirmando quando ele responde 'sim'/'não'.",
"workflowId": { "value": "ID_BUSCAR_TELEFONE", "mode": "id" },
"workflowInputs": {
"mappingMode": "defineBelow",
"value": { "numeroCelular": "={{ $fromAI('numeroCelular', 'Número de celular do paciente, com DDD, somente dígitos (ex.: 71999999999)', 'string') }}" },
"matchingColumns": [],
"schema": [{ "id": "numeroCelular", "displayName": "numeroCelular", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "string" }],
"attemptToConvertTypes": false,
"convertFieldsToString": false
}
}
},
{
"id": "tool-confirmar",
"name": "confirmar_presenca",
"type": "@n8n/n8n-nodes-langchain.toolWorkflow",
"typeVersion": 2.2,
"position": [0, 448],
"parameters": {
"description": "Registra a confirmação de presença de um agendamento no SysLife. resposta deve ser exatamente '1' (paciente confirmou) ou '2' (paciente não confirmou/recusou) — nenhum outro valor é aceito. Use depois de identificar o codigoAgenda correto (ex.: via buscar_agendamento_por_telefone).",
"workflowId": { "value": "ID_CONFIRMAR", "mode": "id" },
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"codigoAgenda": "={{ $fromAI('codigoAgenda', 'Código do agendamento (coAgenda) a confirmar', 'number') }}",
"resposta": "={{ $fromAI('resposta', \"'1' se o paciente confirmou presença, '2' se recusou/não vai comparecer\", 'string') }}"
},
"matchingColumns": [],
"schema": [
{ "id": "codigoAgenda", "displayName": "codigoAgenda", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "number" },
{ "id": "resposta", "displayName": "resposta", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "string" }
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
}
}
}
],
"connections": {
"listar_agendamentos_do_dia": { "ai_tool": [[{ "node": "MCP Server Trigger", "type": "ai_tool", "index": 0 }]] },
"buscar_agendamento_por_telefone": { "ai_tool": [[{ "node": "MCP Server Trigger", "type": "ai_tool", "index": 0 }]] },
"confirmar_presenca": { "ai_tool": [[{ "node": "MCP Server Trigger", "type": "ai_tool", "index": 0 }]] }
}
}
```
Anotar o `id` do servidor retornado — necessário na Task 7.
- [ ] **Step 2: Conferir visualmente os textos salvos dos `$fromAI`**
`n8n_get_workflow` com `{"id": "<id do servidor>", "mode": "filtered", "nodeNames": ["listar_agendamentos_do_dia", "buscar_agendamento_por_telefone", "confirmar_presenca"]}`. Conferir que cada valor de `workflowInputs.value` começa com um único `=` (não `==`).
- [ ] **Step 3: Validar**
`n8n_validate_workflow` com o id do servidor. Esperado: `errorCount: 0`.
---
### Task 5: Ativar os 4 workflows do MCP Server
**Interfaces:**
- Consumes: os 4 workflow ids (3 sub-workflows das Tasks 1–3 + servidor da Task 4).
- Produces: MCP Server "SysLife - Confirmação de Agenda" respondendo via protocolo MCP.
- [ ] **Step 1: Ativar cada um dos 4 workflows**
Para cada um dos 4 ids (3 sub-workflows + servidor), rodar
`n8n_update_partial_workflow` com `{"id": "<id>", "operations": [{"type": "activateWorkflow"}]}`.
- [ ] **Step 2: Confirmar ativação**
`n8n_get_workflow` com `mode: "minimal"` em cada um dos 4 ids —
confirmar `"active": true` em todos.
---
### Task 6: Workflow proativo "Lembrete de Confirmação - SysLife (exemplo)"
**Interfaces:**
- Consumes: workflow `listar_agendamentos_do_dia` (Task 1) via `Execute Workflow`; tool `enviar_texto` do MCP de Mensageria ZPRO (`Y4ndG7GuIUrmVRxV`, já em produção) via `Execute Workflow`.
- Produces: workflow `Lembrete de Confirmação - SysLife (exemplo)`.
- [ ] **Step 1: Criar o workflow**
`n8n_create_workflow` — substituir `ID_LISTAR_AGENDAMENTOS` pelo id
anotado na Task 1:
```json
{
"name": "Lembrete de Confirmação - SysLife (exemplo)",
"nodes": [
{
"id": "cron",
"name": "Cron 8h diário",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [0, 0],
"parameters": {
"rule": { "interval": [{ "field": "cronExpression", "expression": "0 8 * * *" }] }
}
},
{
"id": "listar",
"name": "Listar agendamentos de amanhã",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [224, 0],
"parameters": {
"workflowId": { "value": "ID_LISTAR_AGENDAMENTOS", "mode": "id" },
"workflowInputs": {
"mappingMode": "defineBelow",
"value": { "quantidadeDias": 1 }
}
}
},
{
"id": "extrair-lista",
"name": "Extrair lista de agendamentos",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [448, 0],
"parameters": {
"jsCode": "const result = $input.item.json;\nif (!result.success) {\n throw new Error('Falha ao listar agendamentos do dia: ' + JSON.stringify(result.error));\n}\nconst agendamentos = Array.isArray(result.data) ? result.data : [];\nreturn agendamentos.map(a => ({ json: a }));"
}
},
{
"id": "montar-mensagem",
"name": "Montar mensagem de lembrete",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [672, 0],
"parameters": {
"assignments": {
"assignments": [
{ "name": "numeroWhatsapp", "type": "string", "value": "={{ $json.nuCelularDdd }}{{ $json.nuCelular }}" },
{ "name": "textoLembrete", "type": "string", "value": "=Olá, {{ $json.nmPaciente }}! Passando para confirmar sua consulta{{ $json.txWhatsappProcedimento ? ' de ' + $json.txWhatsappProcedimento : ($json.nmProcedimento ? ' de ' + $json.nmProcedimento : '') }}{{ $json.txWhatsappMedico ? ' com ' + $json.txWhatsappMedico : ($json.nmMedico ? ' com ' + $json.nmMedico : '') }}{{ $json.txWhatsappHorario ? ' em ' + $json.txWhatsappHorario : ' em ' + $json.dtAtendimento + ' às ' + $json.hrAtendimentoAlterado }}. Você confirma presença? Responda SIM ou NÃO." },
{ "name": "externalKey", "type": "string", "value": "=lembrete-syslife-{{ $json.coAgenda }}" }
]
},
"includeOtherFields": true
}
},
{
"id": "enviar",
"name": "Enviar lembrete via Mensageria ZPRO",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [896, 0],
"parameters": {
"workflowId": { "value": "Y4ndG7GuIUrmVRxV", "mode": "id" },
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"number": "={{ $json.numeroWhatsapp }}",
"body": "={{ $json.textoLembrete }}",
"externalKey": "={{ $json.externalKey }}"
}
}
}
}
],
"connections": {
"Cron 8h diário": { "main": [[{ "node": "Listar agendamentos de amanhã", "type": "main", "index": 0 }]] },
"Listar agendamentos de amanhã": { "main": [[{ "node": "Extrair lista de agendamentos", "type": "main", "index": 0 }]] },
"Extrair lista de agendamentos": { "main": [[{ "node": "Montar mensagem de lembrete", "type": "main", "index": 0 }]] },
"Montar mensagem de lembrete": { "main": [[{ "node": "Enviar lembrete via Mensageria ZPRO", "type": "main", "index": 0 }]] }
}
}
```
Nota: `quantidadeDias: 1` é passado como literal fixo (não expressão) —
diferente do Klingo/ClinicAll, o SysLife já calcula "amanhã" no próprio
servidor a partir desse número, então não precisa de um node
`Calcular data` separado. Telefone montado direto de
`nuCelularDdd`+`nuCelular` do próprio item (sem objeto aninhado,
diferente do ClinicAll). O texto usa os campos já formatados pro
WhatsApp (`txWhatsappProcedimento`/`txWhatsappMedico`/
`txWhatsappHorario`) quando presentes, com fallback pros campos brutos
(`nmProcedimento`/`nmMedico`/`dtAtendimento`+`hrAtendimentoAlterado`).
- [ ] **Step 2: Validar**
`n8n_validate_workflow` com o id retornado. Esperado: `errorCount: 0`.
- [ ] **Step 3: Deixar inativo**
Mesma razão do Klingo e do ClinicAll — sem clínica SysLife real, um
cron ativo geraria chamadas reais com erro contra a API e tentativas
de envio com dados vazios. Ativação fica para quando houver clínica
real (a credencial Basic Auth já existe; só falta o `baseUrl`).
---
### Task 7: Workflow de exemplo "AI Agent — Confirmação SysLife (exemplo)"
**Interfaces:**
- Consumes: workflow servidor `MCP Server - SysLife - Confirmação de Agenda` (Task 4, id do servidor).
- Produces: workflow `Confirmação de Agenda - GChat - SysLife+Z-PRO (exemplo)`.
- [ ] **Step 1: Criar o workflow de exemplo**
`n8n_create_workflow` — mesmo contrato de webhook Z-PRO/GChat já usado
nos exemplos do Klingo e do ClinicAll (`body.protocol`→`sessionId`,
`body.entrada`→`mensagem`, `body.contactName`→`nomeContato`,
`body.number`→`telefone`), mesma credencial OpenAI real e
compartilhada (`29vMIDah5DTIhUYJ`, "GPT"):
```json
{
"name": "Confirmação de Agenda - GChat - SysLife+Z-PRO (exemplo)",
"nodes": [
{
"id": "webhook",
"name": "Webhook GChat",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [0, 0],
"parameters": { "httpMethod": "POST", "path": "confirmacao-agenda-syslife-exemplo", "responseMode": "lastNode", "options": {} }
},
{
"id": "extrair-campos",
"name": "Extrair campos do webhook",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [224, 0],
"parameters": {
"assignments": {
"assignments": [
{ "name": "sessionId", "type": "string", "value": "={{ $json.body.protocol }}" },
{ "name": "mensagem", "type": "string", "value": "={{ String($json.body.entrada || '').trim() }}" },
{ "name": "nomeContato", "type": "string", "value": "={{ $json.body.contactName }}" },
{ "name": "telefone", "type": "string", "value": "={{ $json.body.number }}" }
]
}
}
},
{
"id": "ai-agent",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2.1,
"position": [448, 0],
"parameters": {
"text": "={{ $json.mensagem }}",
"systemMessage": "Você é um assistente de confirmação de presença em consultas médicas, via WhatsApp, para uma clínica que usa o sistema SysLife. Seu trabalho: 1) entender se a mensagem do paciente é uma resposta de confirmação (ex.: 'sim', 'confirmo') ou recusa (ex.: 'não', 'não posso ir') a uma consulta agendada; 2) se for, use o telefone do paciente (o telefone do contato do WhatsApp já está disponível — {{ $json.telefone }} — mas confirme com o paciente se não tiver certeza) e chame a tool buscar_agendamento_por_telefone para achar o codigoAgenda pendente; 3) chame confirmar_presenca com esse codigoAgenda e resposta='1' (se o paciente confirmou) ou resposta='2' (se recusou) — nenhum outro valor de resposta é aceito; 4) responda ao paciente confirmando que o registro foi feito. Se a mensagem não for uma resposta de confirmação/recusa clara, peça esclarecimento. Nunca invente um codigoAgenda — sempre busque antes de confirmar."
}
},
{
"id": "openai-chat-model",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [448, -160],
"parameters": { "model": { "mode": "id", "value": "gpt-4o-mini" }, "builtInTools": {}, "options": {} },
"credentials": { "openAiApi": { "id": "29vMIDah5DTIhUYJ", "name": "GPT" } }
},
{
"id": "memoria",
"name": "Memória da Sessão (Postgres)",
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"typeVersion": 1.4,
"position": [448, 160],
"parameters": { "sessionIdType": "customKey", "sessionKey": "={{ $json.sessionId }}", "tableName": "n8n_chat_histories", "contextWindowLength": 20 },
"credentials": { "postgres": { "id": "PLACEHOLDER_SEM_CREDENCIAL", "name": "Postgres - (sem cliente real)" } }
}
],
"connections": {
"Webhook GChat": { "main": [[{ "node": "Extrair campos do webhook", "type": "main", "index": 0 }]] },
"Extrair campos do webhook": { "main": [[{ "node": "AI Agent", "type": "main", "index": 0 }]] },
"OpenAI Chat Model": { "ai_languageModel": [[{ "node": "AI Agent", "type": "ai_languageModel", "index": 0 }]] },
"Memória da Sessão (Postgres)": { "ai_memory": [[{ "node": "AI Agent", "type": "ai_memory", "index": 0 }]] }
}
}
```
Anotar o `id` retornado.
- [ ] **Step 2: Validar**
`n8n_validate_workflow` com o id retornado. Esperado: `errorCount: 0`
(a credencial `postgres` é placeholder — aceitável, sem cliente real).
---
### Task 8: Conectar as tools do MCP SysLife ao AI Agent de exemplo
**Interfaces:**
- Consumes: workflow servidor `MCP Server - SysLife - Confirmação de Agenda` (Task 4, id do servidor) e workflow `Confirmação de Agenda - GChat - SysLife+Z-PRO (exemplo)` (Task 7).
- Produces: `AI Agent` do workflow de exemplo com acesso às tools `buscar_agendamento_por_telefone` e `confirmar_presenca` via `MCP Client Tool`.
- [ ] **Step 1: Adicionar o node `MCP Client Tool` conectado ao AI Agent**
`n8n_update_partial_workflow` no workflow da Task 7, numa única chamada
atômica:
```json
{
"id": "<id do workflow da Task 7>",
"operations": [
{
"type": "addNode",
"node": {
"id": "mcp-client-syslife-confirmacao",
"name": "MCP SysLife Confirmação",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"typeVersion": 1,
"position": [448, 320],
"parameters": {
"endpointUrl": "https://devn8n.gtigrupo.com.br/mcp/mcp-server-syslife-confirmacao",
"authentication": "none",
"include": "selected",
"includeTools": ["buscar_agendamento_por_telefone", "confirmar_presenca"]
}
}
},
{ "type": "addConnection", "source": "MCP SysLife Confirmação", "target": "AI Agent", "sourceOutput": "ai_tool", "targetIndex": 0 }
]
}
```
- [ ] **Step 2: Validar**
`n8n_validate_workflow` no workflow da Task 7. Esperado: `errorCount: 0`.
- [ ] **Step 3: Deixar inativo**
Mesma razão das outras tasks — sem credencial Postgres real nem
clínica SysLife real, ativar não teria efeito útil. Fica pronto pra
ativar quando houver cliente real.
---
### Task 9: Atualizar o runbook e commit
**Interfaces:**
- Consumes: todos os ids de workflow criados nas Tasks 1–8.
- [ ] **Step 1: Adicionar seção 20 ao runbook**
Adicionar em `docs/n8n-agendamento-runbook.md`, após a seção 19, uma
seção "20. Confirmação de Agenda via WhatsApp (SysLife)" cobrindo: as
3 tools do MCP Server e seus endpoints (com destaque pro fato de
`GET /AgendaWSApp` servir três propósitos via parâmetro exclusivo), os
ids de todos os 7 workflows criados (3 sub-workflows + servidor +
lembrete proativo + AI Agent de exemplo), a nota de que a credencial
Basic Auth já existe e foi reaproveitada do MVP de agendamento (não
precisou criar nada novo), a simplicidade do enum `Resposta` (`"1"`/`"2"`,
sem terceiro estado como no Klingo e sem strings longas como no
ClinicAll), e o status "estrutura pronta, sem teste de ponta a ponta —
falta só o `baseUrl` real de uma clínica". Seguir o mesmo estilo de
prosa das seções 14, 17, 18 e 19.
- [ ] **Step 2: Commit**
```bash
cd "D:\PROJETOS\KLINGO-CLINICAL-SYSLIFE-GCHAT-AGENDAMENTO"
git add docs/n8n-agendamento-runbook.md
git commit -m "docs: registra MCP SysLife Confirmação e confirmação de agenda via WhatsApp
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>"
```
---
## Observação sobre execução
Mesma disciplina dos planos anteriores: validar
(`n8n_validate_workflow`) depois de cada workflow criado/modificado, e
conferir visualmente o texto salvo de qualquer expressão `$fromAI`
antes de considerar uma tool pronta (Task 4, Step 2). Os workflows de
lembrete proativo (Task 6) e de AI Agent de exemplo (Tasks 7–8) ficam
**intencionalmente inativos** ao final deste plano — sem clínica
SysLife real (mesmo com a credencial Basic Auth já pronta, falta o
`baseUrl` real) e sem credencial Postgres válida, ativá-los só geraria
execuções com erro. Diferente do Klingo e do ClinicAll, este é o único
dos três providers de confirmação onde a autenticação **já está
resolvida** (credencial `httpBasicAuth` `u8XXJ6wyrKuGJp4Y` reaproveitada
do MVP de agendamento) — só falta o endereço da clínica real pra testar
de ponta a ponta.
@@ -0,0 +1,428 @@
# Workflows de Exemplo de AI Agent para Agendamento (Klingo, ClinicAll, SysLife) Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task (não subagent-driven-development — as tasks são chamadas de API do n8n via MCP, não commits de código; não há diff de git pra revisar por task). Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Construir 3 workflows de exemplo de AI Agent (um por provider — Klingo, ClinicAll, SysLife), cada um conectando via webhook Z-PRO/GChat num agente conversacional com acesso a todas as tools do respectivo MCP Server de agendamento já existente, todos validados estruturalmente (0 erros) e deixados **inativos de propósito** (sem clínica real de nenhum dos três providers).
**Architecture:** Réplica do esqueleto já usado nos 3 workflows de exemplo de confirmação de agenda (Klingo/ClinicAll/SysLife, seções 18-20 do runbook): `Webhook` (contrato Z-PRO/GChat) → `Extrair campos do webhook` (`Set`) → `AI Agent` com `OpenAI Chat Model` (credencial real compartilhada) + `Postgres Chat Memory` (credencial placeholder) + `MCP Client Tool` conectado ao MCP Server de agendamento do provider, com `include: "all"` (diferente dos exemplos de confirmação, que filtravam tools específicas — aqui o agente precisa de todas as tools do provider pra completar um agendamento). Nenhum sub-workflow novo é criado — os MCP Servers de agendamento já existem e são só referenciados pela URL do endpoint MCP.
**Tech Stack:** n8n (`devn8n.gtigrupo.com.br`), MCP tools do n8n (`n8n_create_workflow`, `n8n_update_partial_workflow`, `n8n_validate_workflow`), MCP Servers de agendamento já existentes (Klingo `3eiFEnfOTLnutP78`, ClinicAll `igaKjoHcPNYRAxPS`, SysLife `TYu78UqIUr2yCBHK`).
## Global Constraints
- Nenhum sub-workflow de tool é criado ou modificado nesta rodada — só os 3 workflows de agente e a conexão `MCP Client Tool` que aponta pros servidores já existentes.
- Contrato do webhook Z-PRO/GChat idêntico ao já documentado na seção 6 do runbook e reaproveitado nos 3 exemplos de confirmação: `body.protocol`→`sessionId`, `body.entrada`→`mensagem`, `body.contactName`→`nomeContato`, `body.number`→`telefone`.
- `OpenAI Chat Model` usa a credencial real e compartilhada já em uso em produção e nos exemplos de confirmação: `openAiApi` id `29vMIDah5DTIhUYJ`, nome "GPT" — não é credencial inventada.
- `Postgres Chat Memory` usa credencial placeholder (`PLACEHOLDER_SEM_CREDENCIAL`) — sem cliente real, sem banco provisionado, mesma disciplina dos exemplos de confirmação.
- `MCP Client Tool` de cada workflow usa `include: "all"` (não `"selected"` como nos exemplos de confirmação) — o agente de agendamento precisa de todas as tools do provider pra completar um fluxo de ponta a ponta.
- Webhook paths distintos por provider, pra não colidir entre si nem com os exemplos de confirmação já existentes: `agendamento-klingo-exemplo`, `agendamento-clinicall-exemplo`, `agendamento-syslife-exemplo`.
- Os 3 workflows ficam **inativos de propósito** ao final deste plano — sem clínica real de nenhum provider e sem credencial Postgres válida, ativá-los só geraria execuções com erro.
- O `systemMessage` do agente do Klingo precisa avisar explicitamente sobre a limitação real conhecida: `consultar_horarios` sempre retorna `SLOT_MAPPING_UNAVAILABLE` — o agente deve informar isso ao paciente em vez de inventar horários ou tentar chamar `agendar` sem um `slotId` real.
Spec de referência: `docs/superpowers/specs/2026-08-11-workflows-exemplo-agente-agendamento-design.md`
---
### Task 1: Workflow de exemplo "Agendamento - GChat - Klingo (exemplo)"
**Interfaces:**
- Consumes: MCP Server de agendamento Klingo (`3eiFEnfOTLnutP78`, path `mcp-server-klingo`, tools `consultar_horarios` + `agendar`).
- Produces: workflow `Agendamento - GChat - Klingo (exemplo)`.
- [ ] **Step 1: Criar o workflow (webhook + AI Agent + modelo + memória)**
`n8n_create_workflow`:
```json
{
"name": "Agendamento - GChat - Klingo (exemplo)",
"nodes": [
{
"id": "webhook",
"name": "Webhook GChat",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [0, 0],
"parameters": { "httpMethod": "POST", "path": "agendamento-klingo-exemplo", "responseMode": "lastNode", "options": {} }
},
{
"id": "extrair-campos",
"name": "Extrair campos do webhook",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [224, 0],
"parameters": {
"assignments": {
"assignments": [
{ "name": "sessionId", "type": "string", "value": "={{ $json.body.protocol }}" },
{ "name": "mensagem", "type": "string", "value": "={{ String($json.body.entrada || '').trim() }}" },
{ "name": "nomeContato", "type": "string", "value": "={{ $json.body.contactName }}" },
{ "name": "telefone", "type": "string", "value": "={{ $json.body.number }}" }
]
}
}
},
{
"id": "ai-agent",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2.1,
"position": [448, 0],
"parameters": {
"text": "={{ $json.mensagem }}",
"systemMessage": "Você é um assistente de agendamento de consultas médicas, via WhatsApp, para uma clínica que usa o sistema Klingo. Seu trabalho: 1) entender o que o paciente quer agendar; 2) usar a tool consultar_horarios para ver horários disponíveis. ATENÇÃO — limitação real conhecida desta integração: consultar_horarios pode retornar o erro SLOT_MAPPING_UNAVAILABLE, porque a API do Klingo não documenta publicamente o formato de cada horário individual. Se isso acontecer, informe educadamente ao paciente que a consulta de horários está temporariamente indisponível por essa integração e que ele será atendido de outra forma — nunca invente um horário nem um slotId; 3) se consultar_horarios funcionar e devolver um slotId real, use a tool agendar com esse slotId e os demais dados do paciente para concluir o agendamento; 4) responda sempre em português, de forma clara e cordial."
}
},
{
"id": "openai-chat-model",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [448, -160],
"parameters": { "model": { "mode": "id", "value": "gpt-4o-mini" }, "builtInTools": {}, "options": {} },
"credentials": { "openAiApi": { "id": "29vMIDah5DTIhUYJ", "name": "GPT" } }
},
{
"id": "memoria",
"name": "Memória da Sessão (Postgres)",
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"typeVersion": 1.4,
"position": [448, 160],
"parameters": { "sessionIdType": "customKey", "sessionKey": "={{ $json.sessionId }}", "tableName": "n8n_chat_histories", "contextWindowLength": 20 },
"credentials": { "postgres": { "id": "PLACEHOLDER_SEM_CREDENCIAL", "name": "Postgres - (sem cliente real)" } }
}
],
"connections": {
"Webhook GChat": { "main": [[{ "node": "Extrair campos do webhook", "type": "main", "index": 0 }]] },
"Extrair campos do webhook": { "main": [[{ "node": "AI Agent", "type": "main", "index": 0 }]] },
"OpenAI Chat Model": { "ai_languageModel": [[{ "node": "AI Agent", "type": "ai_languageModel", "index": 0 }]] },
"Memória da Sessão (Postgres)": { "ai_memory": [[{ "node": "AI Agent", "type": "ai_memory", "index": 0 }]] }
}
}
```
Anotar o `id` retornado.
- [ ] **Step 2: Conectar o MCP Client Tool com todas as tools do MCP Klingo**
`n8n_update_partial_workflow`, numa única chamada atômica:
```json
{
"id": "<id do workflow do Step 1>",
"operations": [
{
"type": "addNode",
"node": {
"id": "mcp-client-klingo-agendamento",
"name": "MCP Klingo Agendamento",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"typeVersion": 1,
"position": [448, 320],
"parameters": {
"endpointUrl": "https://devn8n.gtigrupo.com.br/mcp/mcp-server-klingo",
"authentication": "none",
"include": "all"
}
}
},
{ "type": "addConnection", "source": "MCP Klingo Agendamento", "target": "AI Agent", "sourceOutput": "ai_tool", "targetIndex": 0 }
]
}
```
- [ ] **Step 3: Validar**
`n8n_validate_workflow`. Esperado: `errorCount: 0` (warnings de
credencial `postgres` placeholder são aceitáveis).
- [ ] **Step 4: Deixar inativo**
Não ativar — sem clínica Klingo real nem credencial Postgres válida.
---
### Task 2: Workflow de exemplo "Agendamento - GChat - ClinicAll (exemplo)"
**Interfaces:**
- Consumes: MCP Server de agendamento ClinicAll (`igaKjoHcPNYRAxPS`, path `mcp-server-clinicall`, 8 tools).
- Produces: workflow `Agendamento - GChat - ClinicAll (exemplo)`.
- [ ] **Step 1: Criar o workflow (webhook + AI Agent + modelo + memória)**
`n8n_create_workflow`:
```json
{
"name": "Agendamento - GChat - ClinicAll (exemplo)",
"nodes": [
{
"id": "webhook",
"name": "Webhook GChat",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [0, 0],
"parameters": { "httpMethod": "POST", "path": "agendamento-clinicall-exemplo", "responseMode": "lastNode", "options": {} }
},
{
"id": "extrair-campos",
"name": "Extrair campos do webhook",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [224, 0],
"parameters": {
"assignments": {
"assignments": [
{ "name": "sessionId", "type": "string", "value": "={{ $json.body.protocol }}" },
{ "name": "mensagem", "type": "string", "value": "={{ String($json.body.entrada || '').trim() }}" },
{ "name": "nomeContato", "type": "string", "value": "={{ $json.body.contactName }}" },
{ "name": "telefone", "type": "string", "value": "={{ $json.body.number }}" }
]
}
}
},
{
"id": "ai-agent",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2.1,
"position": [448, 0],
"parameters": {
"text": "={{ $json.mensagem }}",
"systemMessage": "Você é um assistente de agendamento de consultas médicas, via WhatsApp, para uma clínica que usa o sistema ClinicAll. Seu trabalho: 1) entender o que o paciente quer agendar (especialidade, convênio, profissional, procedimento), usando as tools especialidade, convenio, profissional e procedimento conforme necessário pra resolver os códigos certos; 2) confirmar/consultar o paciente com a tool paciente; 3) usar consultar_horarios para ver os horários livres de uma unidade+profissional — cada horário livre já é um registro existente, identificado por um idAgenda; 4) para concluir, chamar agendar passando EXATAMENTE o idAgenda do horário livre escolhido no passo anterior — agendar não cria um registro novo do zero, ele concilia (atualiza) esse mesmo idAgenda com os dados do paciente/procedimento/convênio. Nunca invente um idAgenda; 5) responda sempre em português, de forma clara e cordial."
}
},
{
"id": "openai-chat-model",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [448, -160],
"parameters": { "model": { "mode": "id", "value": "gpt-4o-mini" }, "builtInTools": {}, "options": {} },
"credentials": { "openAiApi": { "id": "29vMIDah5DTIhUYJ", "name": "GPT" } }
},
{
"id": "memoria",
"name": "Memória da Sessão (Postgres)",
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"typeVersion": 1.4,
"position": [448, 160],
"parameters": { "sessionIdType": "customKey", "sessionKey": "={{ $json.sessionId }}", "tableName": "n8n_chat_histories", "contextWindowLength": 20 },
"credentials": { "postgres": { "id": "PLACEHOLDER_SEM_CREDENCIAL", "name": "Postgres - (sem cliente real)" } }
}
],
"connections": {
"Webhook GChat": { "main": [[{ "node": "Extrair campos do webhook", "type": "main", "index": 0 }]] },
"Extrair campos do webhook": { "main": [[{ "node": "AI Agent", "type": "main", "index": 0 }]] },
"OpenAI Chat Model": { "ai_languageModel": [[{ "node": "AI Agent", "type": "ai_languageModel", "index": 0 }]] },
"Memória da Sessão (Postgres)": { "ai_memory": [[{ "node": "AI Agent", "type": "ai_memory", "index": 0 }]] }
}
}
```
Anotar o `id` retornado.
- [ ] **Step 2: Conectar o MCP Client Tool com todas as tools do MCP ClinicAll**
`n8n_update_partial_workflow`, numa única chamada atômica:
```json
{
"id": "<id do workflow do Step 1>",
"operations": [
{
"type": "addNode",
"node": {
"id": "mcp-client-clinicall-agendamento",
"name": "MCP ClinicAll Agendamento",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"typeVersion": 1,
"position": [448, 320],
"parameters": {
"endpointUrl": "https://devn8n.gtigrupo.com.br/mcp/mcp-server-clinicall",
"authentication": "none",
"include": "all"
}
}
},
{ "type": "addConnection", "source": "MCP ClinicAll Agendamento", "target": "AI Agent", "sourceOutput": "ai_tool", "targetIndex": 0 }
]
}
```
- [ ] **Step 3: Validar**
`n8n_validate_workflow`. Esperado: `errorCount: 0`.
- [ ] **Step 4: Deixar inativo**
Não ativar — sem clínica ClinicAll real nem credencial Postgres válida.
---
### Task 3: Workflow de exemplo "Agendamento - GChat - SysLife (exemplo)"
**Interfaces:**
- Consumes: MCP Server de agendamento SysLife (`TYu78UqIUr2yCBHK`, path `mcp-server-syslife`, 7 tools).
- Produces: workflow `Agendamento - GChat - SysLife (exemplo)`.
- [ ] **Step 1: Criar o workflow (webhook + AI Agent + modelo + memória)**
`n8n_create_workflow`:
```json
{
"name": "Agendamento - GChat - SysLife (exemplo)",
"nodes": [
{
"id": "webhook",
"name": "Webhook GChat",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [0, 0],
"parameters": { "httpMethod": "POST", "path": "agendamento-syslife-exemplo", "responseMode": "lastNode", "options": {} }
},
{
"id": "extrair-campos",
"name": "Extrair campos do webhook",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [224, 0],
"parameters": {
"assignments": {
"assignments": [
{ "name": "sessionId", "type": "string", "value": "={{ $json.body.protocol }}" },
{ "name": "mensagem", "type": "string", "value": "={{ String($json.body.entrada || '').trim() }}" },
{ "name": "nomeContato", "type": "string", "value": "={{ $json.body.contactName }}" },
{ "name": "telefone", "type": "string", "value": "={{ $json.body.number }}" }
]
}
}
},
{
"id": "ai-agent",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2.1,
"position": [448, 0],
"parameters": {
"text": "={{ $json.mensagem }}",
"systemMessage": "Você é um assistente de agendamento de consultas médicas, via WhatsApp, para uma clínica que usa o sistema SysLife. Siga esta ordem: 1) use a tool especialidade para identificar a especialidade desejada pelo paciente; 2) use a tool medico para listar os médicos daquela especialidade/origem; 3) em qualquer ordem, use as tools convenio, paciente e procedimento conforme necessário pra resolver os códigos de convênio/plano, os dados do paciente (CPF, matrícula ou celular) e o procedimento/valor; 4) use consultar_horarios (tool Horario) para ver os horários disponíveis do médico escolhido; 5) para concluir, chame agendar com todos os códigos já resolvidos nos passos anteriores (data, hora, número da consulta, origem, paciente, convênio, plano, tabela de procedimento, procedimento, médico, especialidade, celular) — nunca invente um código que não veio de uma das tools anteriores; 6) responda sempre em português, de forma clara e cordial."
}
},
{
"id": "openai-chat-model",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [448, -160],
"parameters": { "model": { "mode": "id", "value": "gpt-4o-mini" }, "builtInTools": {}, "options": {} },
"credentials": { "openAiApi": { "id": "29vMIDah5DTIhUYJ", "name": "GPT" } }
},
{
"id": "memoria",
"name": "Memória da Sessão (Postgres)",
"type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
"typeVersion": 1.4,
"position": [448, 160],
"parameters": { "sessionIdType": "customKey", "sessionKey": "={{ $json.sessionId }}", "tableName": "n8n_chat_histories", "contextWindowLength": 20 },
"credentials": { "postgres": { "id": "PLACEHOLDER_SEM_CREDENCIAL", "name": "Postgres - (sem cliente real)" } }
}
],
"connections": {
"Webhook GChat": { "main": [[{ "node": "Extrair campos do webhook", "type": "main", "index": 0 }]] },
"Extrair campos do webhook": { "main": [[{ "node": "AI Agent", "type": "main", "index": 0 }]] },
"OpenAI Chat Model": { "ai_languageModel": [[{ "node": "AI Agent", "type": "ai_languageModel", "index": 0 }]] },
"Memória da Sessão (Postgres)": { "ai_memory": [[{ "node": "AI Agent", "type": "ai_memory", "index": 0 }]] }
}
}
```
Anotar o `id` retornado.
- [ ] **Step 2: Conectar o MCP Client Tool com todas as tools do MCP SysLife**
`n8n_update_partial_workflow`, numa única chamada atômica:
```json
{
"id": "<id do workflow do Step 1>",
"operations": [
{
"type": "addNode",
"node": {
"id": "mcp-client-syslife-agendamento",
"name": "MCP SysLife Agendamento",
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"typeVersion": 1,
"position": [448, 320],
"parameters": {
"endpointUrl": "https://devn8n.gtigrupo.com.br/mcp/mcp-server-syslife",
"authentication": "none",
"include": "all"
}
}
},
{ "type": "addConnection", "source": "MCP SysLife Agendamento", "target": "AI Agent", "sourceOutput": "ai_tool", "targetIndex": 0 }
]
}
```
- [ ] **Step 3: Validar**
`n8n_validate_workflow`. Esperado: `errorCount: 0`.
- [ ] **Step 4: Deixar inativo**
Não ativar — sem clínica SysLife real nem credencial Postgres válida.
---
### Task 4: Atualizar o runbook e commit
**Interfaces:**
- Consumes: os 3 workflow ids criados nas Tasks 1–3.
- [ ] **Step 1: Adicionar seção 22 ao runbook**
Adicionar em `docs/n8n-agendamento-runbook.md`, após a seção 21, uma
seção "22. Workflows de exemplo de AI Agent para Agendamento (Klingo,
ClinicAll, SysLife)" cobrindo: o motivo (os MCP Servers de agendamento
existiam sem workflow de agente cliente, diferente da confirmação),
os 3 ids de workflow criados, a correção do número real de tools de
cada provider (Klingo 2, ClinicAll 8, SysLife 7 — não os 8 do Klingo
Telefonia que tinha sido citado por engano antes), a limitação real do
Klingo (`SLOT_MAPPING_UNAVAILABLE`) e como o `systemMessage` lida com
ela, e o status "estrutura pronta, inativos de propósito — falta
clínica real de qualquer um dos três providers".
- [ ] **Step 2: Atualizar a tabela da seção 21 (opcional, se fizer sentido)**
Adicionar uma linha na tabela comparativa da seção 21 com o id do
workflow de agendamento de exemplo de cada provider, complementando as
linhas já existentes de confirmação — só se isso não deixar a tabela
poluída; caso contrário, deixar a seção 22 autocontida sem tocar na 21.
- [ ] **Step 3: Commit**
```bash
cd "D:\PROJETOS\KLINGO-CLINICAL-SYSLIFE-GCHAT-AGENDAMENTO"
git add docs/n8n-agendamento-runbook.md
git commit -m "docs: registra workflows de exemplo de AI Agent para agendamento (Klingo, ClinicAll, SysLife)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>"
```
---
## Observação sobre execução
Mesma disciplina dos planos anteriores: validar
(`n8n_validate_workflow`) depois de cada workflow criado/modificado.
Os 3 workflows deste plano ficam **intencionalmente inativos** ao
final — sem clínica real de nenhum dos três providers e sem credencial
Postgres válida, ativá-los só geraria execuções com erro. O
`systemMessage` do Klingo é o único que precisa de atenção redobrada:
ele documenta uma limitação real da API (não um bug desta
implementação) — não simplificar nem remover esse aviso ao escrever o
texto final.
@@ -0,0 +1,175 @@
# Design — Confirmação de Agenda via WhatsApp (SysLife)
**Data:** 2026-08-11
**Status:** Aprovado pelo usuário, aguardando plano de implementação.
## Objetivo
Mesmo padrão já implementado para Klingo e ClinicAll
(`docs/superpowers/specs/2026-08-11-confirmacao-agenda-klingo-design.md`,
`docs/superpowers/specs/2026-08-11-confirmacao-agenda-clinicall-design.md`),
agora para o **SysLife**: permitir que o paciente confirme presença numa
consulta agendada via WhatsApp. Os endpoints usados fazem parte do mesmo
WebService já usado no MVP de agendamento (`Manual WS SysLife V3.4.pdf`,
salvo em `docs/Manual WS SysLife V3.4 (1).pdf`, relido nesta sessão),
recurso `AgendaWSApp` — explicitamente descrito no manual como "retorna
os registros da agenda **para uso do WhatsApp**".
## Relação com o trabalho anterior
- Reaproveita o **MCP Server standalone de Mensageria (Z-PRO)**
(`docs/n8n-agendamento-runbook.md`, seção 17) para o disparo do
lembrete, mesma decisão do Klingo e do ClinicAll.
- É um MCP **novo e separado** do MCP de agendamento do SysLife
(seção 14.2 do runbook) — endpoints diferentes (`AgendaWSApp` de
confirmação vs. `Agenda`/`Horario`/etc. de criação), mesmo espírito
de separação já usado nos outros dois providers.
- **Reaproveita a credencial Basic Auth já criada** no MVP de
agendamento do SysLife (`SysLife Basic Auth - clínica pendente`,
`u8XXJ6wyrKuGJp4Y`) — usuário/senha fixos do WebService
(`WebSysLife`/`$Sys10Life`), documentados literalmente no manual, não
variam por clínica nem por endpoint. Diferente do Klingo (token por
clínica) e do ClinicAll (sem auth documentada), aqui a credencial já
existe e pode ser usada de verdade.
## Escopo: 3 tools do MCP Server "SysLife - Confirmação de Agenda"
O recurso `AgendaWSApp` do manual é mais rico que o equivalente dos
outros dois providers: um único `GET` já serve três propósitos
diferentes, alternados por qual dos três parâmetros é enviado (o manual
é explícito: **"Deverá ser usado somente um dos 3 parâmetros"**):
| Tool | Endpoint | Parâmetro usado | Uso |
| --- | --- | --- | --- |
| `listar_agendamentos_do_dia` | `GET /AgendaWSApp` | `QuantidadeDias` (`1` = amanhã, `2` = depois de amanhã, etc.) | Base do lembrete proativo |
| `buscar_agendamento_por_telefone` | `GET /AgendaWSApp` | `NumeroCelular` (DDD + número, sem separador) | O agente usa pra achar a consulta pendente do paciente pelo telefone |
| `confirmar_presenca` | `POST /AgendaWSApp` | `CodigoAgenda` + `Resposta` (`"1"` = SIM, `"2"` = NÃO) | Ação central — o mais simples dos três providers, só dois valores possíveis |
Duas tools de leitura (`listar_agendamentos_do_dia`,
`buscar_agendamento_por_telefone`) apontam pro **mesmo endpoint**, cada
uma com um sub-workflow próprio que monta o parâmetro certo — mesma
separação de responsabilidade já usada nos outros MCP Servers deste
projeto (uma tool, um propósito claro), mesmo reaproveitando a chamada
HTTP de baixo nível.
**Fora de escopo, mesmo raciocínio do `/entrada` do Klingo e do
`AgendaCentral`/relatórios do ClinicAll**: `AgendaCentral` (central
telefônica, não WhatsApp), `AgendaRetorno` (consultas de retorno, não
confirmação), `AgendaStatus` (base para NPS, sem endpoint de submissão
documentado no manual) e `AgendaConfirmado` (só consulta informativa de
quem já confirmou, sem ação — não essencial ao fluxo).
## Arquitetura
```
1) MCP Server "SysLife - Confirmação de Agenda" (servidor + 3 sub-workflows)
[MCP Server Trigger] ──Tools──┬── listar_agendamentos_do_dia ──▶ GET /AgendaWSApp (QuantidadeDias)
├── buscar_agendamento_por_telefone ──▶ GET /AgendaWSApp (NumeroCelular)
└── confirmar_presenca ──▶ POST /AgendaWSApp (CodigoAgenda, Resposta)
2) Workflow proativo "Lembrete de Confirmação - SysLife (exemplo)"
[Cron 8h diário] → [SysLife: listar_agendamentos_do_dia (QuantidadeDias=1)]
→ [Loop por agendamento] → [Mensageria ZPRO: enviar_texto]
3) Workflow de exemplo "Confirmação de Agenda - GChat - SysLife+Z-PRO (exemplo)"
[Webhook Z-PRO/GChat] → [AI Agent] → resposta ao paciente
tools: MCP SysLife - Confirmação de Agenda (buscar_agendamento_por_telefone, confirmar_presenca)
memória: Postgres Chat Memory (mesmo padrão dos outros exemplos)
```
Sem clínica SysLife real disponível: mesma disciplina dos outros dois
providers — estrutura completa, validada (`n8n_validate_workflow`, 0
erros esperados), sem teste de ponta a ponta.
## Componentes
### MCP Server "SysLife - Confirmação de Agenda"
Mesmo esqueleto de sub-workflow do MVP de agendamento do SysLife:
`Execute Workflow Trigger` → `Config SysLife` (`Set` com `baseUrl`
placeholder) → `Montar corpo` (monta o JSON do body — mesmo em GET,
conforme documentado: `Seção Body, Type raw, JSON`) → `HTTP Request`
(Basic Auth via credencial reaproveitada, `neverError: true` +
`fullResponse: true`) → `Classificar resultado` (mesma taxonomia
genérica dos outros providers: `AUTHENTICATION_ERROR` 401/403,
`NOT_FOUND` 404, `VALIDATION_ERROR` 400/422, `SYSLIFE_API_ERROR`
demais — o manual não documenta código de erro específico).
- **`listar_agendamentos_do_dia`**: parâmetro `quantidadeDias`
(obrigatório — `1` para amanhã, conforme o exemplo do manual "1 = Dia
atual + 1"). Body: `{ "QuantidadeDias": <int> }`.
- **`buscar_agendamento_por_telefone`**: parâmetro `numeroCelular`
(obrigatório, string — DDD + número, ex.: `"71999999999"`, conforme
documentado "Código DDD + Número do Celular"). Body:
`{ "NumeroCelular": "<string>" }`.
- **`confirmar_presenca`**: parâmetros `codigoAgenda` (obrigatório) e
`resposta` (obrigatório, string `"1"` ou `"2"` — documentado na
`description` da tool como `"1" = paciente confirmou`, `"2"` =
paciente não confirmou/recusou, sem terceiro estado como no Klingo).
Body: `{ "CodigoAgenda": <int>, "Resposta": "<string>" }`.
Resposta de `AgendaWSApp` GET é um array rico (campos `coAgenda`,
`dtAtendimento`, `hrAtendimentoAlterado`, `nmPaciente`, `coMedico`,
`nmMedico`, `nmEspecialidade`, `nmOrigemDestino`, `coProcedimento`,
`nmProcedimento`, `nuTelefone`, `nuTelefoneDdd`, `nuCelular`,
`nuCelularDdd`, `txObservacao`, `txWhatsappProcedimento`,
`txWhatsappHorario`, `txWhatsappMedico`, `txEndereco`, `txBairro`,
`txComplemento`, `txCidade`, `txEstado`, `nmMsgSms`, `nmMsgSmsExtra`) —
já vem pronto com textos formatados pro WhatsApp
(`txWhatsappProcedimento`/`txWhatsappHorario`/`txWhatsappMedico`), útil
pra montar a mensagem do lembrete sem concatenar campos manualmente.
### Workflow proativo "Lembrete de Confirmação - SysLife (exemplo)"
```
[Cron Trigger, 8h diário] → [SysLife: listar_agendamentos_do_dia]
(quantidadeDias = 1, ou seja, amanhã)
→ [Loop] → [Mensageria ZPRO: enviar_texto]
(number = nuCelularDdd + nuCelular do item, body = mensagem usando
txWhatsappProcedimento/txWhatsappHorario/txWhatsappMedico quando
presentes, senão monta com nmProcedimento/dtAtendimento/nmMedico)
```
Diferente do ClinicAll, o telefone aqui é campo direto do item
(`nuCelular`/`nuCelularDdd`), sem objeto `Paciente` aninhado — mais
parecido com o Klingo nesse aspecto. Fica **inativo** de propósito.
### Workflow de exemplo "Confirmação de Agenda - GChat - SysLife+Z-PRO (exemplo)"
Réplica estrutural do padrão já usado no Klingo e no ClinicAll (webhook
→ AI Agent → memória Postgres), sem cliente real associado.
- **Webhook**: mesmo contrato Z-PRO/GChat já documentado (seção 6 do
runbook).
- **AI Agent**: `systemMessage` fixo instruindo o agente a: entender se
a mensagem é confirmação/recusa; se for, pedir o telefone do paciente
(ou usar o `telefone` já vindo do próprio contato do WhatsApp, quando
disponível) e usar `buscar_agendamento_por_telefone` para achar o
`coAgenda` pendente; chamar `confirmar_presenca` com
`resposta: "1"` (confirmou) ou `"2"` (recusou); responder confirmando
o registro. Mais simples que o ClinicAll — não precisa de tool de
tabela de domínio, os dois valores já são documentados diretamente.
- **Tools**: MCP SysLife - Confirmação de Agenda —
`buscar_agendamento_por_telefone` e `confirmar_presenca` conectadas
(`listar_agendamentos_do_dia` só serve ao workflow proativo).
- **Memória**: `Postgres Chat Memory`, mesmo padrão da seção 16/18/19
do runbook, credencial placeholder.
Fica **inativo** de propósito.
## Fora de escopo (adiado)
- `AgendaCentral`, `AgendaRetorno`, `AgendaStatus`, `AgendaConfirmado`
— ver seção "Escopo" acima.
- Configuração via Google Docs no workflow de exemplo — sem gestor
real associado.
- Teste de ponta a ponta contra a API real do SysLife — sem clínica
real disponível (mesma pendência do MVP de agendamento).
## Testes
Sem clínica SysLife real disponível: validação estrutural apenas
(`n8n_validate_workflow`, 0 erros esperados em todos os workflows).
Teste real de ponta a ponta fica pendente para quando houver uma
clínica SysLife real — a credencial Basic Auth já existe (reaproveitada
do MVP de agendamento), então só falta o `baseUrl` real da clínica.
@@ -0,0 +1,137 @@
# Design — Workflows de Exemplo de AI Agent para Agendamento (Klingo, ClinicAll, SysLife)
**Data:** 2026-08-11
**Status:** Aprovado pelo usuário, aguardando plano de implementação.
## Objetivo
Os MCP Servers de agendamento do Klingo, ClinicAll e SysLife existem e
estão validados estruturalmente há algum tempo, mas nenhum tem um
workflow de agente cliente (AI Agent + prompt + `MCP Client Tool`) —
isso foi explicitamente adiado em cada design ("sem clínica real nem
canal de mensagens definido"). Mesmo padrão que já resolvemos pra
**confirmação de agenda** dos mesmos três providers (seções 18-20 do
runbook): construir um workflow de exemplo/esqueleto, sem cliente real
associado, pronto pra duplicar quando houver clínica de verdade.
## Relação com o trabalho anterior
- Reaproveita **exatamente** o esqueleto já usado nos três exemplos de
confirmação de agenda (webhook Z-PRO/GChat → `Extrair campos` →
`AI Agent` com `OpenAI Chat Model` real + `Postgres Chat Memory`
placeholder), só trocando as tools conectadas.
- Conecta nas tools de **agendamento**, não nas de confirmação — decisão
explícita do usuário: "só agendamento por enquanto", mesmo padrão do
Z-PRO em produção (que também só tem agendamento).
- Os três MCP Servers de agendamento já existem, ativos ou não conforme
cada design; workflows e ids reaproveitados diretamente, nenhum
sub-workflow novo é criado nesta rodada — só o workflow de agente e a
conexão via `MCP Client Tool`.
## Escopo real de cada MCP Server de agendamento (conferido nos designs)
| Provider | MCP Server (id) | Tools | Observação |
| --- | --- | --- | --- |
| **Klingo** | `3eiFEnfOTLnutP78` (path `mcp-server-klingo`) | `consultar_horarios`, `agendar` (2 tools) | **Limitação real conhecida**: `consultar_horarios` sempre retorna `SLOT_MAPPING_UNAVAILABLE` — a API do Klingo responde com sucesso, mas o formato de cada horário individual não é documentado publicamente. Consequência: `agendar` exige um `slotId` que, na prática, não há hoje como obter por esta integração. |
| **ClinicAll** | `igaKjoHcPNYRAxPS` (path `mcp-server-clinicall`) | `unidade`, `especialidade`, `convenio`, `profissional`, `procedimento`, `paciente`, `consultar_horarios`, `agendar` (8 tools) | `agendar` usa `PUT` (suposição não verificada) e **concilia** um `idAgenda` de horário livre já existente (obtido via `consultar_horarios`) — não cria um registro do zero. |
| **SysLife** | `TYu78UqIUr2yCBHK` (path `mcp-server-syslife`) | `especialidade`, `medico`, `convenio`, `paciente`, `procedimento`, `consultar_horarios`, `agendar` (7 tools) | Fluxo linear padrão: consulta os recursos de apoio, resolve os códigos, agenda via `PUT /Agenda`. |
**Correção em relação à conversa inicial**: o Klingo tinha sido
apresentado como tendo 8 tools de agendamento (confundindo com a API
de Telefonia, que essa sim tem 6 tools de confirmação) — na verdade
são só 2. A tabela acima é a fonte de verdade, extraída direto dos
designs já commitados.
## Decisão sobre a limitação do Klingo
**Decisão explícita do usuário**: construir o workflow de exemplo do
Klingo mesmo assim, documentando a limitação — tanto no `systemMessage`
do agente (pra ele explicar ao paciente que não consegue consultar
horários no momento, em vez de inventar uma resposta) quanto na spec e
no runbook. Não é um bug desta implementação; é uma lacuna real e já
conhecida da documentação pública da API do Klingo, fora do escopo
resolver aqui.
## Arquitetura
Três workflows novos, um por provider, todos seguindo o mesmo esqueleto:
```
[Webhook GChat] → [Extrair campos do webhook] → [AI Agent] → resposta
├─ tools: MCP de Agendamento do provider (MCP Client Tool, todas as tools)
├─ modelo: OpenAI Chat Model (credencial real "GPT", 29vMIDah5DTIhUYJ)
└─ memória: Postgres Chat Memory (credencial placeholder, sem cliente real)
```
- `Agendamento - GChat - Klingo (exemplo)` — conecta nas 2 tools do MCP
Klingo (`3eiFEnfOTLnutP78`).
- `Agendamento - GChat - ClinicAll (exemplo)` — conecta nas 8 tools do
MCP ClinicAll (`igaKjoHcPNYRAxPS`).
- `Agendamento - GChat - SysLife (exemplo)` — conecta nas 7 tools do
MCP SysLife (`TYu78UqIUr2yCBHK`).
Mesmo contrato de webhook Z-PRO/GChat já documentado (seção 6 do
runbook): `body.protocol`→`sessionId`, `body.entrada`→`mensagem`,
`body.contactName`→`nomeContato`, `body.number`→`telefone`.
## Componentes
### `systemMessage` de cada agente
Adaptado do fluxo real de cada API (não genérico, não inventado):
- **Klingo**: instrui o agente a seguir `consultar_horarios` →
`agendar`, mas **avisa explicitamente** que `consultar_horarios`
pode retornar `SLOT_MAPPING_UNAVAILABLE` — nesse caso, o agente deve
informar ao paciente que a consulta de horários está temporariamente
indisponível por essa integração, sem inventar horários nem tentar
chamar `agendar` sem um `slotId` real.
- **ClinicAll**: instrui o agente a consultar especialidade/convênio/
profissional/procedimento conforme necessário, usar
`consultar_horarios` para obter um `idAgenda` de horário livre, e
então chamar `agendar` **nesse mesmo `idAgenda`** (nunca inventar um
novo) — deixando explícito que é uma conciliação, não uma criação.
- **SysLife**: instrui o agente a seguir a ordem
`especialidade` → `medico` → (`convenio`/`paciente`/`procedimento`,
qualquer ordem) → `consultar_horarios` → `agendar`, mesma ordem já
documentada no design do MCP SysLife.
Nenhum dos três usa configuração via Google Docs (workflows de exemplo,
sem gestor real).
### Tools conectadas
Via `MCP Client Tool` nativo, `include: "all"` (diferente dos exemplos
de confirmação, que filtravam tools específicas — aqui faz sentido
conectar todas as tools do MCP de agendamento, já que o agente precisa
de todas elas pra completar um agendamento).
### Memória e modelo
Idênticos aos três exemplos de confirmação já construídos: `Postgres
Chat Memory` com credencial placeholder (`PLACEHOLDER_SEM_CREDENCIAL`),
`OpenAI Chat Model` com a credencial real e compartilhada já usada em
produção (`29vMIDah5DTIhUYJ`, "GPT").
## Fora de escopo (adiado)
- Resolver `SLOT_MAPPING_UNAVAILABLE` do Klingo de verdade — lacuna de
contrato da API, não desta implementação.
- Verificar empiricamente o verbo `PUT` de `/agendamento` do ClinicAll
— pendência já registrada no MVP de agendamento, continua em aberto.
- Conectar as tools de confirmação de agenda nesses mesmos agentes —
decisão explícita do usuário de manter só agendamento por enquanto;
pode ser revisitado depois.
- Ativação dos três workflows — ficam **inativos de propósito**, mesma
disciplina de todos os workflows de exemplo já construídos (sem
clínica real, sem credencial Postgres real).
## Testes
Sem clínica real disponível para nenhum dos três providers: validação
estrutural apenas (`n8n_validate_workflow`, 0 erros esperados, exceto
warnings já aceitos de credencial placeholder). Nenhuma chamada HTTP
real. Quando houver clínica real de qualquer um dos três: preencher
`baseUrl`/credenciais reais, provisionar Postgres, ativar o workflow
correspondente — mesmo checklist já seguido nos exemplos de
confirmação.