Autenticación
El servidor MCP es un Resource Server OAuth 2.1. Acepta un Bearer token en el header Authorization y nada más — sin cookies, sin certificado de cliente y nunca un token en la URL: ?access_token= se ignora, y la solicitud se trata como no autenticada (401 con el desafío). Una URL termina en logs de acceso y en headers Referer; un bearer token no debe.
:::caution Aquí no hay mTLS
La API REST exige certificado de cliente (autenticación de /api/v1); el host MCP deliberadamente no. Ningún cliente MCP presenta certificado de cliente, así que la capa de transporte se sustituye por OAuth, no se elimina: la verificación de audience, la de scope y la de permiso por persona siguen ejecutándose.
:::
Dos formas de conectarse
El token es un access token OAuth 2.1 emitido por el authorization server de Kobana, un JWT RS256 emitido para este recurso: su aud es la URL del servidor MCP (https://mcp.inbox.kobana.com.br). Llega al servidor de una de dos formas, y se verifica igual en ambas.
| Flujo OAuth | Token personal | |
|---|---|---|
| Cómo lo obtienes | Pegas la URL en el cliente; este abre el login de Kobana y autorizas | Lo creas en Cuenta Kobana → Tokens y Acceso → Nuevo Token Personal: app Inbox Autónomo, uso MCP, recursos y accesos, validez |
| Cómo lo usa el cliente | Por su cuenta, después de la autorización | Lo pegas en el cliente como Authorization: Bearer <token> |
| Validez | Corta, renovada por el cliente | De 7 días a 1 año, a tu elección |
| Alcance | Los recursos que consentiste, solo lectura | Los recursos y accesos que marcaste |
| Indicado para | Claude, ChatGPT, IDEs y cualquier cliente con OAuth | Clientes sin OAuth, scripts y agentes que necesitan escribir |
:::info Cada superficie tiene su propia audience
Un token emitido para el servidor MCP no es válido en la API REST (api.inbox.*), y un token de la API no es válido aquí — un token entregado a un asistente no puede reutilizarse contra la API. Por la misma razón, el token personal tiene que crearse con el uso MCP. Un token que nombra más de una audience se rechaza.
:::
El flujo OAuth
No ejecutas ninguno de estos pasos: el cliente MCP lo hace todo a partir de la URL. Están aquí para cuando algo falla a mitad de camino.
-
Desafío. Una solicitud sin token recibe
401con el desafío que todo resource server OAuth 2.1 debe 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" -
Metadatos del recurso. El cliente lee el documento al que apunta. Es público y solo lleva punteros; el authorization server se nombra por su identificador de emisor (issuer):
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"} -
Metadatos del authorization server (RFC 8414), en
https://account.kobana.com.br/.well-known/oauth-authorization-server. -
Registro dinámico de cliente (RFC 7591). El cliente se registra solo; la pantalla de consentimiento indica que no es una app verificada.
-
Autorización con PKCE y
resource(RFC 8707). Inicias sesión en Kobana, eliges la organización (si tienes más de una) y autorizas. -
Token. El cliente canjea el código por un access token de corta duración y lo envía en cada solicitud, renovándolo cuando expira.
El token lleva quién eres (sub), la organización que autorizaste (org) y los scopes que consentiste (scope). Es org lo que delimita los datos — ninguna tool recibe la organización como argumento.
Dos niveles de autorización
La autorización es la conjunción de dos verificaciones independientes — una sobre el cliente, otra sobre la persona.
| Capa | Responde | Decidida por | Efecto en MCP |
|---|---|---|---|
Scope (inbox/X + el verbo global write, o el nivel de acceso) | qué puede pedir este cliente en nombre de la persona | la persona, en la pantalla de consentimiento o al crear un token personal | filtra tools/list, bloquea tools/call con insufficient_scope |
Permiso (recurso.acción) | qué puede hacer esta persona en esta organización | el administrador de la organización, en el dashboard | filtra tools/list, bloquea tools/call con insufficient_permission |
Los dos códigos de error son distintos porque quien resuelve cada uno es una persona diferente: un scope que falta lo arregla quien sea dueño del cliente conectado; un permiso que falta, el administrador de la organización.
Todo token MCP es de una persona. El authorization server solo emite un token ligado al recurso para una persona, así que el servidor MCP siempre aplica los permisos de esa persona — sea cual sea el src que lleve el token. Una persona que no es miembro de la organización no alcanza nada (403, no_membership). Los permisos se leen en cada llamada, así que revocar un rol en el dashboard surte efecto en la siguiente llamada, sin esperar a que el token expire.
Scopes
Los scopes tienen dos ejes ortogonales: el recurso, siempre prefijado por la app, y el verbo, un scope global sin prefijo. Recurso sin verbo significa lectura. Escribir exige ambos.
| Scope | Concede |
|---|---|
inbox/workspaces | Leer las tools de workspace |
inbox/inboxes | Leer las tools de inbox y los remitentes permitidos |
inbox/emails | Leer las tools de correo, incluida la descarga del .eml |
inbox/agents | Leer las tools de agente, versiones de prompt y el catálogo de modelos |
inbox/agent_runs | Leer las tools de ejecución de agente |
inbox/usage | Leer las tools de uso y coste |
inbox/webhooks | Leer las tools de webhook y sus entregas |
inbox/system_events | Leer las tools de evento de sistema |
inbox/secrets | Leer las tools de secret — clave, notas y metadatos. El valor nunca se devuelve, por ninguna tool ni endpoint |
inbox/workflow_runs | Leer las tools de ejecución de workflow, incluyendo cada paso de la ejecución |
inbox/all | Catch-all de recurso — lee todos los recursos anteriores, no concede verbo |
write | Verbo global: todas las tools de escritura sobre los recursos que lleva el token |
Un token de solo lectura es el valor recomendado por defecto para un agente: solo con inbox/all, el cliente conectado físicamente no puede escribir, aunque la persona detrás sí pudiera. Un cliente registrado por el flujo OAuth recibe scopes de recurso y ningún verbo — solo lectura por construcción.
El nivel de acceso. Todo token que emite el authorization server también lleva el nivel de acceso que la persona concedió — read, write, delete, import, export, all. Se respeta junto a la gramática anterior:
- Con scopes
inbox/…en el token, los recursos definen el alcance, yread,writeyallactúan solo dentro de ellos:inbox/emails read writelee y escribe correos y nada más;inbox/all readlee todo y no escribe nada. - Sin scopes
inbox/…, decide solo el nivel de acceso: lee conread,writeoall; escribe conwriteoall.
delete, import y export por sí solos no cuentan como escritura.
Cada página de tool en Recursos indica el scope y el permiso que exige.
Eligiendo el workspace
Un token ligado a una persona no fija un workspace — una organización puede tener varios. Elige uno por conexión con:
X-Workspace-Id: <id-o-external-id-del-workspace>
Cuando la organización tiene exactamente un workspace, el header es opcional. Con más de uno y sin header, el servidor responde 400 workspace_required. Un header que apunta a un workspace fuera de la organización del token es 403 forbidden con message: unknown_workspace — indistinguible de uno inexistente. Ninguna tool acepta el workspace como argumento.
Revocación del token personal
Revocar un token personal en tu cuenta Kobana no corta el acceso de inmediato: Inbox Autónomo verifica el token por sí mismo, sin consultar a Kobana en cada llamada, y el token sigue siendo válido hasta que expire. Por eso:
- elige la validez más corta que el uso permita;
- marca solo los recursos y accesos que el agente necesita;
- para cortar un agente de inmediato, suspende o elimina la membresía de la persona en la organización — los permisos se leen en cada llamada y surten efecto al instante.
Modos de fallo
| HTTP | code | Causa |
|---|---|---|
| 400 | workspace_required | La organización tiene varios workspaces y no se eligió ninguno |
| 400 | -32022 (JSON-RPC) | Versión de protocolo no soportada, en MCP-Protocol-Version o en _meta; data.supported lista las soportadas. Ver Transporte |
| 401 | invalid_token | Token ausente, malformado, con firma inválida o emitido para otro recurso (la API REST, por ejemplo) |
| 401 | invalid_issuer | iss no es el emisor de Kobana |
| 401 | token_expired | exp en el pasado |
| 401 | token_revoked | jti revocado |
| 403 | forbidden | La solicitud no llegó por el edge de MCP, o el token no resuelve a ningún tenant — message dice cuál: unknown_organization (el claim org apunta a una cuenta que este servidor no conoce), no_membership (la persona no tiene membresía viva en esa organización) o unknown_workspace (X-Workspace-Id fuera de la organización) |
| 403 | origin_not_allowed | Header Origin fuera de la lista permitida |
| 404 | not_found | La solicitud llegó por un host que no sirve MCP, o pidió una ruta que no es un endpoint MCP — siempre este cuerpo JSON, en cualquier método |
| 429 | rate_limited | Límite de solicitudes excedido — ver Límite de solicitudes. Los tokens rechazados también se limitan por IP del cliente |
| 503 | as_unavailable | No se pudieron descargar las claves de firma del authorization server. No es un problema de tu token: reintenta después de Retry-After. Nunca es un 401, que haría pasar al cliente por todo el flujo OAuth de nuevo para nada |
Todo 401 lleva el desafío WWW-Authenticate anterior, que devuelve al cliente al flujo OAuth. Las negativas de scope y de permiso no son errores HTTP: vuelven como resultado de tool marcado con isError, para que el modelo pueda leerlas y reaccionar — ver Errores.