Files
KLINGO-CLINICAL-SYSLIFE-GCHAT/docs/superpowers/plans/2026-08-11-klingo-tools-de-apoio.md
GustavoandClaude Sonnet 5 69b99b4212 Plano: tools de apoio do Klingo (especialidade, profissional, convenio, unidade, preco)
7 tasks: 5 sub-workflows novos de consulta (mesma credencial
X-APP-TOKEN já existente, sem sessão de paciente), adição desses 5
como novas tools no servidor MCP Server - Klingo já existente (via
addNode/addConnection, sem recriar o workflow), e revisão final +
commit. specialtyId/procedimento continua sem tool que resolva
(lacuna documentada na spec).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 00:22:36 -03:00

28 KiB

Tools de Apoio do Klingo 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, não commits de código; não há diff de git pra revisar por task). Steps use checkbox (- [ ]) syntax for tracking.

Goal: Adicionar 5 tools de apoio (especialidade, profissional, convenio, unidade, preco) ao MCP Server nativo do Klingo já existente, a partir de endpoints do Swagger não usados até agora.

Architecture: 5 sub-workflows novos, mesmo esqueleto simples (Execute Workflow Trigger → Config Klingo → [Montar query] → GET <endpoint> → Classificar resultado), acrescentados como novos nodes Call n8n Sub-Workflow Tool no workflow servidor já existente (MCP Server - Klingo, 3eiFEnfOTLnutP78) — sem criar um servidor novo.

Tech Stack: n8n (devn8n.gtigrupo.com.br), nodes oficiais @n8n/n8n-nodes-langchain (toolWorkflow), n8n-nodes-base (executeWorkflowTrigger, httpRequest, code, set).

Global Constraints

  • Nenhum código TypeScript é alterado.
  • As 5 tools são somente leitura (GET) — sem risco de duplicidade, então não precisam da proteção "2xx sempre é sucesso" do agendar; em caso de erro (fora de 2xx), classificação genérica já usada no restante do Klingo.
  • Em caso de sucesso (2xx), o corpo de resposta é devolvido cru, sem reformatar — sem exemplo de resposta real capturado pra validar contra.
  • Todas as 5 usam a credencial X-APP-TOKEN já existente (Klingo APP Token - clínica pendente, id lwmRgDYe7W1zrKP5) — nenhuma credencial nova é criada.
  • specialtyId/procedimento continua sem uma tool que resolva (lacuna documentada na spec, não resolvida por este plano).
  • Sem clínica Klingo real disponível: nenhuma chamada HTTP real é feita. Validação é só estrutural. Nada é ativado.

Spec de referência: docs/superpowers/specs/2026-08-11-klingo-tools-de-apoio-design.md


Task 1: Sub-workflow "MCP Server - Klingo - especialidade"

Interfaces:

  • Consumes: credencial Klingo APP Token - clínica pendente (lwmRgDYe7W1zrKP5).

  • Produces: workflow MCP Server - Klingo - especialidade, sem parâmetros de entrada, retorna o corpo cru de GET /agenda/especialidades ou erro classificado.

  • Step 1: Criar o workflow

{
  "name": "MCP Server - Klingo - especialidade",
  "nodes": [
    {
      "id": "trigger",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.2,
      "position": [0, 0],
      "parameters": { "inputSource": "passthrough" }
    },
    {
      "id": "config",
      "name": "Config Klingo",
      "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": "https://SUBSTITUIR-PELA-URL-REAL-DA-CLINICA.klingo.com.br" }
          ]
        }
      }
    },
    {
      "id": "get-especialidades",
      "name": "GET /agenda/especialidades",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [520, 0],
      "parameters": {
        "method": "GET",
        "url": "={{ $json.baseUrl }}/agenda/especialidades",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": false,
        "options": {
          "response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
          "timeout": 15000
        }
      },
      "credentials": {
        "httpHeaderAuth": { "id": "lwmRgDYe7W1zrKP5", "name": "Klingo APP Token - clínica pendente" }
      }
    },
    {
      "id": "classificar",
      "name": "Classificar resultado",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [780, 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 Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 404) {\n    return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 400 || status === 422) {\n    return { code: \"VALIDATION_ERROR\", message: `A API do Klingo rejeitou os dados enviados ao ${context} (status ${status}).` };\n  }\n  return { code: \"KLINGO_API_ERROR\", message: `A API do Klingo retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n  return { json: { success: false, error: classifyError(status, \"consultar especialidades\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
      }
    }
  ],
  "connections": {
    "Execute Workflow Trigger": { "main": [[{ "node": "Config Klingo", "type": "main", "index": 0 }]] },
    "Config Klingo": { "main": [[{ "node": "GET /agenda/especialidades", "type": "main", "index": 0 }]] },
    "GET /agenda/especialidades": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
  }
}

