Files
KLINGO-CLINICAL-SYSLIFE-GCHAT/docs/n8n-agendamento-runbook.md
T

65 KiB
Raw Blame History

Runbook — Workflow de Agendamento no n8n (Z-PRO, Klingo, SysLife, ClinicAll)

Registra problemas reais encontrados ao montar os workflows de agendamento no n8n (servidor srvdevn8ngti / devn8n.gtigrupo.com.br) e como foram resolvidos — para não repetir o mesmo processo de descoberta ao duplicar para uma nova clínica ou provider. As seções 1-13 cobrem o histórico completo do Z-PRO (o único provider em produção real até agora, incluindo a migração do node comunitário pro MCP Server 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). 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

  • O node oficial do n8n (MCP Client Tool, @n8n/n8n-nodes-langchain) só conecta em MCP remoto via HTTP Streamable/SSE — não roda comando local (stdio). Para rodar o gti-scheduling-mcp como subprocesso local, use o pacote comunitário n8n-nodes-mcp (autor nerding-io).
  • Instalação: Settings → Community Nodes → Install a community node → n8n-nodes-mcp.
  • Ao conectar como tool de um AI Agent, o tipo do node no JSON do workflow precisa ser n8n-nodes-mcp.mcpClientTool (não n8n-nodes-mcp.mcpClient) — é uma variante "Tool" que o n8n gera automaticamente para nodes marcados como usáveis em AI Agents. Usar mcpClient na conexão ai_tool falha a validação com "cannot output ai_tool connections".
  • É necessário setar a variável de ambiente do processo do n8n (não é configurável pela UI):
    N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true
    
    Nesse servidor, o n8n roda via systemd (n8n.service), com EnvironmentFile=/opt/n8n.env. A variável foi adicionada nesse arquivo, seguido de systemctl restart n8n. (Se o n8n rodasse em Docker, seria em environment: no docker-compose.yml.)

2. Credencial MCP (STDIO) — dois bugs reais

Tipo de credencial: mcpClientApi ("MCP Client (STDIO) API"), campos: command, args, environments.

  • Bug 1 — command: "node" sozinho falhou com "Connection closed". O serviço systemd tem um PATH mais restrito que um shell interativo. Fix: usar o caminho absoluto (which node no servidor → /usr/bin/node).

  • Bug 2 — o campo "Environments" é um <input> de uma linha só (mascarado como senha) na UI do n8n. O código real do node (nodes/McpClient/McpClient.node.ts no pacote n8n-nodes-mcp) espera o formato NOME=VALOR separado por quebra de linha real (split('\n')), mas navegadores removem quebras de linha ao digitar OU colar em campos de uma linha — então múltiplas variáveis nunca conseguem ser inseridas corretamente pela UI (tentamos: uma por linha, vírgula, espaço — todas colapsam a mesma forma, e a primeira variável acaba recebendo o resto do texto como valor, quebrando a validação).

    Fix: criar/recriar a credencial via API REST do n8n, que aceita o JSON com \n de verdade (não passa pelo campo quebrado da UI):

    # 1. Gerar uma API key: Settings → n8n API → Create an API key
    # 2. DELETE na credencial antiga (se existir), depois POST na nova:
    curl -X POST "https://devn8n.gtigrupo.com.br/api/v1/credentials" \
      -H "X-N8N-API-KEY: <chave>" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Client (STDIO) account",
        "type": "mcpClientApi",
        "data": {
          "command": "/usr/bin/node",
          "args": "/opt/gti-scheduling-mcp/dist/index.js",
          "environments": "SCHEDULING_PROVIDER=zpro\nZPRO_BASE_URL=https://...\nZPRO_API_TOKEN=...\nZPRO_API_ID=..."
        }
      }'
    

    Sintoma quando esse bug está presente: o log do n8n (journalctl -u n8n -f) mostra exatamente a mensagem de erro do gti-scheduling-mcp (Falha ao carregar a configuração: SCHEDULING_PROVIDER deve ser "zpro" ou "klingo".), seguida de MCP error -32000: Connection closed — o processo sobe e cai na validação de config antes de completar o handshake stdio.

3. Deploy do gti-scheduling-mcp no servidor do n8n

O node dist/index.js executado pela credencial precisa estar no mesmo host onde o n8n roda (o node comunitário spawna o processo localmente). Processo usado (sem repositório git configurado ainda neste projeto): tar local (excluindo node_modules/dist) → scp pro servidor → npm install && npm run build lá. Publicado em /opt/gti-scheduling-mcp.

4. Modelo de IA (OpenAI Chat Model node) — gotchas de configuração

Mesmo usando um provider "compatível com OpenAI" (ex.: Z.ai/GLM), o node OpenAI Chat Model (@n8n/n8n-nodes-langchain.lmChatOpenAi, v1.3) tem comportamento por padrão que quebra com endpoints não-OpenAI:

  • responsesApiEnabled é true por padrão nessa versão — usa a "Responses API" da OpenAI (/responses), um endpoint proprietário que providers OpenAI-compatíveis geralmente não implementam (eles só têm /chat/completions). Sintoma: 404 Not Found / MODEL_NOT_FOUND. Fix: setar responsesApiEnabled: false explicitamente.
  • Campo model é um resourceLocator — precisa de {mode: "id", value: "nome-do-modelo"} explícito. Omitir mode pode fazer o n8n tentar listar modelos via uma chamada de API (GET /models) que o provider alternativo pode não suportar do mesmo jeito, gerando erro parecido com o anterior.
  • Base URL da credencial: o campo correto na credencial openAiApi é url (aparece como "Base URL" na UI, geralmente atrás de "Add Option").

5. Expressões em sub-nodes de IA (Memory/Tools) dentro do AI Agent

Dentro de nodes conectados via ai_memory/ai_tool/ai_languageModel (sub-nodes do AI Agent), referenciar um node upstream explicitamente (={{ $('Normalizar entrada').item.json.sessionId }}) falhou com "Key parameter is empty" — mesmo com o dado presente no item que chegou no AI Agent. Fix: usar ={{ $json.sessionId }} (referência ao item atual, sem nome de node) — é o padrão que o próprio n8n usa por padrão nesse campo, e funciona porque sub-nodes de IA herdam o item do node pai (AI Agent) na execução.

