Saltar al contenido principal

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, bearer, api_key y key) no autentica, aunque venga junto a una cabecera válida: la solicitud 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 del MCP y la RFC 6750 lo prohíben. :::

Ese token es un access token emitido por el Authorization Server de Kobana (https://account.kobana.com.br), un JWT firmado con RS256 y emitido para este recurso: su aud es https://mcp.kadu.ia.br (en staging, https://mcp.staging.kadu.ia.br), y solo ese — un token con más de una audience se rechaza. El token llega por uno de dos caminos — el flujo OAuth, que hace el propio cliente, o un token personal que creas en la Cuenta Kobana — y se verifica igual en los dos casos, con la misma verificación local de firma de la API v1.

Authorization: Bearer eyJhbGciOiJSUzI1NiIs…

:::info Cada superficie tiene su audience Un token emitido para el MCP no vale en la API (api.kadu.ia.br), y un token de la API no vale aquí. Es lo que impide que el token entregado a un asistente se reutilice como credencial REST — y al revés. :::

Dos formas de conectar​

Flujo OAuthToken personal
Cómo lo obtienesPegas la URL en el cliente; abre el inicio de sesión de la Cuenta Kobana y autorizasLo creas en el asistente de tokens de la Cuenta Kobana, con el uso MCP, los recursos y accesos y la validez
Cómo lo usa el clientePor su cuenta, tras la autorización, renovándolo cuando expiraLo pegas en el cliente como Authorization: Bearer <token>
AlcanceLos recursos y niveles de acceso que dejaste marcados en la pantalla de consentimientoLos recursos y accesos que marcaste
Bueno paraClaude, ChatGPT, IDEs y cualquier cliente con OAuthClientes sin soporte de OAuth, scripts y automatizaciones

El token personal tiene que crearse con el uso MCP. Un token creado para la API lleva la audience de la API y aquí se rechaza con 401 — y al revés también.

El flujo OAuth​

No ejecutas ninguno de estos pasos: el cliente MCP lo hace todo por su cuenta a partir de la URL. Están aquí para cuando algo falle en el camino.

  1. Desafío. Una solicitud sin token recibe 401 con el desafío que todo resource server OAuth 2.1 debe enviar (RFC 9728):

    WWW-Authenticate: Bearer realm="kadu-mcp",
    error="invalid_token",
    resource_metadata="https://mcp.kadu.ia.br/.well-known/oauth-protected-resource"
  2. Metadata del recurso. El cliente lee el documento indicado. Es público y no lleva ningún secreto — solo punteros:

    curl https://mcp.kadu.ia.br/.well-known/oauth-protected-resource
    {
    "resource": "https://mcp.kadu.ia.br",
    "authorization_servers": ["https://account.kobana.com.br"],
    "bearer_methods_supported": ["header"],
    "scopes_supported": [
    "kadu/activities",
    "kadu/environments",
    "kadu/executions",
    "kadu/files",
    "kadu/memberships",
    "kadu/memories",
    "kadu/organizations",
    "kadu/repository",
    "kadu/roles",
    "kadu/schedules",
    "kadu/secrets",
    "kadu/system_events",
    "kadu/tasks",
    "kadu/todos",
    "kadu/usage",
    "kadu/users",
    "kadu/webhook_deliveries",
    "kadu/webhooks",
    "kadu/workspaces",
    "read",
    "write",
    "delete",
    "import",
    "export",
    "all"
    ],
    "resource_documentation": "https://api.kadu.ia.br/v1/docs"
    }

    kadu/all queda fuera a propósito: el comodín no se entrega a un cliente que se registró solo.

  3. Metadata del Authorization Server (RFC 8414), en https://account.kobana.com.br/.well-known/oauth-authorization-server.

  4. Registro dinámico del cliente (RFC 7591). El cliente se registra solo.

  5. Autorización con PKCE y resource (RFC 8707). Inicias sesión en la Cuenta Kobana, eliges la organización (si tienes más de una), revisas lo que pide el cliente y autorizas.

  6. Token. El cliente cambia el código por un access token de vida corta y lo envía en cada solicitud, renovándolo cuando expira.

El token lleva quién eres (sub) y la organización que autorizaste (org). Es el org el que delimita los datos — ninguna tool acepta organización como argumento. Un token cuya organización no existe en Kadu recibe 403 unknown_organization.

Autorización: el rol de quien autorizó​

Lo que ve un llamador es más estrecho que el catálogo: las tools se filtran por el rol de la persona del token en la organización — los mismos permisos agent.<recurso>.<acción> de la consola y de la API (mira Permisos). La tool exige exactamente el permiso de la ruta que refleja. El techo es siempre lo que esa persona puede hacer en la consola.

SituaciónResultado
La persona del token no es miembro de la organizaciónNiega todas las tools (not_a_member). Autoriza de nuevo con una cuenta que pertenezca a la organización.
MiembroLos permisos del rol, aplicados tool por tool. Los comodines *, agent.* y agent.<recurso>.* valen como en la consola.
La consulta de permisos fallaNiega todas las tools. Falla cerrada.

A diferencia de la API, el MCP no tiene token de integración sin persona: el token tiene que llevar a una persona de la organización (por el sub o por el correo del token); si no, ninguna tool corre.

Los permisos se releen al menos una vez por minuto, así que cambiar o quitar el rol de alguien vale en menos de un minuto, sin esperar a que el token expire.

Una tool que el llamador no puede ejecutar no se lista en tools/list. Cuando tools/call la rechaza, el código dice quién lo resuelve:

CódigoQuién lo resuelve
insufficient_scopeTú, autorizando de nuevo con el acceso que faltó — o usando un token personal que alcance el recurso con el nivel pedido.
insufficient_permissionUn administrador de la organización, concediendo el permiso (el error dice cuál).
not_a_memberAutorizar 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 alguien que solo lee expone solo las tools de lectura, haga lo que haga el modelo del otro lado. :::

Alcance del token​

Además del rol, el MCP aplica el alcance que lleva el token, en el claim scope, con la misma gramática de la API (mira Autenticación de la API → Alcances). Las dos verificaciones se suman: una tool solo aparece si las dos lo permiten.

ToolExige
Lectura (*_list, *_get, kadu_usage_get…)El alcance del recurso (kadu/tasks)
Eliminación (*_delete)El alcance del recurso + delete
Cualquier otro cambio (crear, modificar, lanzar, cancelar, continuar, sincronizar, reenviar, rotar un secreto)El alcance del recurso + write
kadu_me_getCualquier token válido

El recurso es el primer segmento de la ruta que refleja la tool: kadu_executions_logs_list es del recurso executions, y kadu_tasks_run exige kadu/tasks write. Las aprobaciones por enlace (kadu_operation_approvals_*) se leen con kadu/system_events. Ningún nivel reemplaza a otro: write no elimina. Ninguna tool exige import ni export.

Alcance del tokenResultado
kadu/executions kadu/todos read writeLee y modifica ejecuciones y pendientes — cancela, continúa y resuelve — y nada más
kadu/tasks kadu/executions writeLee, lanza y sigue tareas, sin eliminar nada
read (sin ningún kadu/…)Lee todo, no escribe nada

:::info Los clientes conectados por OAuth piden todos los niveles — tú eliges cuáles conceder El documento /.well-known/oauth-protected-resource anuncia los recursos de Kadu y los seis niveles de acceso, y eso es lo que el cliente pide en la pantalla de consentimiento. Allí desmarcas lo que no quieres conceder: el token emitido lleva solo los recursos y niveles que quedaron marcados, y el MCP lista solo las tools que alcanzan. Una tool fuera de eso devuelve insufficient_scope, y la salida es autorizar de nuevo concediendo el acceso que faltó — delete para las tools de eliminación, por ejemplo. :::

Revocación del token personal​

Kadu verifica el token por su cuenta, por la firma, sin consultar a la Cuenta Kobana en cada llamada: revocar allí un token personal no corta el acceso al instante, y sigue aceptado hasta su validez. 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, quita el vínculo de la persona con la organización o cambia su rol — vale en menos de un minuto.

Modos de falla​

HTTPcodeCausa
400-32022 (JSON-RPC)Versión del protocolo no soportada, en la cabecera MCP-Protocol-Version o en el _meta; data.supported lista las soportadas. Mira Transporte.
401invalid_tokenToken ausente, mal formado, inválido, emitido para otro recurso (la API, por ejemplo) o con más de una audience en aud.
401token_expiredEl token expiró. El cliente lo renueva y lo intenta de nuevo.
401token_revokedEl token fue revocado en Kadu.
401invalid_requestToken en la query string — mira el aviso al principio de la página.
403unknown_organizationEl token es válido, pero la organización que nombra no existe en Kadu.
403FORBIDDENOrigin fuera de la lista permitida (origin_not_allowed).
404NOT_FOUNDLa solicitud llegó por un host que no sirve MCP.
413-32600 (JSON-RPC)Cuerpo de más de 1 MB.
429TOO_MANY_REQUESTSLímite de solicitudes alcanzado, con Retry-After y X-RateLimit-* — mira Límite de Peticiones.
503SERVICE_UNAVAILABLENo pudimos verificar el token contra el Authorization Server. Es de nuestro lado: inténtalo de nuevo después del Retry-After.

Todo 401 lleva el desafío WWW-Authenticate de arriba, que devuelve al cliente al flujo OAuth. El desafío dice siempre error="invalid_token" (o invalid_request, para token en la URL), como manda la RFC 6750; es el code del cuerpo el que distingue un token expirado (token_expired) de los demás. Los intentos con token rechazado cuentan en un límite por IP, y pasado el límite la respuesta pasa a ser 429.

Ninguna respuesta del MCP se puede cachear: todas, rechazos incluidos, llevan Cache-Control: no-store y Content-Security-Policy: default-src 'none'. La excepción es el documento público /.well-known/oauth-protected-resource, con Cache-Control: public, max-age=300.

Las negativas de alcance y de permiso no son errores HTTP: vuelven como resultado de tool marcado isError, para que el modelo lo lea y reaccione — mira Errores.

Host y borde​

El MCP solo responde por mcp.kadu.ia.br — nunca por el host de la consola, nunca por el host de la API, que apuntan a la misma aplicación. Por cualquier otro camino la respuesta es 404: el endpoint no anuncia que existe en otro lugar.

El identificador de recurso OAuth — y, por lo tanto, la audience que el token tiene que llevar — viene de la configuración del servidor, nunca del Host de la solicitud, para que un Host falsificado no pueda apuntar a un cliente a otro identificador.