Saltar para o conteúdo principal

Ligações a serviços externos

Esta página não é sobre o mesmo que Ligações. Lá, uma ligação faz uma linha de uma tabela apontar para linhas de outra (link_rows, create_link_column). Aqui, uma ligação a serviço externo é o registo, numa organização, de como as automações falam com um sistema de fora: o Metabase, ou qualquer serviço HTTP. É a mesma coisa que o diálogo «Nova ligação» das automações cria na aplicação.

Os argumentos de cada ferramenta estão em Ferramentas MCP, gerados do código. Uma automação usa a ligação pelo nome (ver Automações (WorkflowV2)).

O que uma ligação guarda​

  • Uma linha com o name, o label, o type (http para os dois modelos suportados) e o config: o endereço base, o tipo de autenticação e os endpoints conhecidos.
  • Os segredos (a chave de API, o token, a palavra-passe) vivem à parte, num cofre, por slot (apiKey, bearer, password). O config nunca os contém.

Os segredos nunca se leem de volta, nem pela API nem pelo MCP. Quem os escreveu não os consegue ver outra vez, e pela API não há como substituir um: regista uma ligação nova ou muda-o na aplicação. A resposta de create_connection diz só os nomes dos slots escritos (secret_slots); list_connections e get_connection devolvem a lista de slots vazia.

Permissões​

Criar e testar exigem a permissão de gerir ligações (connection.manage) na organização, a mesma que a aplicação pede, e, numa chave, os scopes write e structure (o structure é aditivo ao write). Na prática:

  • Um admin da organização passa.
  • Uma chave de API não é admin, mas passa se tem o scope structure e o papel editor ou acima (migração 423). Como só um admin cunha chaves, é uma delegação explícita: o admin que lhe deu structure deu-lhe também esta permissão.
  • Chaves sem structure, ou dos papéis user e view, recebem 403 permission_denied.
  • Uma chave confinada a um workspace também recebe 403 ao criar e ao testar: a ligação é um recurso da organização, não do workspace. A lista fica presa ao workspace da chave.

Ler (list_connections, get_connection) só pede uma chave com o scope read: vê o que a pertença à organização deixa ver.

Criar: create_connection​

ArgumentoSignificado
organization_idA organização dona da ligação. Obrigatório.
nameO nome, de 1 a 80 caracteres. É por ele que as automações a referem.
templatemetabase ou http. Qualquer outro dá 422 unsupported_template.
labelO rótulo visível. Por omissão, o name.
workspace_idOpcional. Restringe a ligação a um workspace da organização.
fieldsSó com metabase: {baseUrl, apiKey}.
configSó com http: o config HTTP cru (baseUrl, auth, endpoints). Até 64 KB.
secretsSó com http: {slot: valor}, cada valor de 1 a 4096 caracteres.
idempotency_keyOpcional. Torna a repetição segura.

Metabase​

Dás o endereço e a chave de API; o servidor constrói o resto exatamente como o template da aplicação: autenticação por cabeçalho x-api-key e um endpoint current_user (GET /api/user/current). O baseUrl é aparado e perde as barras finais.

{
"name": "create_connection",
"arguments": {
"organization_id": "3d6e8a1b-92c4-4f07-b5a3-7c1e0d9f2468",
"name": "metabase-dourum",
"label": "Metabase Dourum",
"template": "metabase",
"fields": {
"baseUrl": "https://metabase.exemplo.pt/",
"apiKey": "mb_xxxxxxxxxxxxxxxx"
}
}
}

A resposta traz o registo criado e o nome do slot escrito, nunca o valor:

{
"id": "b81f4c27-0e5a-4d93-a6c8-1f3e7b9d0a52",
"type": "http",
"name": "metabase-dourum",
"secret_slots": ["apiKey"],
"connection": {
"id": "b81f4c27-0e5a-4d93-a6c8-1f3e7b9d0a52",
"organization_id": "3d6e8a1b-92c4-4f07-b5a3-7c1e0d9f2468",
"workspace_id": null,
"type": "http",
"name": "metabase-dourum",
"label": "Metabase Dourum",
"config": {
"baseUrl": "https://metabase.exemplo.pt",
"auth": { "type": "apiKey", "headerName": "x-api-key" },
"endpoints": [
{ "name": "current_user", "kind": "data", "method": "GET", "path": "/api/user/current" }
],
"template": "metabase"
}
}
}

(A resposta real inclui também created_by, created_at e updated_at.)

HTTP genérico​

Para qualquer outro serviço dás tu o config e os segredos.

  • config.baseUrl é obrigatório e começa por http:// ou https://.
  • config.auth.type é um de none (omissão), apiKey, bearer, basic ou endpointLogin.
  • config.endpoints é uma lista de {name, method, path}; o kind é data (omissão) ou auth. O resto do config passa tal como o enviaste.
  • Cada tipo de autenticação lê um slot do cofre, e o servidor recusa a criação se faltar: apiKey pede secrets.apiKey, bearer pede secrets.bearer, basic pede secrets.password. none e endpointLogin não pedem nenhum.
{
"name": "create_connection",
"arguments": {
"organization_id": "3d6e8a1b-92c4-4f07-b5a3-7c1e0d9f2468",
"name": "faturacao",
"template": "http",
"config": {
"baseUrl": "https://api.faturacao.exemplo.pt",
"auth": { "type": "bearer" },
"endpoints": [
{ "name": "estado", "method": "GET", "path": "/v1/estado" }
]
},
"secrets": { "bearer": "tok_xxxxxxxxxxxxxxxx" }
}
}