6. Contrato do webhook do Z-PRO/GChat (verificado, não documentado

oficialmente em lugar nenhum)

  • Uma execução do workflow por mensagem do cliente — o Z-PRO não enfileira mensagens seguintes se o workflow não responder imediatamente.
  • Corpo recebido: {step, entrada, number, contactName, protocol} — step deve ser "process"; protocol é o identificador do atendimento (não do telefone).
  • Resposta esperada: texto puro, nunca JSON — node Respond to Webhook em modo text.

7. Z.ai/GLM como modelo temporário — limitação real de tool-calling

Usado como substituto temporário enquanto a chave da OpenAI não chegava. Dois endpoints testados:

  • https://api.z.ai/api/coding/paas/v4 ("GLM Coding Plan"): funciona bem para chat simples, mas é restrito a ferramentas oficialmente suportadas (Claude Code, Goose, etc. — ver https://docs.z.ai/devpack/faq). Ao anexar uma tool MCP genérica ao AI Agent, o modelo passou a devolver respostas vazias silenciosamente (sem erro) em qualquer mensagem, mesmo sem chamar a tool. Confirmado desabilitando a tool: a conversa voltou a funcionar normalmente.
  • https://api.z.ai/api/paas/v4/ (endpoint geral, mesma conta): suporta tool-calling arbitrário segundo a documentação, mas apresentou timeout consistente nesta conta/plano (possivelmente saldo separado do "Coding Plan").
  • Conclusão: Z.ai/GLM não é uma substituição direta e confiável da OpenAI para um AI Agent com tools neste projeto. Recomendado usar a chave real da OpenAI (ou outro provider com suporte robusto e testado de function-calling) assim que disponível — só trocar a credencial e o model/responsesApiEnabled de volta, sem tocar no resto do workflow.

8. Tratamento de erro adicionado

Normalizar entrada e AI Agent têm onError: "continueErrorOutput", ambos roteados para um node Set ("Erro - Resposta padrão") com uma mensagem fixa amigável, que alimenta o Respond to Webhook. Isso garante que o Z-PRO sempre recebe alguma resposta, mesmo se a normalização lançar uma exceção ou o AI Agent falhar (timeout, erro de modelo, etc.) — testado com um timeout real do endpoint geral do Z.ai, confirmado funcionando.

9. Bug crítico — toolParameters do node MCP nunca era preenchido pelo modelo

Sintoma: toda chamada de agendar falhava com MCP error -32602: Input validation error: Invalid arguments for tool agendar: Required at clinicId, Required at startAt, Required at endAt, Required at patient. — mesmo com o prompt do sistema explicando o formato esperado em detalhe.

Causa raiz: o node n8n-nodes-mcp (operação executeTool) tem um campo próprio toolParameters (JSON, obrigatório, valor padrão '{}') que carrega os argumentos reais enviados à tool. Ele não é preenchido automaticamente só por a tool estar conectada a um AI Agent — é preciso configurá-lo explicitamente com o helper $fromAI() do n8n, que é o mecanismo real usado para "deixar o modelo decidir este valor em cada chamada". Sem isso, o campo fica travado no {} padrão, e nenhum valor que o modelo "pensa" que está enviando chega de fato ao MCP.

Fix: configurar toolParameters assim (mistura valores fixos vindos do próprio workflow com $fromAI() só para o que o modelo precisa mesmo decidir):

={{ JSON.stringify({
  clinicId: $('Normalizar entrada').item.json.clinicId,
  startAt: $fromAI('startAt', 'Data e hora de início, ISO 8601 completo', 'string'),
  endAt: $fromAI('endAt', 'Data e hora de término, ISO 8601 completo', 'string'),
  patient: {
    name: $fromAI('patientName', 'Nome completo confirmado do paciente', 'string'),
    phone: $('Normalizar entrada').item.json.telefone
  }
}) }}

10. Bug crítico — systemMessage do AI Agent nunca era avaliado como expressão

Sintoma: um agendamento de teste foi criado com o campo de telefone contendo literalmente o texto {{ $('Normalizar entrada').item.json.telefone }} em vez de um número de telefone real.

Causa raiz: o campo parameters.options.systemMessage do node AI Agent só é avaliado como expressão do n8n se o valor inteiro do campo começar com =. Sem esse prefixo, tudo — inclusive trechos {{ ... }} escritos "como exemplo" dentro do texto — é enviado ao modelo como texto literal, e o modelo, sem saber que aquilo deveria virar um valor real, às vezes copia o placeholder ao pé da letra.

Fix: sempre prefixar o campo inteiro com = quando ele precisar referenciar dados reais do workflow (={{ $('Normalizar entrada')... }}).

Consequência que isso causou (transparência total): dois agendamentos de teste fictícios ficaram duplicados no Z-PRO (Consulta - TESTE-N8N Paciente Final, mesma data/hora) antes desse bug ser identificado — uma chamada que o agente reportou como "erro" na verdade teve sucesso silenciosamente no lado do Z-PRO. Os testes fictícios foram apagados manualmente depois. Isso reforça por que a disciplina de "uma execução por vez, conferir visualmente antes de tentar de novo" existe em todos os testes reais deste projeto — mesmo seguindo ela, um bug de configuração ainda pode gerar um resultado inesperado, e só a conferência visual pega isso.

11. Bug — modelo não sabe a data de hoje

Sintoma: pedido de agendamento para "amanhã" resultou em uma data no passado (2023) sendo enviada ao Z-PRO.

Causa raiz: modelos de linguagem não têm acesso à data/hora real do momento da conversa — sem essa informação no prompt, o modelo "chuta" uma data (geralmente relacionada à data de corte do treinamento).

Fix: incluir a data/hora atual no systemMessage via expressão do próprio n8n:

A data de hoje é {{ $now.setZone('America/Sao_Paulo').toFormat('yyyy-MM-dd (cccc)') }}