Guarde o id retornado como <wf-especialidade>.

  • Step 2: Validar

n8n_validate_workflow com {"id": "<wf-especialidade>"}. Esperado: sem erros.


Task 2: Sub-workflow "MCP Server - Klingo - profissional"

Interfaces:

  • Consumes: credencial Klingo APP Token - clínica pendente.

  • Produces: workflow MCP Server - Klingo - profissional, recebe idEspecialidade (opcional), retorna o corpo cru de GET /profissionais ou erro classificado.

  • Step 1: Criar o workflow

{
  "name": "MCP Server - Klingo - profissional",
  "nodes": [
    {
      "id": "trigger",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.2,
      "position": [0, 0],
      "parameters": {
        "inputSource": "workflowInputs",
        "workflowInputs": { "values": [{ "name": "idEspecialidade", "type": "string" }] }
      }
    },
    {
      "id": "config",
      "name": "Config Klingo",
      "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": "https://SUBSTITUIR-PELA-URL-REAL-DA-CLINICA.klingo.com.br" }
          ]
        }
      }
    },
    {
      "id": "montar-query",
      "name": "Montar query",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [520, 0],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const input = $json;\nconst queryParams = {};\nif (input.idEspecialidade) queryParams.id_especialidade = input.idEspecialidade;\n\nreturn {\n  json: {\n    baseUrl: input.baseUrl,\n    queryParams,\n  },\n};"
      }
    },
    {
      "id": "get-profissionais",
      "name": "GET /profissionais",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [780, 0],
      "parameters": {
        "method": "GET",
        "url": "={{ $json.baseUrl }}/profissionais",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "specifyQuery": "json",
        "jsonQuery": "={{ JSON.stringify($json.queryParams) }}",
        "options": {
          "response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
          "timeout": 15000
        }
      },
      "credentials": {
        "httpHeaderAuth": { "id": "lwmRgDYe7W1zrKP5", "name": "Klingo APP Token - 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 Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 404) {\n    return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 400 || status === 422) {\n    return { code: \"VALIDATION_ERROR\", message: `A API do Klingo rejeitou os dados enviados ao ${context} (status ${status}).` };\n  }\n  return { code: \"KLINGO_API_ERROR\", message: `A API do Klingo retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n  return { json: { success: false, error: classifyError(status, \"consultar profissionais\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
      }
    }
  ],
  "connections": {
    "Execute Workflow Trigger": { "main": [[{ "node": "Config Klingo", "type": "main", "index": 0 }]] },
    "Config Klingo": { "main": [[{ "node": "Montar query", "type": "main", "index": 0 }]] },
    "Montar query": { "main": [[{ "node": "GET /profissionais", "type": "main", "index": 0 }]] },
    "GET /profissionais": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
  }
}

Guarde o id retornado como <wf-profissional>.

  • Step 2: Validar

n8n_validate_workflow com {"id": "<wf-profissional>"}. Esperado: sem erros.


Task 3: Sub-workflow "MCP Server - Klingo - convenio"

Interfaces:

  • Consumes: credencial Klingo APP Token - clínica pendente.

  • Produces: workflow MCP Server - Klingo - convenio, sem parâmetros de entrada, retorna o corpo cru de GET /convenios ou erro classificado.

  • Step 1: Criar o workflow

Mesmo esqueleto exato da Task 1, trocando endpoint e mensagem de contexto:

