Autenticação
O servidor MCP aceita um Bearer token no cabeçalho Authorization, e nada além disso — sem cookie, sem certificado de cliente, sem token na URL. Uma requisição com ?access_token= (ou ?token= e afins) é recusada com 401, mesmo acompanhada de um cabeçalho válido: na URL o token vaza para logs, histórico do navegador e intermediários.
Esse token é um access token OAuth 2.1 emitido pelo authorization server da Kobana (https://account.kobana.com.br), um JWT assinado em RS256 e emitido para este recurso: o aud dele é https://mcp.finance.kobana.com.br. Ele chega por um de dois caminhos — o fluxo OAuth, feito pelo próprio cliente, ou um token pessoal que você cria na sua Conta Kobana — e é verificado do mesmo jeito nos dois casos.
Authorization: Bearer eyJhbGciOiJSUzI1NiIs…
:::info Cada superfície tem a sua audience
Um token emitido para o MCP não vale na API REST (api.finance.*), e um token da API não vale aqui. É o que impede que o token entregue a um assistente seja reaproveitado contra a API — e o contrário.
:::
Dois jeitos de conectar
| Fluxo OAuth | Token pessoal | |
|---|---|---|
| Como você obtém | Cola a URL no cliente; ele abre o login da Kobana e você autoriza | Cria em Conta Kobana → Tokens e Acesso → Novo Token Pessoal: app Financeiro Inteligente, uso MCP, recursos e acessos, validade |
| Como o cliente usa | Sozinho, depois da autorização | Você cola no cliente como Authorization: Bearer <token> |
| Validade | Curta, renovada pelo cliente | De 7 dias a 1 ano, escolhida por você |
| Escopo | Só o nível de acesso — hoje, read | Os recursos e acessos que você marcou |
| Bom para | Claude, ChatGPT, IDEs e qualquer cliente com OAuth | Clientes sem suporte a OAuth, scripts, e agentes que precisam escrever |
O token pessoal tem que ser criado com o uso MCP. Um token criado para API REST tem a audience da API e é recusado aqui com 401 — e o contrário também vale.
O workspace
O org do token diz a organização; o workspace em que cada tool age é decidido a cada chamada, nesta ordem:
| Ordem | De onde vem |
|---|---|
| 1 | O argumento workspace_id da tool, quando vem na chamada |
| 2 | O workspace padrão da conexão (abaixo) |
| — | Nenhum dos dois: a tool volta o erro workspace_required |
A URL do servidor não precisa de workspace — https://mcp.finance.kobana.com.br basta —, e conectar nunca falha por falta dele. Para saber onde pode agir, o agente chama finance_workspaces_list, sem argumentos: ela lista os workspaces da organização que a pessoa do token alcança.
{ "data": [
{ "id": "2b93f876-769a-4bdc-b23e-304957f313b4", "name": "Matriz", "default": true },
{ "id": "7c1d0e52-…", "name": "Filial Sul", "default": false }
] }
Toda outra tool — menos finance_schemas_get e a própria finance_workspaces_list — aceita o argumento opcional workspace_id (uuid):
{ "name": "finance_payables_list",
"arguments": { "workspace_id": "2b93f876-769a-4bdc-b23e-304957f313b4", "limit": 10 } }
O workspace padrão
É o que vale quando a chamada não traz workspace_id, e é o que vem marcado default: true em finance_workspaces_list:
| Onde | Exemplo |
|---|---|
Cabeçalho X-Workspace-Id (opcional) | X-Workspace-Id: 2b93f876-769a-4bdc-b23e-304957f313b4 |
| Parâmetro na URL do servidor (opcional) | https://mcp.finance.kobana.com.br/?workspace_id=2b93f876-… |
| Nenhum dos dois | O único workspace que a pessoa alcança, se ela alcança exatamente um |
O cabeçalho e o parâmetro de URL continuam aceitos, mas agora são opcionais e só definem o padrão: o argumento workspace_id sempre ganha deles. Em qualquer caso o valor é seletor, não concessão — ele é conferido contra a organização do token e o acesso da pessoa:
-
Sem
workspace_ide sem padrão — a pessoa alcança vários workspaces —, a tool voltaworkspace_required. É um resultado de tool comisError: true, não um erro HTTP:{ "error": { "code": "workspace_required", "message": "…" } } -
Um
workspace_idque a pessoa não alcança, ou que não existe, volta o erro de toolworkspace_access_denied— a mesma resposta nos dois casos. -
Um cabeçalho ou parâmetro de URL com um workspace de outra organização continua recusado com HTTP
403UNKNOWN_WORKSPACE.
Resources (kobana://finance/…) e completions não têm argumento de workspace: usam o padrão da conexão. Sem padrão, ler um resource de registro falha com workspace_required — use as tools —, e as completions não sugerem nada. Veja Resources e prompts.
O fluxo OAuth
Você não executa nenhum destes passos: o cliente MCP (Claude, ChatGPT, uma IDE) faz tudo sozinho a partir da URL. Eles estão aqui para quando algo falhar no meio.
-
Desafio. Uma requisição sem token recebe
401com o desafio que todo resource server OAuth 2.1 deve mandar (RFC 9728):WWW-Authenticate: Bearer realm="kobana-finance-mcp",error="invalid_token",resource_metadata="https://mcp.finance.kobana.com.br/.well-known/oauth-protected-resource" -
Metadata do recurso. O cliente lê o documento apontado. Ele é público e não carrega segredo nenhum — só ponteiros:
curl https://mcp.finance.kobana.com.br/.well-known/oauth-protected-resource{"resource": "https://mcp.finance.kobana.com.br","authorization_servers": ["https://account.kobana.com.br"],"bearer_methods_supported": ["header"],"resource_documentation": "https://docs.finance.kobana.com.br/pt/mcp/overview/introduction"}Não há
scopes_supported: a Conta Kobana ainda não publica os escopos do Financeiro Inteligente, e um cliente que os pedisse seria recusado na autorização. -
Metadata do authorization server (RFC 8414), em
https://account.kobana.com.br/.well-known/oauth-authorization-server. -
Registro dinâmico do cliente (RFC 7591). O cliente se registra sozinho; a tela de consentimento avisa que ele não é um app verificado.
-
Autorização com PKCE e
resource(RFC 8707). Você faz login na Kobana, escolhe a organização (se tiver mais de uma) e autoriza. -
Token. O cliente troca o código por um access token de vida curta e passa a mandá-lo em toda requisição, renovando quando expira.
O token carrega quem você é (sub) e a organização que você autorizou (org); o workspace vem de cada chamada, como acima. Nenhuma tool aceita organização como argumento.
Dois eixos de autorização
O que um chamador vê é mais estreito que o catálogo, por dois filtros independentes. Nenhum dos dois pode alargar a superfície.
Eixo 1 — o escopo do token
O teto do cliente, no claim scope. Leitura é tool de leitura, resource, prompt e completion; escrita é todo o resto, destrutivas incluídas. Mover dinheiro é um degrau acima da escrita.
Token com recursos — o caso do token pessoal. Os recursos definem até onde o token chega, e read, write e all valem só dentro deles:
| Escopo do token | Resultado |
|---|---|
finance/payables finance/people read write | Lê e escreve contas a pagar e pessoas — e nada mais |
finance/payables read | Só lê contas a pagar |
finance/all read | Lê tudo, não escreve nada |
finance/payables finance/payable_dispatches read write | Também envia contas a pagar ao banco |
Enviar ao banco e cobrar exigem o recurso próprio — finance/payable_dispatches e finance/receivable_charges — com write ou all; finance/payables write não basta. delete, import e export sozinhos não contam como escrita.
Token sem recursos — o caso do fluxo OAuth. Vale só o nível de acesso: leitura com read, write ou all; escrita com write ou all; mover dinheiro só com all.
:::info Clientes conectados pelo fluxo OAuth ficam só com leitura
O authorization server concede apenas read a clientes registrados dinamicamente — Claude, ChatGPT, o MCP Inspector, IDEs. Para eles, o MCP lista só as tools de leitura, e uma tool que escreve volta insufficient_scope. Para um agente escrever hoje, use um token pessoal com acesso de escrita nos recursos de que ele precisa.
:::
A mesma regra vale na API REST — veja Escopos.
Eixo 2 — as permissões da pessoa do token
O sub do token é a pessoa que consentiu. No MCP, as tools são estreitadas para o que essa pessoa pode fazer no dashboard da organização, resolvido a cada requisição — as mesmas funções e permissões da tela Membros.
| Situação | Resultado |
|---|---|
| A pessoa nunca entrou no Financeiro Inteligente, ou não é membro da organização | Nega todas as tools. Quem não é membro não alcança nada pelo MCP. |
| Membro ativo, com acesso ao workspace | As permissões dela, tool a tool. O dono (*) libera tudo; payables.* libera a família. |
| Membro ativo sem acesso ao workspace | Nega todas as tools daquele workspace. |
| Membro suspenso, com convite pendente, removido, ou sem permissão nenhuma | Nega todas as tools. Um token sobrevivendo ao acesso da pessoa é exatamente o caso a fechar. |
| A consulta de permissões falha | Nega todas as tools. Falha fechada. |
As permissões são lidas a cada chamada: tirar uma permissão no dashboard vale já na tool seguinte, sem esperar o token expirar.
:::tip Postura recomendada para agentes Conecte o assistente com uma conta que só tem as permissões que o agente precisa, e, num token pessoal, marque só os recursos e acessos que ele vai usar. Os dois eixos se somam: o token de um analista somente-leitura expõe só as tools de leitura, faça o que fizer o modelo do outro lado. :::
Como os dois compõem
O conjunto final é a interseção: tools ∩ escopos do token ∩ permissões da pessoa. Uma tool que o chamador não pode rodar não é listada.
Quando tools/call recusa, o código diz quem resolve:
| Código | Quem resolve |
|---|---|
insufficient_scope | Usar um token que alcance o recurso com o acesso pedido — por exemplo, um token pessoal com escrita nesse recurso. |
insufficient_permission | Um admin da organização, concedendo a permissão (o erro nomeia qual). |
workspace_required | O agente passa workspace_id — um dos id de finance_workspaces_list —, ou a conexão define um workspace padrão. |
workspace_access_denied | Um admin concede o workspace à pessoa, ou o agente passa outro workspace_id. |
membership_inactive | Incluir a pessoa na organização ou reativá-la — nenhuma permissão conserta um vínculo que não existe ou está inativo. |
:::caution O que o eixo 2 não cobre
O estreitamento por permissão vale só para o MCP. Um token da API, chamado direto em api.finance.*, continua limitado apenas pelos escopos.
:::
Segurança › Canais
As regras da aba Segurança › Canais continuam valendo por cima dos dois eixos — elas são aplicadas pelo próprio endpoint. Um agente de IA age pelo canal MCP - Inteligência Artificial, onde, por padrão, enviar ao banco começa fechado: finance_payables_send_to_bank só funciona depois que a solicitação for aprovada.
Revogação do token pessoal
Revogar um token pessoal na sua Conta Kobana não corta o acesso na hora: o Financeiro Inteligente verifica o token sozinho, sem consultar a Kobana a cada chamada, e ele continua aceito até a validade dele. Por isso:
- escolha a validade mais curta que o uso permite;
- marque só os recursos e acessos de que o agente precisa;
- para cortar um agente imediatamente, suspenda ou remova a pessoa na organização, ou tire o acesso dela ao workspace — as permissões são lidas a cada chamada e valem na hora.
Modos de falha
| HTTP | code | Causa |
|---|---|---|
| 400 | -32022 (JSON-RPC) | Versão do protocolo não suportada, no cabeçalho MCP-Protocol-Version ou no _meta; data.supported lista as que são. Veja Transporte. |
| 401 | UNAUTHORIZED | Token ausente, malformado, inválido, revogado, expirado, emitido para outro recurso (a API, por exemplo) ou enviado na URL (?access_token=). |
| 403 | UNKNOWN_ORGANIZATION / UNKNOWN_WORKSPACE | O org do token não é um cliente, ou o workspace de X-Workspace-Id / ?workspace_id= não é da organização. |
| 403 | FORBIDDEN | Origin fora da allowlist (origin_not_allowed). |
| 404 | NOT_FOUND | A requisição chegou por um host que não serve MCP, ou pediu um caminho que não existe no servidor. |
| 429 | RATE_LIMITED | Limite de requisições atingido — veja Limite de requisições. |
| 503 | SERVICE_UNAVAILABLE | A Conta Kobana não respondeu para validar o token. Não é problema do token: tente de novo depois do Retry-After. |
Todo 401 carrega o desafio WWW-Authenticate acima, que manda o cliente de volta ao fluxo OAuth.
Negativas de escopo e de permissão não são erros HTTP: elas voltam como resultado de tool marcado isError, para que o modelo leia e reaja — veja Erros.
Host e borda
O endpoint só é alcançável por mcp.finance.* — nunca pelo host do app nem pelo da API, que apontam para a mesma origin. Qualquer outro caminho responde 404, sempre em JSON e para qualquer método — { "error": { "code": "NOT_FOUND", "message": "Not found." } }, nunca uma página HTML. O identificador de recurso OAuth é derivado da configuração do servidor, nunca do Host da requisição, para que um Host forjado não consiga apontar um cliente para outro identificador.