12. Bug — horário criado 3h adiantado/atrasado (fuso horário)

Sintoma: cliente pediu "sexta às 10h", o agendamento foi criado em produção às 7h — exatamente 3h a menos (o offset de America/Sao_Paulo, UTC-3).

Causa raiz: o exemplo de formato dado ao modelo usava sufixo Z (UTC) — ex. 2026-04-20T18:00:00.000Z. O modelo tratou o horário local que o cliente pediu (10h) como se já fosse UTC, sem converter, e o Z-PRO (que aparentemente armazena/exibe em UTC) mostrou 10h UTC como 7h local.

Fix: instruir o modelo a nunca usar Z/UTC e sempre escrever o mesmo número de hora que o cliente pediu, com offset -03:00 explícito (ex.: cliente pediu 10h → 2026-08-14T10:00:00-03:00). Isso evita qualquer aritmética de fuso horário pelo modelo — ele só copia o número que o cliente já disse, sem calcular nada. Ajustado tanto na descrição do $fromAI('startAt', ...)/$fromAI('endAt', ...) quanto numa regra explícita no systemMessage.

Se isso acontecer nas próximas clínicas: o offset -03:00 só está certo para fuso de Brasília. Se uma clínica futura estiver em outro fuso, ajustar o offset (e o $now.setZone(...) do prompt) de acordo.

13. Migração — MCP Server nativo no n8n (substitui o node comunitário, só Z-PRO)

Data: 11/08/2026. Ver design completo em docs/superpowers/specs/2026-08-10-mcp-server-nativo-n8n-zpro-design.md e plano em docs/superpowers/plans/2026-08-10-mcp-server-nativo-n8n-zpro.md.

Motivação: o node comunitário (n8n-nodes-mcp, seções 1–2 acima) exigiu depuração pesada (bug de credencial STDIO, variável de ambiente do processo, toolParameters/$fromAI não documentado) e não é editável visualmente — qualquer manutenção de memória/prompt/tool exige mexer em processo externo. A alternativa: reconstruir o mesmo "MCP Server" inteiramente dentro do n8n, com nodes oficiais (MCP Server Trigger + Call n8n Sub-Workflow Tool do lado servidor, MCP Client Tool oficial via HTTP Streamable do lado cliente) — sem processo Node.js externo, sem pacote comunitário.

Arquitetura nova (3 workflows adicionais, o workflow de agendamento existente só trocou o node MCP):

  • MCP Server - ZPRO (qjSaKllvneBIZ7mC) — MCP Server Trigger (path: mcp-server-zpro-clinica-exemplo) + 2 Call n8n Sub-Workflow Tool (agendar, consultar_horarios).
  • MCP Server - ZPRO - agendar (5ZEOqTOk4Xex6jUQ) — porta fiel da lógica já testada em gti-scheduling-mcp (zpro.mapper.ts/zpro.adapter.ts/ zpro.errors.ts) para nodes Set/Code/HTTP Request: monta o corpo, chama POST /v2/api/external/{apiId}/appointment/create com neverError: true + fullResponse: true (captura manual de status/body, nunca deixa o n8n abortar em 4xx/5xx), classifica o resultado (qualquer 2xx é sucesso operacional — mesma proteção contra duplicidade de sempre).
  • MCP Server - ZPRO - consultar_horarios (yfKkhSTDZaIYCPqP) — sempre retorna NOT_SUPPORTED (mesma decisão de produto de sempre, Z-PRO não expõe esse endpoint).
  • No workflow de agendamento (yG2mi6ECBpPv4Hmn): saiu o node comunitário MCP - gti-scheduling-mcp (n8n-nodes-mcp.mcpClientTool, stdio), entrou MCP - ZPRO (nativo n8n) (@n8n/n8n-nodes-langchain.mcpClientTool, serverTransport: httpStreamable, apontando pra URL do MCP Server Trigger acima). Nada mais no workflow mudou (prompt, memória, fallback de erro).

Gotcha 1 — todos os workflows envolvidos precisam estar active: true, inclusive os dois sub-workflows (agendar/consultar_horarios) chamados via Call n8n Sub-Workflow Tool — não só o servidor MCP e o workflow de agendamento. O erro sintoma é "Workflow is not active and cannot be executed." no node MCP Client Tool do lado do AI Agent.

Gotcha 2 — diagnóstico via chamada MCP crua (curl), sem depender do AI Agent: pra isolar se o problema está na cadeia de sub-workflows ou no transporte/roteamento do AI Agent, dá pra chamar o endpoint MCP diretamente:

# 1. Handshake — captura o mcp-session-id no header da resposta
curl -s -i "https://devn8n.gtigrupo.com.br/mcp/mcp-server-zpro-clinica-exemplo" -X POST \
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl-test","version":"1.0"}}}'

# 2. tools/call — usa o mcp-session-id do passo 1
curl -s "https://devn8n.gtigrupo.com.br/mcp/mcp-server-zpro-clinica-exemplo" -X POST \
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: <session-id>" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"agendar","arguments":{"startAt":"...","endAt":"...","patientName":"...","patientPhone":"..."}}}'

Isso foi o que revelou que a cadeia de sub-workflows já funcionava (chegava até o Z-PRO de verdade) enquanto o caminho via AI Agent ainda reportava "not active" — depois de reativar os 3 workflows envolvidos e aguardar um pouco, o caminho via AI Agent voltou a funcionar igual ao teste direto (não ficou claro se foi só o tempo/cache do n8n resolvendo, ou a reativação — mas o sintoma não voltou a aparecer depois disso).

Gotcha 3 — causa raiz real do primeiro 403 em produção: não foi formato de header nem token expirado — foi ApiID e token de integrações diferentes. A clínica tem mais de uma integração externa cadastrada no Z-PRO (ex.: uma pro canal de WhatsApp "Canal QR", outra pro agendamento), cada uma com seu próprio ApiID (segmento da URL, /v2/api/external/{ApiID}/...) e seu próprio Bearer token — não são intercambiáveis. O node Config ZPRO precisa ter o apiId da mesma integração de onde veio o token salvo na credencial httpHeaderAuth. Os sintomas por tipo de descasamento, na ordem em que apareceram:

Corpo de erro do Z-PRO (403) Causa
{"error": "ERR_SESSION_NOT_AUTH_TOKEN"} token nunca usado/nunca válido pra nenhuma integração
{"error": "Invalid token."} token de uma integração, apiId de outra (ou vice-versa)
(sucesso, 200) apiId e token da mesma integração

Ao duplicar este padrão pra uma nova clínica: sempre confirmar, na tela de integrações do Z-PRO daquela clínica, que o ApiID copiado pra URL e o Bearer token copiado pra credencial vêm da mesma linha/integração.

Teste real de validação (11/08/2026): um agendamento fictício foi criado de ponta a ponta pelo caminho de produção completo (webhook → Normalizar entrada → AI Agent → MCP - ZPRO (nativo n8n) → MCP Server - ZPRO → sub-workflow agendar → Z-PRO), com startAt local correto (2026-08-12T11:00:00-03:00, sem bug de timezone), retorno 200 do Z-PRO, id de agendamento real mapeado, e resposta final coerente pro cliente. Conferido visualmente no Z-PRO e apagado logo em seguida.

Resultado: o node comunitário n8n-nodes-mcp não é mais necessário pro Z-PRO (segue instalado no servidor, mas sem uso nesse workflow). As seções 1–2 deste runbook (instalação do node comunitário, bugs da credencial STDIO) ficam como referência histórica — não se aplicam mais a este workflow, mas continuam relevantes se algum dia o padrão nativo não for suficiente e for necessário voltar ao processo externo (gti-scheduling-mcp, monorepo TypeScript pausado).

Status final — Z-PRO (11/08/2026)

Testado de ponta a ponta com sucesso, tanto com a chave real da OpenAI (gpt-4o-mini) quanto com o MCP Server nativo do n8n (seção 13): telefone correto, data correta, um único agendamento por teste, confirmado visualmente no Z-PRO. Workflow ativo em produção (yG2mi6ECBpPv4Hmn), junto com os 3 workflows do MCP Server nativo (qjSaKllvneBIZ7mC, 5ZEOqTOk4Xex6jUQ, yfKkhSTDZaIYCPqP) — todos precisam permanecer active: true. Desde a seção 15, o systemMessage também depende de um Google Doc externo (leitura pública, docId fixo em "Config Clínica") — se o Doc for despublicado ou o docId mudar, o atendimento continua funcionando (fallback seguro), só perde a personalização da clínica.

14. Providers adicionais via MCP Server nativo (Klingo, SysLife, ClinicAll)

Mesmo padrão arquitetural validado no Z-PRO (seção 13) — MCP Server Trigger + Call n8n Sub-Workflow Tool, sem processo Node.js externo — aplicado a mais três providers nesta sessão (11/08/2026). Nenhum dos três tem clínica real disponível ainda: todos os workflows foram criados e validados estruturalmente (n8n_validate_workflow, 0 erros), mas ficam inativos, sem nenhuma chamada HTTP real feita, e sem workflow de agente cliente (AI Agent + prompt) — isso fica para quando houver uma clínica real e um canal de mensagens definido para cada um.

14.1 - Klingo

  • Spec: docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-klingo-design.md
  • Plano: docs/superpowers/plans/2026-08-11-mcp-server-nativo-n8n-klingo.md
  • Tools de apoio (spec/plano adicional): docs/superpowers/specs/2026-08-11-klingo-tools-de-apoio-design.md / docs/superpowers/plans/2026-08-11-klingo-tools-de-apoio.md
  • Fonte: gti-scheduling-mcp/docs/klingo-openapi.json (Swagger público) — único provider dos 4 com adapter TypeScript prévio testado (KlingoAdapter), portado fielmente.
  • 7 tools no servidor MCP Server - Klingo (3eiFEnfOTLnutP78): agendar (0PXwQZ3EXJUtuRgN), consultar_horarios (7ikOIk6mdoBwClC3), especialidade (VhDRpgVxC7Bq9ZMg), profissional (27HOTfmlTH0r5UiX), convenio (v8VGt7Du0zfbc2FT), unidade (Sms5egwOtmZkeIkw), preco (tSq0p8fRxS39CSWE).
  • Diferença de autenticação em relação ao Z-PRO: dois estágios — X-APP-TOKEN estático (credencial Klingo APP Token - clínica pendente, lwmRgDYe7W1zrKP5) para identificar o paciente e consultar catálogo, e um Bearer de sessão dinâmico (obtido na resposta de /paciente/identificar, nunca armazenado como credential) só para /agenda/reservar.
  • Limitação conhecida, sem solução: não existe endpoint público de listagem de procedimentos no Klingo — specialtyId/procedimento (exigido por agendar e opcionalmente por preco) não tem nenhuma tool que resolva. consultar_horarios sempre retorna SLOT_MAPPING_UNAVAILABLE pelo mesmo motivo já registrado no KlingoAdapter original (formato de horário individual não documentado no Swagger público).

14.2 - SysLife

  • Spec: docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-syslife-design.md
  • Plano: docs/superpowers/plans/2026-08-11-mcp-server-nativo-n8n-syslife.md
  • Fonte: Manual WS SysLife V3.4.pdf (fornecido pelo usuário) — sem adapter TypeScript prévio, único provider cuja fonte de verdade é só o manual.
  • 7 tools no servidor MCP Server - SysLife (TYu78UqIUr2yCBHK): especialidade, medico, convenio, paciente, procedimento, consultar_horarios (GET /Horario), agendar (PUT /Agenda).
  • Autenticação: Basic Auth fixo do WebService (usuário/senha documentados literalmente no manual, não por clínica) — credencial SysLife Basic Auth - clínica pendente (u8XXJ6wyrKuGJp4Y), reaproveitada nas 7 tools. Só o baseUrl (IP:porta) muda por clínica.
  • Ponto forte deste provider: o Horario GET retorna nuConsulta, que corresponde ao NumeroConsulta esperado no Agenda PUT — ciclo consultar→agendar fecha de verdade, diferente do Klingo.