Equivalente REST​

POST /v1/connections
Authorization: Bearer outdo_sk_...
Content-Type: application/json

{
"organization_id": "3d6e8a1b-92c4-4f07-b5a3-7c1e0d9f2468",
"name": "metabase-dourum",
"template": "metabase",
"fields": { "baseUrl": "https://metabase.exemplo.pt", "apiKey": "mb_xxxxxxxxxxxxxxxx" }
}

Responde 201 com o registo (ConnectionOut) e secret_slots. Precisa dos scopes write e structure e da permissão de gerir ligações na organização.

Como o servidor cria​

  1. Confirma a permissão de gerir ligações antes de escrever seja o que for.
  2. Grava a linha da ligação com a identidade da chave.
  3. Escreve cada segredo no cofre, por ordem.
  4. Se um segredo falhar, apaga a linha e responde 502 secret_store_failed; se nem apagar conseguir, responde 502 secret_store_failed_connection_kept com o connection_id que ficou, para o limpares à mão. Nunca fica uma ligação a meio sem o dizer.

Listar e ler​

list_connections (GET /v1/connections) devolve as ligações visíveis, por ordem do nome. Filtra por organization_id e workspace_id; sem filtros lista tudo o que vês. Na REST a página traz next_cursor e aceita cursor e limit.

{
"name": "list_connections",
"arguments": { "organization_id": "3d6e8a1b-92c4-4f07-b5a3-7c1e0d9f2468" }
}

get_connection (GET /v1/connections/{connection_id}) lê uma só, com o type, o name e o config; 404 se não existir ou não estiver visível. Nunca traz valores de segredos.

Testar: test_connection​

Chama o serviço de verdade e diz se a ligação funciona. Pede os scopes write e structure e a permissão de gerir ligações na organização.

ArgumentoSignificado
connection_idA ligação a testar.
endpoint_nameO endpoint a chamar. Sem ele, faz um GET ao baseUrl.
allow_mutatingfalse por omissão. Um endpoint cujo método pode alterar dados (POST, PUT, PATCH, DELETE) é recusado se não for true.

Para o Metabase, chama o endpoint current_user:

{
"name": "test_connection",
"arguments": {
"connection_id": "b81f4c27-0e5a-4d93-a6c8-1f3e7b9d0a52",
"endpoint_name": "current_user"
}
}

A resposta é {ok, status, message, body}. Um ok verdadeiro com um body que traz um email prova que a chave é válida.

Equivalente REST​

POST /v1/connections/{connection_id}:test
Authorization: Bearer outdo_sk_...
Content-Type: application/json

{ "endpoint_name": "current_user" }

Responde 200 com o veredito. O teste é feito pelo servidor da plataforma, por isso depende de ele estar configurado neste ambiente.

Arquivar e restaurar automações​

Arquivar tira uma automação das listas por omissão sem a apagar; restaurar devolve-a. Pede os scopes write e structure e a permissão de gerir a automação, como /versions e /apply (uma chave editor com structure chega).

OperaçãoRESTMCP
ArquivarPOST /v1/workflows-v2/{workflow_id}:archivearchive_workflow_v2
RestaurarPOST /v1/workflows-v2/{workflow_id}:restorerestore_workflow_v2
{
"name": "archive_workflow_v2",
"arguments": { "workflow_id": "9a4e6c31-5d28-4b70-8e19-0f7a3c2d1b64" }
}
  • Arquivar torna todas as versões do grupo inativas e marca-as arquivadas. É seguro repetir.
  • Restaurar tira a marca de arquivo e não reativa: a automação continua inativa até uma pessoa a ativar na aplicação, como sempre.
  • As duas respondem com a versão representativa da automação; 404 se o workflow_id não existir ou não estiver visível.
  • GET /v1/workflows-v2 aceita archived=true (só as arquivadas) ou archived=false (só as que não estão).

Erros​

Os erros trazem um code estável no corpo do problema, e as ferramentas MCP devolvem o mesmo code na mensagem.

EstadocodeQuando
403permission_deniedFalta a permissão de gerir ligações, o scope structure, ou a chave está confinada a um workspace.
404not_foundA organização, o workspace ou a ligação não existem ou não estão visíveis.
422unsupported_templateO template não é metabase nem http.
422fields_onlyconfig ou secrets com o template metabase.
422config_onlyfields com o template http.
422secret_requiredA autenticação pede um slot que secrets não traz; detail.slot diz qual.
422workspace_not_in_organizationO workspace_id é de outra organização.
502secret_store_failedUm segredo não ficou no cofre; a ligação foi removida.
502secret_store_failed_connection_keptIdem, e a ligação não pôde ser removida; detail.connection_id diz qual.
503upstream_unavailableO teste não está configurado neste ambiente, ou o servidor falhou.

Há ainda erros de validação do corpo sem code próprio, também 422: baseUrl em falta ou que não é http(s), apiKey vazia, auth.type desconhecido, um config acima de 64 KB. No teste, um 429 rate_limited quer dizer que há pedidos a mais. Um teste que corre mas dá ok: false não é um erro da chamada: é o veredito, e a message diz o que correu mal com o serviço de fora.

O que fica fora​

  • Outros modelos. mcp, smtp e ai_provider não se criam por aqui (422 unsupported_template); usa a aplicação.
  • Editar ou apagar uma ligação, e ler ou listar segredos. Pela API, para mudar um segredo regista uma ligação nova; na aplicação também se edita.
  • Ativar uma automação continua a ser só na aplicação.