Autenticação
O servidor MCP é um Resource Server OAuth 2.1. Ele aceita um Bearer token no header Authorization e nada além disso — sem cookies, sem certificado de cliente e nunca token na URL: ?access_token= é ignorado, e a requisição é tratada como não autenticada (401 com o desafio). Uma URL vai parar em logs de acesso e em headers Referer; um bearer token não pode.
:::caution Sem mTLS aqui
A API REST exige certificado de cliente (autenticação de /api/v1); o host MCP deliberadamente não. Nenhum cliente MCP apresenta certificado de cliente, então a camada de transporte é substituída pelo OAuth, não removida: a checagem de audience, a de escopo e a de permissão por pessoa continuam todas valendo.
:::
Duas formas de conectar
O token é um access token OAuth 2.1 emitido pelo authorization server da Kobana, um JWT RS256 emitido para este recurso: seu aud é a URL do servidor MCP (https://mcp.inbox.kobana.com.br). Ele chega ao servidor de uma de duas formas, e é verificado do mesmo jeito nas duas.
| Fluxo OAuth | Token pessoal | |
|---|---|---|
| Como obter | Cole a URL no cliente; ele abre o login da Kobana e você autoriza | Crie em Conta Kobana → Tokens e Acesso → Novo Token Pessoal: app Inbox Autônomo, uso MCP, recursos e acessos, validade |
| Como o cliente o usa | Sozinho, depois da autorização | Você o cola no cliente como Authorization: Bearer <token> |
| Validade | Curta, renovada pelo cliente | De 7 dias a 1 ano, à sua escolha |
| Escopo | Os recursos que você consentiu, somente leitura | Os recursos e acessos que você marcou |
| Indicado para | Claude, ChatGPT, IDEs e qualquer cliente com OAuth | Clientes sem OAuth, scripts e agentes que precisam escrever |
:::info Cada superfície tem sua própria audience
Um token emitido para o servidor MCP não vale na API REST (api.inbox.*), e um token da API não vale aqui — um token entregue a um assistente não pode ser reapresentado contra a API. É pelo mesmo motivo que o token pessoal precisa ser criado com o uso MCP. Um token que nomeia mais de uma audience é recusado.
:::
O fluxo OAuth
Você não executa nenhum destes passos: o cliente MCP faz tudo a partir da URL. Eles estão aqui para quando algo falhar no meio do caminho.
-
Desafio. Uma requisição sem token recebe
401com o desafio que todo resource server OAuth 2.1 precisa enviar (RFC 9728):WWW-Authenticate: Bearer realm="kobana-inbox-mcp", error="invalid_token", resource_metadata="https://mcp.inbox.kobana.com.br/.well-known/oauth-protected-resource" -
Metadados do recurso. O cliente lê o documento para o qual o desafio aponta. Ele é público e carrega apenas ponteiros; o authorization server é nomeado pelo seu identificador de emissor:
curl https://mcp.inbox.kobana.com.br/.well-known/oauth-protected-resource{"resource": "https://mcp.inbox.kobana.com.br","authorization_servers": ["https://account.kobana.com.br"],"bearer_methods_supported": ["header"],"scopes_supported": ["inbox/agent_runs", "inbox/agents", "inbox/emails", "inbox/inboxes","inbox/secrets", "inbox/system_events", "inbox/usage", "inbox/webhooks","inbox/workflow_runs", "inbox/workspaces", "read"],"resource_documentation": "https://docs.inbox.kobana.com.br"} -
Metadados do authorization server (RFC 8414), em
https://account.kobana.com.br/.well-known/oauth-authorization-server. -
Registro dinâmico de 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ê entra 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 o envia em toda requisição, renovando-o quando expira.
O token carrega quem você é (sub), a organização que você autorizou (org) e os escopos que você consentiu (scope). É o org que delimita os dados — nenhuma tool recebe organização como argumento.
Dois níveis de autorização
A autorização é a conjunção de duas checagens independentes — uma sobre o cliente, outra sobre a pessoa.
| Camada | Responde | Decidida por | Efeito no MCP |
|---|---|---|---|
Escopo (inbox/X + o verbo global write, ou o nível de acesso) | o que este cliente pode pedir em nome da pessoa | a pessoa, na tela de consentimento ou ao criar um token pessoal | filtra tools/list, barra tools/call com insufficient_scope |
Permissão (recurso.ação) | o que esta pessoa pode fazer nesta organização | o administrador da organização, no dashboard | filtra tools/list, barra tools/call com insufficient_permission |
Os dois códigos de erro são distintos porque quem resolve cada um é uma pessoa diferente: escopo faltando é com o dono do cliente conectado; permissão faltando é com o administrador da organização.
Todo token MCP é de uma pessoa. O authorization server só emite um token vinculado ao recurso para uma pessoa, então o servidor MCP sempre aplica as permissões dessa pessoa — qualquer que seja o src do token. Uma pessoa que não é membro da organização não alcança nada (403, no_membership). As permissões são lidas a cada chamada, então revogar uma função no dashboard vale na chamada de tool seguinte, sem esperar o token expirar.
Escopos
Os escopos têm dois eixos ortogonais: o recurso, sempre prefixado pelo app, e o verbo, um escopo global sem prefixo. Recurso sem verbo significa leitura. Escrever exige os dois.
| Escopo | Concede |
|---|---|
inbox/workspaces | Ler as tools de workspace |
inbox/inboxes | Ler as tools de inbox e os remetentes permitidos |
inbox/emails | Ler as tools de e-mail, incluindo o download do .eml |
inbox/agents | Ler as tools de agente, versões de prompt e o catálogo de modelos |
inbox/agent_runs | Ler as tools de execução de agente |
inbox/usage | Ler as tools de uso e custo |
inbox/webhooks | Ler as tools de webhook e suas entregas |
inbox/system_events | Ler as tools de evento de sistema |
inbox/secrets | Ler as tools de secret — chave, notas e metadados. O valor nunca é devolvido, por tool ou endpoint nenhum |
inbox/workflow_runs | Ler as tools de execução de workflow, incluindo cada passo da execução |
inbox/all | Catch-all de recurso — lê todos os recursos acima, não concede verbo |
write | Verbo global: todas as tools de escrita nos recursos que o token carrega |
Um token somente-leitura é o padrão recomendado para um agente: só com inbox/all, o cliente conectado fisicamente não consegue escrever, mesmo que a pessoa por trás dele pudesse. Um cliente registrado pelo fluxo OAuth recebe escopos de recurso e nenhum verbo — somente leitura por construção.
O nível de acesso. Todo token que o authorization server emite também carrega o nível de acesso que a pessoa concedeu — read, write, delete, import, export, all. Ele é respeitado ao lado da gramática acima:
- Com escopos
inbox/…no token, os recursos definem o alcance, eread,writeeallagem só dentro deles:inbox/emails read writelê e escreve e-mails e nada mais;inbox/all readlê tudo e não escreve nada. - Sem escopos
inbox/…, só o nível de acesso decide: lê comread,writeouall; escreve comwriteouall.
delete, import e export, sozinhos, não contam como escrita.
Cada página de tool em Recursos informa o escopo e a permissão exigidos.
Escolhendo o workspace
Um token ligado a uma pessoa não fixa um workspace — uma organização pode ter vários. Escolha um por conexão com:
X-Workspace-Id: <id-ou-external-id-do-workspace>
Quando a organização tem exatamente um workspace, o header é opcional. Com mais de um e sem o header, o servidor responde 400 workspace_required. Header apontando um workspace fora da organização do token é 403 forbidden com message: unknown_workspace — indistinguível de um inexistente. Nenhuma tool aceita workspace como argumento.
Revogação do token pessoal
Revogar um token pessoal na sua conta Kobana não corta o acesso na hora: o Inbox Autônomo verifica o token por conta própria, sem consultar a Kobana a cada chamada, e ele continua válido até expirar. Por isso:
- escolha a menor validade que o uso permite;
- marque só os recursos e acessos de que o agente precisa;
- para cortar um agente imediatamente, suspenda ou remova a membership da pessoa na organização — as permissões são lidas a cada chamada e valem na hora.
Modos de falha
| HTTP | code | Causa |
|---|---|---|
| 400 | workspace_required | A organização tem vários workspaces e nenhum foi escolhido |
| 400 | -32022 (JSON-RPC) | Versão de protocolo não suportada, em MCP-Protocol-Version ou no _meta; data.supported lista as suportadas. Veja Transporte |
| 401 | invalid_token | Token ausente, malformado, com assinatura inválida ou emitido para outro recurso (a API REST, por exemplo) |
| 401 | invalid_issuer | iss não é o emissor Kobana |
| 401 | token_expired | exp no passado |
| 401 | token_revoked | jti revogado |
| 403 | forbidden | A requisição não veio pela borda do MCP, ou o token não resolve para nenhum tenant — message diz qual: unknown_organization (o claim org aponta uma account que este servidor não conhece), no_membership (a pessoa não tem membership viva nessa organização) ou unknown_workspace (X-Workspace-Id fora da organização) |
| 403 | origin_not_allowed | Header Origin fora da allowlist |
| 404 | not_found | A requisição chegou por um host que não serve MCP, ou pediu um caminho que não é endpoint MCP — sempre este corpo JSON, em qualquer método |
| 429 | rate_limited | Limite de requisições excedido — veja Limite de requisições. Tokens rejeitados também são limitados por IP do cliente |
| 503 | as_unavailable | As chaves de assinatura não puderam ser buscadas no authorization server. Não é problema do seu token: tente de novo depois do Retry-After. Nunca é um 401, que mandaria o cliente refazer todo o fluxo OAuth à toa |
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: voltam como resultado de tool marcado com isError, para que o modelo possa lê-las e reagir — veja Erros.