14.3 - ClinicAll

  • Spec: docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-clinicall-design.md
  • Plano: docs/superpowers/plans/2026-08-11-mcp-server-nativo-n8n-clinicall.md
  • Fonte: docs/API Clinicall.pdf ("Documentação da API de Integração com ClinicAll para Módulo de Agendamento", v1.1.16, Focus Tecnologia em Sistemas) — a documentação mais completa e explícita dos 4 providers (campos obrigatórios, exemplos reais de request/response).
  • 8 tools no servidor MCP Server - ClinicAll (igaKjoHcPNYRAxPS): unidade, especialidade, convenio, profissional, procedimento, paciente, consultar_horarios (GET /disponibilidade/{idUnidade}/{idProfissional}), agendar (PUT /agendamento).
  • Duas pendências reais, sem credencial nem verbo assumido por invenção:
    1. Autenticação desconhecida — o manual não documenta nenhum header/token nas chamadas de TEntityController/TPatientController/TCalendarController. Nenhuma credencial foi criada; todos os nodes HTTP usam authentication: none. Existe um TAuthenticateController/login separado, mas não está claro se é pré-requisito nem que token ele gera.
    2. Verbo HTTP do agendamento não confirmado — /agendamento aceita GET/POST/PUT/DELETE sem o manual mapear qual verbo concilia um idAgenda livre já existente (o fluxo real é atualizar um registro pré-existente, não criar do zero). Assumido PUT; se não funcionar contra uma clínica real, tentar POST antes de qualquer outra hipótese.
  • Ponto forte deste provider: /disponibilidade retorna idAgenda de cada horário livre, e esse mesmo idAgenda é usado para "conciliar" o agendamento via /agendamento — mesmo padrão de ciclo fechado do SysLife, com a vantagem de já vir com nome do profissional/especialidade/unidade no mesmo payload.

14.4 - Padrão comum aos três (e ao Z-PRO)

Reforçando o que já vale desde a seção 13, agora confirmado em mais três implementações:

  • Cada provider = 1 workflow servidor (MCP Server Trigger + N Call n8n Sub-Workflow Tool) + N sub-workflows (1 por tool).
  • Sub-workflows chamados via Call n8n Sub-Workflow Tool precisam estar active: true para funcionar no caminho real do AI Agent (gotcha 1 da seção 13) — nenhum dos três providers desta seção foi ativado ainda, então isso só será re-confirmado quando houver teste real.
  • HTTP Request nodes sempre com neverError: true + fullResponse: true — captura manual de status/corpo, nunca deixa o n8n abortar em 4xx/5xx.
  • Tools de escrita (agendar) sempre com a regra "qualquer HTTP 2xx é sucesso operacional" — proteção contra duplicidade, nunca reportar erro numa operação que a API já aceitou.
  • Tools de leitura nunca reformatam o corpo de sucesso — devolvem cru, sem inventar um envelope que não foi confirmado por um exemplo real de resposta.
  • Mapeamento de parâmetros $fromAI(...) nas tools do servidor é sempre um passo manual na UI (resourceMapper não é confiável via API do n8n) — feito pelo usuário, não pela automação.
  • Nenhuma credencial é criada automaticamente pela automação — sempre pré-requisito manual do usuário na UI do n8n, mesmo quando o valor é só um placeholder de rascunho.

15. Configuração da IA via Google Docs — autonomia do gestor (só Z-PRO)

Data: 11/08/2026. Ver design completo em docs/superpowers/specs/2026-08-11-config-ia-google-docs-design.md e plano em docs/superpowers/plans/2026-08-11-config-ia-google-docs.md.

Motivação: o systemMessage do AI Agent era texto fixo hardcoded no workflow. Com o número de clientes crescendo (1 workflow de agente por clínica), editar manualmente o prompt de cada um toda vez que um gestor quisesse ajustar tom de voz, saudação, horário de funcionamento ou uma regra específica não escala. Solução: um Google Doc por clínica, público só para leitura (sem exigir credencial no n8n), editável diretamente pela conta do gestor — o systemMessage passa a concatenar as regras fixas de segurança (inalteradas) com o conteúdo do Doc.

Arquitetura implementada (4 nodes novos no workflow yG2mi6ECBpPv4Hmn):

"É step=process?" → Config Clínica → Buscar config da clínica ─┬→ Doc OK ──────┐
                     (docId fixo)     (GET export?format=txt,   └→ Doc falhou ─┴→ AI Agent
                                       sem credencial)
  • Config Clínica (Set): docId do Google Doc desta clínica, fixo por cópia do workflow (mesmo padrão de clinicId/baseUrl dos outros providers) — setado uma vez na instalação, nunca mais mexido depois disso.
  • Buscar config da clínica (HTTP Request): GET https://docs.google.com/document/d/{docId}/export?format=txt, sem autenticação (Doc público só para leitura), onError: continueErrorOutput.
  • Doc OK / Doc falhou (Set): reconstroem o item explicitamente a partir de $('Config Clínica').item.json + docContent (do corpo da resposta ou vazio, respectivamente).
  • systemMessage do AI Agent: ganhou uma seção final "Instruções específicas desta clínica:\n{{ $json.docContent }}", depois de todas as 7 regras fixas originais (que continuam idênticas, sem alteração de texto).

Bug real encontrado e corrigido durante a implementação — perda de contexto depois de um HTTP Request: o node HTTP Request substitui o $json inteiro pelo corpo da resposta, descartando qualquer campo que viesse do item anterior (sessionId, mensagem, telefone, nomeContato, clinicId). Isso quebrou a "Memória da Sessão" (Key parameter is empty, porque sessionKey depende de $json.sessionId) logo na primeira tentativa. Mesma classe de bug já registrada na seção 5 deste runbook (expressões em sub-nodes de IA), só que desta vez a causa foi upstream do AI Agent, não dentro dele.

