Spec: MCP Server nativo no n8n para o ClinicAll
Quarta aplicação do padrão nativo, a partir do manual oficial da Focus Tecnologia (docs/API Clinicall.pdf) -- documentação mais completa dos 4 providers até agora. 8 tools: unidade, especialidade, convenio, profissional, procedimento, paciente, consultar_horarios (GET /disponibilidade) e agendar (PUT /agendamento). Duas ambiguidades reais documentadas explicitamente: mecanismo de autenticação por requisição não especificado no manual (nenhuma credencial criada, authentication:none) e verbo HTTP de criação/atualização do agendamento não mapeado (assumido PUT, não verificado). Sem clínica ClinicAll real ainda -- validação estrutural apenas. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e2ed887a05
commit
04e5b189b0
@@ -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/<idUnidade>/<idProfissional>` | 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 <endpoint>] → [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://<host>:<porta>`).
|
||||
- **GET `<endpoint>`** (`HTTP Request`): URL
|
||||
`{{baseUrl}}/datasnap/rest/TEntityController/<endpoint>`,
|
||||
`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.
|
||||
Reference in New Issue
Block a user