{
  "name": "MCP Server - Klingo - convenio",
  "nodes": [
    {
      "id": "trigger",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.2,
      "position": [0, 0],
      "parameters": { "inputSource": "passthrough" }
    },
    {
      "id": "config",
      "name": "Config Klingo",
      "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": "https://SUBSTITUIR-PELA-URL-REAL-DA-CLINICA.klingo.com.br" }
          ]
        }
      }
    },
    {
      "id": "get-convenios",
      "name": "GET /convenios",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [520, 0],
      "parameters": {
        "method": "GET",
        "url": "={{ $json.baseUrl }}/convenios",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": false,
        "options": {
          "response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
          "timeout": 15000
        }
      },
      "credentials": {
        "httpHeaderAuth": { "id": "lwmRgDYe7W1zrKP5", "name": "Klingo APP Token - clínica pendente" }
      }
    },
    {
      "id": "classificar",
      "name": "Classificar resultado",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [780, 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 Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 404) {\n    return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 400 || status === 422) {\n    return { code: \"VALIDATION_ERROR\", message: `A API do Klingo rejeitou os dados enviados ao ${context} (status ${status}).` };\n  }\n  return { code: \"KLINGO_API_ERROR\", message: `A API do Klingo retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n  return { json: { success: false, error: classifyError(status, \"consultar convênios\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
      }
    }
  ],
  "connections": {
    "Execute Workflow Trigger": { "main": [[{ "node": "Config Klingo", "type": "main", "index": 0 }]] },
    "Config Klingo": { "main": [[{ "node": "GET /convenios", "type": "main", "index": 0 }]] },
    "GET /convenios": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
  }
}

Guarde o id retornado como <wf-convenio>.

  • Step 2: Validar

n8n_validate_workflow com {"id": "<wf-convenio>"}. Esperado: sem erros.


Task 4: Sub-workflow "MCP Server - Klingo - unidade"

Interfaces:

  • Consumes: credencial Klingo APP Token - clínica pendente.

  • Produces: workflow MCP Server - Klingo - unidade, sem parâmetros de entrada, retorna o corpo cru de GET /unidades ou erro classificado.

  • Step 1: Criar o workflow

Mesmo esqueleto exato da Task 1/3:

{
  "name": "MCP Server - Klingo - unidade",
  "nodes": [
    {
      "id": "trigger",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.2,
      "position": [0, 0],
      "parameters": { "inputSource": "passthrough" }
    },
    {
      "id": "config",
      "name": "Config Klingo",
      "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": "https://SUBSTITUIR-PELA-URL-REAL-DA-CLINICA.klingo.com.br" }
          ]
        }
      }
    },
    {
      "id": "get-unidades",
      "name": "GET /unidades",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [520, 0],
      "parameters": {
        "method": "GET",
        "url": "={{ $json.baseUrl }}/unidades",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": false,
        "options": {
          "response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
          "timeout": 15000
        }
      },
      "credentials": {
        "httpHeaderAuth": { "id": "lwmRgDYe7W1zrKP5", "name": "Klingo APP Token - clínica pendente" }
      }
    },
    {
      "id": "classificar",
      "name": "Classificar resultado",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [780, 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 Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 404) {\n    return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 400 || status === 422) {\n    return { code: \"VALIDATION_ERROR\", message: `A API do Klingo rejeitou os dados enviados ao ${context} (status ${status}).` };\n  }\n  return { code: \"KLINGO_API_ERROR\", message: `A API do Klingo retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n  return { json: { success: false, error: classifyError(status, \"consultar unidades\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
      }
    }
  ],
  "connections": {
    "Execute Workflow Trigger": { "main": [[{ "node": "Config Klingo", "type": "main", "index": 0 }]] },
    "Config Klingo": { "main": [[{ "node": "GET /unidades", "type": "main", "index": 0 }]] },
    "GET /unidades": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
  }
}

Guarde o id retornado como <wf-unidade>.

  • Step 2: Validar

n8n_validate_workflow com {"id": "<wf-unidade>"}. Esperado: sem erros.


Task 5: Sub-workflow "MCP Server - Klingo - preco"

Interfaces:

  • Consumes: credencial Klingo APP Token - clínica pendente.

  • Produces: workflow MCP Server - Klingo - preco, recebe idProcedimento, idPlano (obrigatórios pela API — sem validação prévia no lado n8n, a própria API classifica se algo faltar), idMedico, idUnidade (opcionais), retorna o corpo cru de GET /preco ou erro classificado.

  • Step 1: Criar o workflow