Fix: os nodes Doc OK/Doc falhou não podem confiar em includeOtherFields quando há um HTTP Request no meio do caminho — precisam reconstruir cada campo explicitamente referenciando o node anterior ao HTTP Request por nome (={{ $('Config Clínica').item.json.sessionId }}, etc.), exatamente como já era feito em Classificar resultado nos sub-workflows de agendar dos MCP Servers (seção 13/14) — a lição "depois de um HTTP Request, resgate os campos anteriores pelo nome do node, nunca confie em passthrough automático" vale pra qualquer node no meio do fluxo principal, não só dentro de sub-workflows de tool.

Teste real de validação (11/08/2026), com um Google Doc de teste contendo a regra fictícia "não atendemos às segundas-feiras":

  1. Conteúdo do Doc apareceu naturalmente na resposta do agente (pergunta genérica sobre dias de atendimento).
  2. Regras fixas continuaram valendo (agente pediu confirmação do nome completo antes de agendar).
  3. Caminho de falha testado de propósito (docId inválido) — Google Docs respondeu 404, capturado pelo onError: continueErrorOutput, roteado pro branch Doc falhou, atendimento não quebrou (resposta normal, só sem a personalização da clínica).
  4. docId revertido pro valor real de teste depois da validação.

Resultado: workflow ativo em produção com a configuração de negócio já externalizada para o Google Doc de teste (1NmYRIoF7yD_B6N160_6Bpfv4NyJiryTTO2LFr9xNlYY). Falta trocar pelo Doc real de produção da clínica exemplo quando o gestor tiver o conteúdo definitivo. Padrão pronto pra replicar em Klingo/SysLife/ClinicAll quando esses tiverem workflow de agente.

16. Memória da sessão via Postgres (substitui o buffer em RAM, só Z-PRO)

Data: 11/08/2026. Ver design completo em docs/superpowers/specs/2026-08-11-memoria-sessao-postgres-design.md e plano em docs/superpowers/plans/2026-08-11-memoria-sessao-postgres.md.

Motivação: o node Memória da Sessão (memoryBufferWindow/"Simple Memory") guardava o histórico da conversa só em RAM do processo do n8n — não sobrevive a um reinício (deploy, crash, atualização) e não funcionaria em setups com múltiplos workers (queue mode). Trocado pelo node oficial Postgres Chat Memory, que persiste o histórico num banco.

Infraestrutura: o usuário provisionou um container Postgres, com um banco por cliente/clínica dentro dele (mesma filosofia de isolamento já usada pra docId, baseUrl/apiId dos MCP Servers). Credencial no n8n: Postgres Agendamento - (clínica exemplo) (xq3QAN3MZSOCVgdY), apontando pro banco do Z-PRO. Cada cliente futuro terá sua própria credencial, apontando pro banco dele no mesmo container.

Troca implementada (operação atômica — adicionar + conectar + remover, mesma lição da seção 15 sobre nós desconectados): saiu Memória da Sessão (memoryBufferWindow), entrou Memória da Sessão (Postgres) (@n8n/n8n-nodes-langchain.memoryPostgresChat, v1.4), com os mesmos parâmetros de sessão de sempre (sessionKey: ={{ $json.sessionId }}, contextWindowLength: 20). A tabela n8n_chat_histories foi criada automaticamente pelo node na primeira execução — sem setup manual de schema.

Sem migração de histórico: o histórico anterior só existia em RAM, não havia nada a migrar — mesmo efeito que já acontecia a cada reinício do n8n, só que agora deixa de acontecer daqui pra frente.

Teste real de validação (11/08/2026): duas mensagens enviadas em sequência ao webhook de produção, mesmo protocol (teste-memoria-postgres-01) — primeira mensagem informando um nome fictício, segunda perguntando "qual nome você anotou". O agente respondeu corretamente com o nome da primeira mensagem, confirmando que o contexto persistiu entre duas execuções separadas do workflow (prova de que não é mais RAM do processo, já que cada chamada webhook é uma execução isolada). Confirmação direta via SELECT na tabela n8n_chat_histories não foi feita (sem necessidade de dar acesso ao banco pra automação — a prova conversacional já foi considerada suficiente).

Resultado: workflow ativo em produção com memória de sessão persistida em Postgres. Padrão pronto pra replicar em Klingo/SysLife/ClinicAll quando esses tiverem workflow de agente — cada um com seu próprio banco dentro do mesmo container e sua própria credencial.

17. MCP Server standalone de Mensageria (Z-PRO) — reusável por qualquer provider

Data: 11/08/2026. Ver design completo em docs/superpowers/specs/2026-08-11-mcp-server-mensageria-zpro-design.md e plano em docs/superpowers/plans/2026-08-11-mcp-server-mensageria-zpro.md.

Motivação: a feature de "confirmação de agenda" (Klingo) precisa disparar mensagens de WhatsApp de forma proativa — capacidade que ainda não existia no projeto (tudo até então era resposta reativa a webhook). Decisão explícita do usuário: em vez de acoplar o envio ao MCP de agendamento de um provider específico, construir um MCP Server standalone só de mensageria, já que diferentes clientes usam canais diferentes (WABA oficial, não oficial, híbrido) — qualquer workflow futuro (confirmação, campanha, o que for, de qualquer provider) pode chamar essas tools sem depender de qual sistema de agendamento o cliente usa.

Escopo: 4 tools, reaproveitando a API de mensageria do Z-PRO (mesmo host apigchat.gtigrupo.com.br, endpoints diferentes dos de agendamento):

Tool Endpoint Uso
enviar_texto POST /v2/api/external/{ApiID}/ Texto simples — canal não oficial ou dentro da janela de 24h do WABA oficial
enviar_template POST .../template Template WABA aprovado, sem parâmetros dinâmicos
enviar_template_com_parametros POST .../templateBody Template WABA aprovado, com parâmetros dinâmicos no corpo
enviar_template_marketing POST .../templateMarketingBody Template WABA de marketing, com componente de header (ex.: imagem)

