diff --git a/docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-clinicall-design.md b/docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-clinicall-design.md new file mode 100644 index 0000000..3b7054d --- /dev/null +++ b/docs/superpowers/specs/2026-08-11-mcp-server-nativo-n8n-clinicall-design.md @@ -0,0 +1,207 @@ +# Design — MCP Server nativo no n8n para o ClinicAll + +**Data:** 2026-08-11 +**Status:** Aprovado pelo usuário, aguardando plano de implementação. + +## Objetivo + +Quarta aplicação do padrão de "MCP Server" nativo do n8n (`MCP Server +Trigger` + `Call n8n Sub-Workflow Tool`), já validado em produção pro +Z-PRO e estruturalmente pronto pro Klingo e pro SysLife, agora pro +ClinicAll — a partir do manual oficial fornecido pelo usuário +(`docs/API Clinicall.pdf`, "Documentação da API de Integração com +ClinicAll para Módulo de Agendamento", versão 1.1.16, Focus Tecnologia em +Sistemas). É a documentação mais completa dos 4 providers até agora: +REST/JSON, campos obrigatórios explícitos, exemplos reais de +request/response para todos os endpoints relevantes. + +## Relação com o trabalho anterior + +Mesma arquitetura de base do Z-PRO/Klingo/SysLife. O ClinicAll não tem +adapter TypeScript prévio em `gti-scheduling-mcp` — a fonte de verdade é +exclusivamente o manual PDF fornecido nesta sessão. + +## Contexto verificado (manual oficial, v1.1.16) + +Todos os endpoints usam o contexto fixo `/datasnap/rest`, formato REST/JSON. + +| Controller | Endpoint | Método | Parâmetros | Retorna | +| --- | --- | --- | --- | --- | +| `TEntityController` | `/unidades` | GET | `nome` (opcional) | lista `{idUnidade, nomeUnidade, cnpjUnidade}` | +| `TEntityController` | `/especialidades` | GET | `nome` (opcional) | lista `{idEspecialidade, nomeEspecialidade}` | +| `TEntityController` | `/convenios` | GET | `nome` (opcional) | lista `{idConvenio, nomeConvenio, cnpj, numeroANS, situacaoConvenio}` | +| `TEntityController` | `/profissionais` | GET | `nome` (opcional) | lista `{idProfissional, nomeProfissional, situacaoProfissional, ..., especialidades[], horarios[]}` | +| `TEntityController` | `/procedimentos` | GET | `nome`, `grp` (opcionais) | lista `{idProcedimento, nomeProcedimento, grupoProcedimento}` | +| `TPatientController` | `/paciente` | GET/POST/PUT/DELETE | `busca` (nome ou id) | lista de objeto Paciente completo | +| `TCalendarController` | `/disponibilidade//` | GET | route: `idUnidade`, `idProfissional`; query opcionais: `m` (meses), `p` (procedimento), `e` (especialidade), `c` (convênio) | lista de `{idUnidade, nomeUnidade, idEspecialidade, nomeEspecialidade, idMedico, conselho, nomeMedico, dataAgenda, horarios: [{idAgenda, horaAgenda}]}` | +| `TCalendarController` | `/agendamento` | GET/POST/PUT/DELETE | corpo com `idAgenda, idUnidade, idPaciente, idProfissional, idProcedimento, dataAgenda, horaAgenda, idConvenio, carteiraConvenio, validadeCarteiraConvenio, usuario (obrigatório), senhaAutorizacao` | objeto agendamento (echo com dados conciliados) | + +**Fluxo real de agendamento** (conforme diagrama do manual, seção 3): o +sistema externo consulta `/disponibilidade` para obter horários livres +(cada um já é um registro `idAgenda` existente, `situacaoAgenda: "Livre"`) +e depois "concilia" esse registro — atualiza o mesmo `idAgenda` com os +dados do paciente/procedimento/convênio via `/agendamento`. Não é criar +um registro novo do zero; é atualizar um que já existe. + +## Ambiguidade real: qual verbo HTTP cria/atualiza o agendamento + +O manual lista `/agendamento` como aceitando `GET, POST, PUT, DELETE`, +sem mapear explicitamente qual verbo corresponde a "conciliar um +`idAgenda` já existente". Dado que o fluxo real é uma **atualização** de +um registro que já existe (o `idAgenda` livre obtido via +`/disponibilidade`), a decisão desta etapa é usar **`PUT`**. Esta é uma +suposição não verificada contra a API real — fica registrada +explicitamente, não é um fato confirmado pelo manual. Se, ao testar +contra uma clínica real, `PUT` não funcionar como esperado, tentar `POST` +antes de qualquer outra hipótese. + +## Ambiguidade real: mecanismo de autenticação por requisição + +O manual não documenta nenhum header de autenticação (token, Bearer, +API key) nos exemplos de `TEntityController`, `TPatientController` ou +`TCalendarController`. Existe um `TAuthenticateController/login` +separado (`POST`, `{userName, password}` → `{login, nomeUsuario}` ou +`401` com mensagem de erro), mas o manual não explica se é obrigatório +chamá-lo antes das demais requisições, nem que token/sessão ele geraria +para as chamadas seguintes. + +**Decisão desta etapa**: não inventar um mecanismo de autenticação. +Todos os nodes HTTP são construídos com `authentication: none`. Isso é +uma limitação deliberada e documentada — não uma omissão. Resolver isso +exige acesso a uma clínica ClinicAll real (para testar empiricamente) ou +contato com o suporte da Focus Tecnologia em Sistemas. + +## Escopo + +**8 tools**, cobrindo tudo que um agendamento completo precisa perguntar +e confirmar: `unidade`, `especialidade`, `convenio`, `profissional`, +`procedimento`, `paciente`, `consultar_horarios`, `agendar`. + +## Arquitetura + +``` +[MCP Server Trigger] ──Tools──┬── unidade ──▶ GET /unidades + ("MCP Server - ClinicAll") ├── especialidade ──▶ GET /especialidades + ├── convenio ──▶ GET /convenios + ├── profissional ──▶ GET /profissionais + ├── procedimento ──▶ GET /procedimentos + ├── paciente ──▶ GET /paciente + ├── consultar_horarios ──▶ GET /disponibilidade/{idUnidade}/{idProfissional} + └── agendar ──▶ PUT /agendamento +``` + +9 workflows no total (servidor + 8 sub-workflows). Sem workflow de +agente cliente — mesma decisão já tomada no Klingo e no SysLife (sem +clínica real nem canal de mensagens definido ainda). + +## Componentes + +### Sub-workflows de catálogo (`unidade`, `especialidade`, `convenio`, `profissional`, `procedimento`) + +Mesmo esqueleto simples, cada um só troca endpoint/parâmetro: + +``` +[Execute Workflow Trigger] → [Config ClinicAll] → [Montar query]* → [GET ] → [Classificar resultado] +``` + +(*`Montar query` só existe quando há parâmetro opcional a passar — +todos os 5 aceitam um parâmetro de busca por nome, exceto `procedimento` +que aceita `nome` e `grp`.) + +- **Execute Workflow Trigger**: `nome` (opcional) em `unidade`, + `especialidade`, `convenio`, `profissional`; `nome` e `grp` (ambos + opcionais) em `procedimento`. +- **Config ClinicAll** (`Set`): `baseUrl` desta clínica (placeholder, + formato `http://:`). +- **GET ``** (`HTTP Request`): URL + `{{baseUrl}}/datasnap/rest/TEntityController/`, + `authentication: none`, `neverError: true` + `fullResponse: true`. +- **Classificar resultado** (`Code`): 2xx → devolve o corpo cru como veio + (sem reformatar — sem exemplo de erro real capturado pra validar + contra, mesmo raciocínio do SysLife/Klingo). Fora de 2xx → taxonomia + genérica por status HTTP (`AUTHENTICATION_ERROR` 401/403, `NOT_FOUND` + 404, `VALIDATION_ERROR` 400/422, `CLINICALL_API_ERROR` demais) — o + manual não documenta nenhum código de erro específico do ClinicAll + para estes controllers. + +### Sub-workflow `paciente` + +``` +[Execute Workflow Trigger] → [Config ClinicAll] → [Montar query] → [GET /paciente] → [Classificar resultado] +``` + +- **Execute Workflow Trigger**: `busca` (nome ou id do paciente, + conforme documentado). +- Resto idêntico ao padrão de catálogo acima, endpoint + `TPatientController/paciente`. + +### Sub-workflow `consultar_horarios` + +``` +[Execute Workflow Trigger] → [Config ClinicAll] → [Montar URL/query] → [GET /disponibilidade/{idUnidade}/{idProfissional}] → [Classificar resultado] +``` + +- **Execute Workflow Trigger**: `idUnidade`, `idProfissional` + (obrigatórios, route params), `meses`, `procedimento`, + `especialidade`, `convenio` (opcionais, query params `m`/`p`/`e`/`c`). +- **Montar URL/query** (`Code`): monta a URL com os route params + interpolados e os query params opcionais só quando presentes. +- Resto idêntico ao padrão de catálogo. + +### Sub-workflow `agendar` + +``` +[Execute Workflow Trigger] → [Config ClinicAll] → [Montar corpo] → [PUT /agendamento] → [Classificar resultado] +``` + +- **Execute Workflow Trigger**: `idAgenda` (obrigatório — vem de + `consultar_horarios`), `idUnidade`, `idPaciente`, `idProfissional`, + `idProcedimento`, `dataAgenda`, `horaAgenda`, `idConvenio`, + `carteiraConvenio`, `validadeCarteiraConvenio`, `usuario` + (obrigatório, conforme documentado), `senhaAutorizacao` (opcional). +- **Montar corpo** (`Code`): monta exatamente o JSON documentado, sem + campo extra. +- **PUT `/datasnap/rest/TCalendarController/agendamento`**: + `authentication: none`, `neverError: true` + `fullResponse: true`. +- **Classificar resultado** (`Code`): mesma proteção contra duplicidade + já usada nos outros três providers — **qualquer 2xx é sucesso + operacional**, sem exceção. Tenta mapear o objeto de agendamento + documentado (echo com `idAgenda`, `situacaoAgenda`/`estadoAgenda` + atualizados); se o corpo não bater, devolve "aceito, mapeamento + pendente" construído só com os dados do input. Fora de 2xx: mesma + classificação genérica. + +## Credenciais + +**Nenhuma credencial é criada nesta rodada.** Todos os 8 nodes HTTP +ficam com `authentication: none`, até sabermos o mecanismo real de +autenticação do ClinicAll (ver seção de ambiguidade acima). + +## Fora de escopo (adiado) + +- `TDomainController` (tabelas de domínio genéricas: sexo, raça, UF, + município, operadora, dia da semana, estados/situações de agenda — não + específicas de agendamento). +- `TDocumentController`, `TReportController`, `TBIController` + (documentos, relatórios, indicadores de BI — não fazem parte de + realizar um agendamento). +- `cobertura` (procedimentos cobertos por convênio), + `valorprocedimentos`, `gruposProcedimento` (informativos + complementares — podem ser adicionados depois se o agente precisar + confirmar cobertura/valor antes de agendar, mas não são essenciais ao + MVP). +- `TAuthenticateController/login` — fica pendente até resolvermos o + mecanismo de autenticação real. +- Workflow de agente cliente (AI Agent + prompt + MCP Client Tool) — + mesma decisão já tomada no Klingo e no SysLife, sem clínica real nem + canal de mensagens definido. + +## Testes + +Sem clínica ClinicAll real disponível: validação estrutural apenas +(`n8n_validate_workflow`), nenhuma chamada HTTP real nesta etapa. Quando +houver uma clínica real, a autenticação precisa ser resolvida **antes** +de qualquer teste (ver ambiguidade acima) — não adianta testar o fluxo +de agendamento sem isso. Depois de resolvida, mesma disciplina já usada +nos outros providers: dado fictício, execução única por vez, conferência +visual no ClinicAll antes de qualquer nova tentativa.