{
  "name": "MCP Server - Klingo - preco",
  "nodes": [
    {
      "id": "trigger",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.2,
      "position": [0, 0],
      "parameters": {
        "inputSource": "workflowInputs",
        "workflowInputs": {
          "values": [
            { "name": "idProcedimento", "type": "string" },
            { "name": "idPlano", "type": "string" },
            { "name": "idMedico", "type": "string" },
            { "name": "idUnidade", "type": "string" }
          ]
        }
      }
    },
    {
      "id": "config",
      "name": "Config Klingo",
      "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": "https://SUBSTITUIR-PELA-URL-REAL-DA-CLINICA.klingo.com.br" }
          ]
        }
      }
    },
    {
      "id": "montar-query",
      "name": "Montar query",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [520, 0],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const input = $json;\nconst queryParams = {\n  id_procedimento: input.idProcedimento,\n  id_plano: input.idPlano,\n};\nif (input.idMedico) queryParams.id_medico = input.idMedico;\nif (input.idUnidade) queryParams.id_unidade = input.idUnidade;\n\nreturn {\n  json: {\n    baseUrl: input.baseUrl,\n    queryParams,\n  },\n};"
      }
    },
    {
      "id": "get-preco",
      "name": "GET /preco",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [780, 0],
      "parameters": {
        "method": "GET",
        "url": "={{ $json.baseUrl }}/preco",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "specifyQuery": "json",
        "jsonQuery": "={{ JSON.stringify($json.queryParams) }}",
        "options": {
          "response": { "response": { "fullResponse": true, "neverError": true, "responseFormat": "autodetect" } },
          "timeout": 15000
        }
      },
      "credentials": {
        "httpHeaderAuth": { "id": "lwmRgDYe7W1zrKP5", "name": "Klingo APP Token - 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 Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 404) {\n    return { code: \"NOT_FOUND\", message: `Recurso não encontrado na API do Klingo ao ${context} (status ${status}).` };\n  }\n  if (status === 400 || status === 422) {\n    return { code: \"VALIDATION_ERROR\", message: `A API do Klingo rejeitou os dados enviados ao ${context} (status ${status}).` };\n  }\n  return { code: \"KLINGO_API_ERROR\", message: `A API do Klingo retornou um erro inesperado ao ${context} (status ${status}).` };\n}\n\nif (status < 200 || status >= 300) {\n  return { json: { success: false, error: classifyError(status, \"consultar preço\") } };\n}\n\nreturn { json: { success: true, data: rawBody } };"
      }
    }
  ],
  "connections": {
    "Execute Workflow Trigger": { "main": [[{ "node": "Config Klingo", "type": "main", "index": 0 }]] },
    "Config Klingo": { "main": [[{ "node": "Montar query", "type": "main", "index": 0 }]] },
    "Montar query": { "main": [[{ "node": "GET /preco", "type": "main", "index": 0 }]] },
    "GET /preco": { "main": [[{ "node": "Classificar resultado", "type": "main", "index": 0 }]] }
  }
}

Guarde o id retornado como <wf-preco>.

  • Step 2: Validar

n8n_validate_workflow com {"id": "<wf-preco>"}. Esperado: sem erros.


Task 6: Adicionar as 5 tools ao workflow "MCP Server - Klingo" (já existente)

Interfaces:

  • Consumes: <wf-especialidade> (Task 1), <wf-profissional> (Task 2), <wf-convenio> (Task 3), <wf-unidade> (Task 4), <wf-preco> (Task 5).

  • Modifica: workflow MCP Server - Klingo (3eiFEnfOTLnutP78) — acrescenta 5 nodes, não remove nada existente (agendar e consultar_horarios continuam intactos).

  • Step 1: Adicionar os 5 nodes de tool e suas conexões

n8n_update_partial_workflow com {"id": "3eiFEnfOTLnutP78", "operations": [...]}:

[
  {
    "type": "addNode",
    "node": {
      "id": "tool-especialidade",
      "name": "especialidade",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [260, 340],
      "parameters": {
        "description": "Lista as especialidades médicas disponíveis na clínica, com o código de cada uma. Sem parâmetros de entrada.",
        "source": "database",
        "workflowId": { "value": "<wf-especialidade>", "mode": "id" }
      }
    }
  },
  {
    "type": "addNode",
    "node": {
      "id": "tool-profissional",
      "name": "profissional",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [260, 420],
      "parameters": {
        "description": "Lista os médicos/profissionais, opcionalmente filtrados por especialidade (idEspecialidade, obtido via a tool especialidade). Retorna nome, CRM e conselho de cada um.",
        "source": "database",
        "workflowId": { "value": "<wf-profissional>", "mode": "id" }
      }
    }
  },
  {
    "type": "addNode",
    "node": {
      "id": "tool-convenio",
      "name": "convenio",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [260, 500],
      "parameters": {
        "description": "Lista os convênios aceitos pela clínica e seus planos (nome, id, código de cada plano). Sem parâmetros de entrada.",
        "source": "database",
        "workflowId": { "value": "<wf-convenio>", "mode": "id" }
      }
    }
  },
  {
    "type": "addNode",
    "node": {
      "id": "tool-unidade",
      "name": "unidade",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [260, 580],
      "parameters": {
        "description": "Lista as unidades físicas da clínica (nome, CEP, código CNES, local). Sem parâmetros de entrada.",
        "source": "database",
        "workflowId": { "value": "<wf-unidade>", "mode": "id" }
      }
    }
  },
  {
    "type": "addNode",
    "node": {
      "id": "tool-preco",
      "name": "preco",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [260, 660],
      "parameters": {
        "description": "Consulta o valor de um procedimento para um plano específico. Exige idProcedimento e idPlano já conhecidos por outro meio — este provider não tem uma tool que liste procedimentos disponíveis (lacuna conhecida do Klingo).",
        "source": "database",
        "workflowId": { "value": "<wf-preco>", "mode": "id" }
      }
    }
  },
  { "type": "addConnection", "source": "especialidade", "target": "MCP Server Trigger", "sourceOutput": "ai_tool" },
  { "type": "addConnection", "source": "profissional", "target": "MCP Server Trigger", "sourceOutput": "ai_tool" },
  { "type": "addConnection", "source": "convenio", "target": "MCP Server Trigger", "sourceOutput": "ai_tool" },
  { "type": "addConnection", "source": "unidade", "target": "MCP Server Trigger", "sourceOutput": "ai_tool" },
  { "type": "addConnection", "source": "preco", "target": "MCP Server Trigger", "sourceOutput": "ai_tool" }
]