Arquitetura: mesmo padrão de sempre — MCP Server - Mensageria ZPRO (WsL4RlSD0hZ34gpB) + 4 sub-workflows (enviar_texto Y4ndG7GuIUrmVRxV, enviar_template E9lsmu8mlgzKFemk, enviar_template_com_parametros 8zj1V7yXOrdCAWVq, enviar_template_marketing WYakJ2GmV6fNW2iq). ApiID confirmado pelo usuário como o mesmo já validado pro agendamento (ab2d51db-54e3-48c2-8b97-114a20340809, credencial ZPRO API Token - Canal QR - MC AGENDAMENTO).

Bug real — $fromAI com == duplicado no início da expressão: ao mapear manualmente os campos de "Workflow Inputs" nos 4 nodes Call n8n Sub-Workflow Tool do servidor, os valores foram salvos como "=={{ $fromAI(...) }}" (dois = em vez de um) — a expressão nunca era avaliada, então todo argumento chegava null no sub-workflow e a API do Z-PRO rejeitava com 400 (body must be a string type... null). Fix: reescrever os campos com um único = no início ("={{ $fromAI(...) }}"), via patchNodeField/updateNode. Depois de corrigir, apareceu um segundo erro (Required → at isClosed): o $fromAI do campo opcional isClosed (boolean) não tinha valor padrão, então o schema da tool o tratava como obrigatório. Fix: adicionar o 4º argumento de default ao $fromAI (ex.: $fromAI('isClosed', '...', 'boolean', false)), mesma correção aplicada ao headerImageUrl opcional do template de marketing (default ''). Lição nova: sempre conferir visualmente o texto final salvo no campo depois de colar uma expressão $fromAI na UI — um = a mais não dá erro de validação estrutural do workflow, só falha silenciosamente em runtime com campos null.

Teste real de validação (11/08/2026): chamada tools/call direta via MCP (raw, sem AI Agent) pro tool enviar_texto, mandando uma mensagem de teste pro número pessoal do usuário (5575999091780, autorização explícita dada em chat). Resultado: {"success": true, "data": {"message": "Message sent successfully", "ticketId": 461590}} — mensagem confirmada recebida no celular de teste. Tools de template (enviar_template, enviar_template_com_parametros, enviar_template_marketing) ainda não testadas de verdade — precisam de um nome de template WABA real aprovado, não disponível no momento.

Fora de escopo desta rodada: envio de mídia (multipart/URL/Base64), busca de mensagem por wamid, e a própria feature de "confirmação de agenda" do Klingo (que motivou a criação deste MCP) — fica pro usuário montar depois, atribuindo estas tools no workflow que ele decidir.

Resultado: MCP Server de mensageria standalone, validado e testado com envio real, pronto para ser consumido por qualquer workflow futuro (confirmação de agenda ou outro), de qualquer provider.

18. Confirmação de Agenda via WhatsApp (Klingo Telefonia)

Data: 11/08/2026. Ver design completo em docs/superpowers/specs/2026-08-11-confirmacao-agenda-klingo-design.md e plano em docs/superpowers/plans/2026-08-11-confirmacao-agenda-klingo.md.

