Autenticación
El servidor MCP acepta un Bearer token en la cabecera Authorization, y nada más — sin cookie, sin certificado de cliente.
:::warning Nunca en la URL
Un token en la query string (?access_token=…, o parámetros como token y api_key) no autentica, aunque venga junto a una cabecera válida: la petición responde 401 con error="invalid_request" en WWW-Authenticate. Un token en la URL se filtra en logs de proxy y CDN, en el Referer y en el historial — la especificación de autorización de MCP y la RFC 6750 lo prohíben.
:::
Ese token es un access token OAuth 2.1 emitido por el authorization server de Kobana (https://account.kobana.com.br): un JWT firmado en RS256 y emitido para este recurso, cuyo aud es https://mcp.dashboards.kobana.com.br. Llega por uno de dos caminos — el flujo OAuth, que hace el propio cliente, o un token personal que creas en tu cuenta Kobana — y se verifica igual en los dos casos.
Authorization: Bearer eyJhbGciOiJSUzI1NiIs…
:::info Cada superficie tiene su propia audience
Un token emitido para el MCP no vale en la API REST (api.dashboards.*), y un token de la API no vale aquí. Es lo que impide que el token entregado a un asistente se reutilice contra la API — y al revés.
:::
Dos formas de conectarse
| Flujo OAuth | Token personal | |
|---|---|---|
| Cómo lo obtienes | Pegas la URL en el cliente; abre el inicio de sesión de Kobana y autorizas | Lo creas en Cuenta Kobana → Tokens y Acceso → Nuevo Token Personal: app Dashboard Mágico, uso MCP, recursos y accesos, validez |
| Cómo lo usa el cliente | Solo, después de la autorización | Lo pegas en el cliente como Authorization: Bearer <token> |
| Validez | 30 minutos, renovado por el cliente | De 7 días a 1 año, a tu elección |
| Alcance | Solo el nivel de acceso — hoy, read | Los recursos y accesos que marcaste |
| Bueno para | Claude, ChatGPT, IDEs y cualquier cliente con OAuth | Clientes sin soporte de OAuth, scripts y automatizaciones |
El token personal tiene que crearse con el uso MCP. Un token creado para la API REST tiene la audience de la API y aquí se rechaza con 401 — y lo contrario también vale.
El flujo OAuth
No ejecutas ninguno de estos pasos: el cliente MCP (Claude, ChatGPT, un IDE) lo hace todo solo a partir de la URL. Están aquí para cuando algo falle a mitad de camino.
-
Desafío. Una petición sin token recibe
401con el desafío que todo resource server OAuth 2.1 debe enviar (RFC 9728):WWW-Authenticate: Bearer realm="kobana-dashboards-mcp",error="invalid_token",resource_metadata="https://mcp.dashboards.kobana.com.br/.well-known/oauth-protected-resource" -
Metadata del recurso. El cliente lee el documento señalado. Es público y no lleva ningún secreto — solo punteros:
curl https://mcp.dashboards.kobana.com.br/.well-known/oauth-protected-resource{"resource": "https://mcp.dashboards.kobana.com.br","authorization_servers": ["https://account.kobana.com.br"],"bearer_methods_supported": ["header"],"resource_documentation": "https://docs.dashboards.kobana.com.br"} -
Metadata del authorization server (RFC 8414), en
https://account.kobana.com.br/.well-known/oauth-authorization-server. -
Registro dinámico del cliente (RFC 7591). El cliente se registra solo; la pantalla de consentimiento avisa 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 cambia el código por un access token de vida corta y lo envía en cada petición, renovándolo cuando expira.
El token lleva quién eres (sub) y la organización que autorizaste (org). Es el org lo que delimita los datos — ninguna tool acepta organización como argumento. Un token cuya organización no existe en Dashboard Mágico recibe 403 unknown_organization.
Autorización: los permisos de quien autorizó
Lo que un llamador ve es más estrecho que el catálogo: las tools se filtran por los permisos de dashboard de la persona que autorizó el cliente, en esa organización, resueltos en cada petición. El techo es siempre lo que esa persona puede hacer en la interfaz.
| Situación | Resultado |
|---|---|
| La persona no es miembro de la organización | Niega todas las tools (key_owner_not_member). Autoriza de nuevo con una cuenta que pertenezca a la organización. |
| Vínculo activo | Los permisos y roles de la persona, aplicados tool a tool. owner y el comodín * lo liberan todo; portal-users.* libera la familia. |
| Vínculo suspendido, eliminado, o sin ningún rol | Niega todas las tools (membership_inactive). |
| La consulta de permisos falla | Niega todas las tools. Falla cerrada. |
Los permisos se leen en cada llamada, así que revocar un rol en el dashboard vale ya en la tool siguiente, sin esperar a que el token expire.
Una tool que el llamador no puede ejecutar no aparece en tools/list. Cuando tools/call rechaza, el código dice quién lo resuelve:
| Código | Quién lo resuelve |
|---|---|
insufficient_scope | Usar un token que alcance el recurso con el acceso pedido — por ejemplo, un token personal con escritura en ese recurso. |
insufficient_permission | Un admin de la organización, concediendo el permiso (el error dice cuál). |
membership_inactive | Reactivar a la persona — ningún permiso arregla un vínculo muerto. |
key_owner_not_member | Autorizar de nuevo con una cuenta que sea miembro de la organización. |
:::tip Postura recomendada para agentes Autoriza el cliente con una cuenta que tenga solo los permisos que el agente necesita. Un cliente autorizado por un analista de solo lectura expone solo las tools de lectura, haga lo que haga el modelo del otro lado. :::
Alcance del token
Además de los permisos, el MCP aplica el alcance que trae el token, en el claim scope. Las dos verificaciones se suman: una tool solo aparece si las dos lo permiten. Lectura es tool de lectura, resource, prompt de lectura y completion; escritura es todo lo demás, destructivas incluidas.
Token con recursos — el caso del token personal. Los recursos definen hasta dónde llega el token, y read/write valen solo dentro de ellos:
| Alcance del token | Resultado |
|---|---|
dashboards/users dashboards/members read write | Lee y escribe usuarios del portal y miembros del equipo (con sus roles) — y nada más |
dashboards/users read | Solo lee usuarios del portal |
dashboards/all read | Lee todo, no escribe nada |
Un recurso fuera de los diez grupos solo se alcanza con dashboards/all. delete, import y export solos no cuentan como escritura.
Token sin recursos — el caso del flujo OAuth. Vale solo el nivel de acceso: lectura con read, write o all; escritura con write o all.
:::info Los clientes conectados por el flujo OAuth quedan solo con lectura
El authorization server concede solo read a los clientes registrados dinámicamente — Claude, ChatGPT, el MCP Inspector, IDEs. Para ellos, el MCP lista solo las tools de lectura, y una tool que escribe devuelve insufficient_scope. Para que un agente escriba hoy, usa un token personal con acceso de escritura a los recursos que necesita.
:::
La misma regla vale en la API REST, con el recurso tomado de la ruta: un token sin acceso de escritura al recurso recibe 403 insufficient_scope en cualquier método que no sea GET.
Revocación del token personal
Revocar un token personal en tu cuenta Kobana no corta el acceso en el momento: Dashboard Mágico verifica el token por su cuenta, sin consultar a Kobana en cada llamada, y sigue aceptándolo hasta su vencimiento. 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 quita el vínculo de la persona con la organización — los permisos se leen en cada llamada y valen al instante.
Modos de fallo
| HTTP | code | Causa |
|---|---|---|
| 400 | -32022 (JSON-RPC) | Versión del protocolo no soportada, en la cabecera MCP-Protocol-Version o en _meta; data.supported lista las que sí. Ve Transporte. |
| 401 | UNAUTHORIZED | Token ausente, malformado, inválido, expirado o emitido para otro recurso (por ejemplo, para la API REST). |
| 403 | unknown_organization | El token es válido, pero la organización que nombra no existe en Dashboard Mágico. |
| 403 | FORBIDDEN | Origin fuera de la allowlist (origin_not_allowed). |
| 404 | NOT_FOUND | La petición llegó por un host que no sirve MCP. |
| 429 | TOO_MANY_REQUESTS | Límite de peticiones alcanzado — ver Límite de peticiones. |
| 503 | SERVICE_UNAVAILABLE | No pudimos hablar con el authorization server para verificar el token. Es de nuestro lado: reintenta después del Retry-After. |
Todo 401 lleva el desafío WWW-Authenticate de arriba, que devuelve al cliente al flujo OAuth.
Las negativas de permiso no son errores HTTP: vuelven como resultado de tool marcado isError, para que el modelo las lea y reaccione — ver Errores.
Host y edge
/mcp tiene que ser alcanzable solo por mcp.dashboards.* — nunca por el host de la app, nunca por el host de la API, cuyas distributions apuntan al mismo origin. Cualquier otro camino responde 404: el endpoint no anuncia que existe en otro lugar.
El identificador de recurso OAuth — y, por tanto, la audience que el token necesita tener — se deriva de la configuración del servidor, nunca del Host de la petición, para que un Host falsificado no pueda apuntar un cliente a otro identificador.