Substitua os 5 <wf-...> pelos IDs reais das Tasks 1-5.

  • Step 2: Mapear os parâmetros na UI (passo manual — resourceMapper não é confiável via API)

Abrir os nodes profissional e preco na UI do n8n (os únicos com parâmetro — especialidade, convenio e unidade não têm nenhum). Em "Workflow Inputs":

profissional:

idEspecialidade: ={{ $fromAI('idEspecialidade', 'Código da especialidade retornado pela tool especialidade, para filtrar os médicos (opcional — sem ele lista todos)', 'string') }}

preco:

idProcedimento: ={{ $fromAI('idProcedimento', 'Código do procedimento — só use se já souber esse código por outro meio, não há tool que liste procedimentos disponíveis neste provider', 'string') }}
idPlano: ={{ $fromAI('idPlano', 'Código do plano retornado pela tool convenio', 'string') }}
idMedico: ={{ $fromAI('idMedico', 'Código do médico retornado pela tool profissional (opcional)', 'string') }}
idUnidade: ={{ $fromAI('idUnidade', 'Código CNES da unidade retornado pela tool unidade (opcional)', 'string') }}
  • Step 3: Validar (sem ativar)

n8n_validate_workflow com {"id": "3eiFEnfOTLnutP78"}. Esperado: sem erros — 8 tools no total (2 já existentes + 5 novas + o trigger). Confirmar que agendar e consultar_horarios continuam funcionando (nenhuma conexão existente foi removida). Não ativar — mesma decisão já tomada pro Klingo inteiro, sem clínica real nem workflow de agente cliente ainda.


Task 7: Revisão final e commit

Interfaces:

  • Consumes: workflows das Tasks 1-6.

  • Step 1: Validação estrutural final

Rodar n8n_validate_workflow nos 5 novos sub-workflows e no servidor atualizado (3eiFEnfOTLnutP78) com {"options": {"profile": "ai-friendly"}}. Esperado: sem erros em nenhum.

  • Step 2: Atualizar a spec com os IDs reais

Editar docs/superpowers/specs/2026-08-11-klingo-tools-de-apoio-design.md, adicionando ao final uma seção "Status desta etapa" com os 5 IDs de sub-workflow novos e a confirmação de que o servidor (3eiFEnfOTLnutP78) agora tem 7 tools no total (agendar, consultar_horarios + as 5 novas).

  • Step 3: Commit
cd "D:\PROJETOS\KLINGO-CLINICAL-SYSLIFE-GCHAT-AGENDAMENTO"
git add docs/superpowers/specs/2026-08-11-klingo-tools-de-apoio-design.md
git commit -m "docs: registra IDs das tools de apoio do Klingo (especialidade, profissional, convenio, unidade, preco)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>"

Observação sobre execução

Mesmo padrão dos planos anteriores do Klingo/SysLife: tasks são chamadas de API ao n8n, não commits de código. A Task 6 modifica um workflow já existente em produção (estrutural, active: false) em vez de criar um novo — usar n8n_update_partial_workflow com addNode/addConnection, nunca recriar o workflow do zero, para não perder o agendar/consultar_horarios já configurados.