Motivação: permitir que o paciente confirme presença numa consulta agendada via WhatsApp, usando uma API separada da de agendamento do Klingo — a Klingo Telefonia (https://api-externa.klingo.app/api/telefonia, auth X-APP-TOKEN). Dois fluxos: um lembrete proativo (cron diário) e uma confirmação reativa (o paciente responde "sim"/"não" no WhatsApp). POST /entrada (registro de chamada telefônica) ficou fora do escopo por instrução explícita do usuário — "não envolve telefonia, apenas a confirmação no nosso sistema de WhatsApp".

MCP Server "Klingo Telefonia" (tSw2LGlOYVg9antR) — 6 tools:

Tool Endpoint Workflow id
listar_agendamentos_do_dia GET /lista/{data} hynQtoURFqpDUGTI
consultar_agendamento_por_id GET /{id} JXEaNHZSmiBWxDej
buscar_agendamento_pendente_por_cpf GET /lista_ultimo_por_cpf OJYHMUQlYv48Gw7h
confirmar_presenca POST /confirmar jdFH4T2fyd7YKNOa
registrar_nps POST /nps khUIxWFx7zF0tygP
consultar_bloqueios GET /bloqueios TfYHBjRkaL8gDmYR

Campos confirmados direto no spec OpenAPI real (api.swaggerhub.com/apis/agsx30/klingo-api-telefonia/1.0.0) durante a implementação — nada inventado. Pendências documentadas explicitamente:

  • Schema de /lista_ultimo_por_cpf e /bloqueios não documentado no spec — as respostas são tratadas como objeto genérico, sem assumir campos específicos.
  • Obrigatoriedade de callid em /confirmar é ambígua: o texto descritivo do endpoint sugere obrigatoriedade, mas nenhum campo do schema JSON está marcado required. Tratado como opcional — vazio para confirmações originadas no WhatsApp (sem chamada telefônica real).
  • Inconsistência de tipo do id_marcacao: aparece como string no schema marcacao (retornado por /lista/{data} e /{id}), mas como number obrigatório no body de /confirmar e /nps. Os sub-workflows convertem com Number(...) antes de enviar.
  • Os endpoints GET desta API aceitam filtros no corpo da requisição (incomum para GET) — implementado no node HTTP Request do n8n com method: "GET" + sendBody: true.

Workflow proativo "Lembrete de Confirmação - Klingo (exemplo)" (IvLzmASwa9LGaMxf): cron diário às 8h → calcula a data de amanhã → chama listar_agendamentos_do_dia (mesmo sub-workflow usado pela tool do MCP, via Execute Workflow direto — fluxo determinístico, sem IA) → loop pelos agendamentos → monta a mensagem de lembrete → chama enviar_texto do MCP Server - Mensageria ZPRO (Y4ndG7GuIUrmVRxV, seção 17), reaproveitando o envio já validado. Validado estruturalmente (0 erros), mas deixado inativo de propósito — sem clínica Klingo real, um cron ativo geraria só chamadas com erro contra a API e tentativas de envio com dados vazios.

Workflow de exemplo "Confirmação de Agenda - GChat - Klingo+Z-PRO (exemplo)" (F5jEliFFE3K9cW14): réplica estrutural do padrão da clínica exemplo (webhook → AI Agent → memória Postgres), mas sem cliente real associado — mesmo espírito dos MCP Servers de agendamento Klingo/SysLife/ClinicAll construídos sem clínica real. Contrato do webhook idêntico ao já documentado na seção 6 (body.protocol → sessionId, body.entrada → mensagem, body.contactName → nomeContato, body.number → telefone). Modelo de chat usa a credencial OpenAI real e compartilhada já em uso na clínica exemplo (29vMIDah5DTIhUYJ, "GPT") — não é uma credencial inventada. A memória Postgres fica com credencial placeholder (sem cliente real, sem banco provisionado ainda). Tools conectadas via MCP Client Tool (nativo), restritas a buscar_agendamento_pendente_por_cpf e confirmar_presenca (as outras 4 tools do MCP existem mas não foram atribuídas a este agente de exemplo). systemMessage fixo instruindo o agente a interpretar confirmação/recusa, buscar o id_marcacao pendente pelo CPF do paciente, e então confirmar (status: "C") ou recusar (status: "N"). Validado estruturalmente (0 erros), deixado inativo de propósito pela mesma razão do workflow de lembrete.

Resultado: MCP Server de confirmação de agenda (Klingo Telefonia) completo e validado estruturalmente, junto com os dois workflows de exemplo (lembrete proativo + AI Agent reativo) prontos pra ativar assim que houver uma clínica Klingo real com credencial X-APP-TOKEN e banco Postgres provisionado. Sem teste de ponta a ponta contra a API real — pendência explícita até então.

19. Confirmação de Agenda via WhatsApp (ClinicAll)

Data: 11/08/2026. Ver design completo em docs/superpowers/specs/2026-08-11-confirmacao-agenda-clinicall-design.md e plano em docs/superpowers/plans/2026-08-11-confirmacao-agenda-clinicall.md.

Motivação: mesmo objetivo da seção 18 (Klingo), agora para o ClinicAll — permitir que o paciente confirme presença numa consulta via WhatsApp. Diferente do Klingo, o ClinicAll não tem uma API de "Telefonia" separada: os endpoints de confirmação fazem parte do mesmo TCalendarController/TDomainController já usado no MVP de agendamento (seção 14.3), verificados diretamente no manual oficial (docs/API Clinicall.pdf, v1.1.16, relido nesta sessão).

MCP Server "ClinicAll - Confirmação de Agenda" (lHU5H0cZP4BJ6dWp) — 5 tools:

Tool Endpoint Workflow id
listar_agendamentos_do_dia GET /TCalendarController/agendamento/<data> 9pudW1QzBMh7c4ve
buscar_agendamento_por_cpf GET /TCalendarController/agendamentoSemPaciente (cpf + dataNascimento) i7Dw7xJZPpSbV3Ak
confirmar_presenca POST /TCalendarController/AgendamentoFlags 3mAkzfGwGeRSvWvO
consultar_estados_agenda GET /TDomainController/estadoAgenda EGX5whFSJX6ew50a
consultar_situacoes_agenda GET /TDomainController/situacaoAgenda YzFJ5evrw2bzJTGi

Diferenças reais em relação ao Klingo (mesma disciplina de não generalizar padrões entre providers sem verificar):

  • Strings exatas em vez de código curto: o Klingo aceita status: 'C'/'S'/'N' pra confirmar. O ClinicAll exige duas strings longas e exatas (estadoAgenda, situacaoAgenda — ex.: "CONFIRMADO PELA TELEFONISTA", "Agendado"), documentadas só nas tabelas de domínio — por isso consultar_estados_agenda/consultar_situacoes_agenda são tools obrigatórias no fluxo, não apoio opcional.
  • CPF + data de nascimento, não só CPF: agendamentoSemPaciente exige os dois campos, diferente do lista_ultimo_por_cpf do Klingo.
  • Telefone aninhado: no ClinicAll, o telefone do paciente vem em item.Paciente.telefoneCelular (objeto aninhado), não um campo direto do item como no Klingo (item.celular) — refletido na extração de dados do workflow de lembrete.
  • Sem NPS nem consulta de bloqueios: não documentados no manual do ClinicAll para este módulo — ficaram fora, sem inventar.
  • Pendência não verificada: o manual não esclarece se agendamentoSemPaciente (GET, POST) espera os parâmetros como query string ou body. Implementado como GET + query string, por analogia com todos os outros GETs deste manual (nenhum usa body) — suposição registrada, não testada contra a API real.
  • Mesma pendência de autenticação já registrada no MVP de agendamento do ClinicAll: authentication: "none" em todos os nodes HTTP (não httpHeaderAuth como no Klingo) — o manual do ClinicAll não documenta nenhum mecanismo de auth por requisição.

Workflow proativo "Lembrete de Confirmação - ClinicAll (exemplo)" (liBLpRUmbcnWk05V): mesmo desenho do Klingo (cron 8h → lista amanhã → loop → enviar_texto do MCP Mensageria ZPRO), com um filtro a mais — descarta itens com situacaoAgenda: "Livre" (sem idPaciente/ Paciente) antes de montar a mensagem. Validado (0 erros), deixado inativo de propósito.

Workflow de exemplo "Confirmação de Agenda - GChat - ClinicAll+Z-PRO (exemplo)" (ylc3Jcz239ra6XZK): mesmo padrão do Klingo (webhook → AI Agent → memória Postgres), systemMessage ajustado pra pedir CPF e data de nascimento, e pra sempre consultar consultar_estados_agenda/consultar_situacoes_agenda antes de chamar confirmar_presenca (nunca inventar a string exata). Tools conectadas via MCP Client Tool: buscar_agendamento_por_cpf, confirmar_presenca, consultar_estados_agenda, consultar_situacoes_agenda (listar_agendamentos_do_dia fica de fora, só serve ao workflow proativo). Validado (0 erros), deixado inativo de propósito.

Resultado: MCP Server de confirmação de agenda (ClinicAll) completo e validado estruturalmente, junto com os dois workflows de 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.