Flujo OAuth 2.1 de MCP explicado: CIMD frente a DCR con ejemplos
El flujo OAuth 2.1 de MCP, paso a paso, desde el desafío 401 y las consultas de metadatos hasta PKCE y la validación del token. Incluye JSON real de Client ID Metadata Documents y Dynamic Client Registration, una tabla comparativa y las comprobaciones de seguridad que exige cada enfoque.
Un cliente MCP que quiere llamar a un servidor protegido tiene un problema de confianza desde su primera petición. El servidor nunca ha visto a este cliente, y el servidor de autorización que hay detrás tampoco lo conoce. La especificación de autorización de MCP resuelve esto con OAuth 2.1, y lo que más ha cambiado en el último año es cómo obtiene un cliente su client_id. Client ID Metadata Documents (CIMD) llegó en la revisión 2025-11-25 como mecanismo de registro recomendado, y la revisión 2026-07-28 marca Dynamic Client Registration (DCR) como obsoleta. Este artículo recorre el flujo OAuth 2.1 de MCP desde la primera respuesta 401 hasta la primera llamada autorizada a una herramienta, muestra peticiones y respuestas reales para las dos vías de registro y termina con una regla sencilla para elegir entre ellas.
Por qué MCP necesita OAuth 2.1
Imagina la recepción de un hotel. Muestras tu identificación una vez, la recepción confirma quién eres y te vas con una tarjeta de habitación que abre tu habitación y nada más. OAuth sigue el mismo patrón. El servidor de autorización es la recepción, el token de acceso es la tarjeta de habitación y el servidor MCP es la puerta que comprueba la tarjeta. La puerta nunca ve tu pasaporte, y una tarjeta de la habitación 412 no abre la 518.
La autorización es opcional en MCP, pero las reglas se vuelven estrictas en cuanto la activas. Los servidores basados en HTTP DEBERÍAN seguir la especificación de autorización, mientras que los servidores stdio NO DEBERÍAN hacerlo y en su lugar leen las credenciales del entorno. Esto es lo que la especificación hace obligatorio:
PKCE con el método S256. Los clientes también deben comprobar que el servidor de autorización anuncia code_challenge_methods_supported, y no continuar si el campo falta.
Metadatos del recurso protegido (RFC 9728). El servidor MCP los publica, y el cliente los usa para encontrar el servidor de autorización correcto.
Indicadores de recurso (RFC 8707). Los clientes envían un parámetro resource tanto en la petición de autorización como en la petición de token.
Tokens Bearer en una cabecera. La cabecera Authorization: Bearer va en cada petición HTTP, y los tokens nunca aparecen en la cadena de consulta.
Validación de audiencia. Un servidor MCP solo acepta tokens emitidos para sí mismo.
Los cuatro actores
Todos los flujos de este artículo involucran a las mismas cuatro partes. Si las tienes claras, el resto se lee con facilidad.
Actor
Rol en OAuth
Ejemplo típico
Usuario
Propietario del recurso
Una persona que aprueba el acceso en un navegador
Cliente MCP
Cliente OAuth
Una app de escritorio con IA, un IDE, un agente CLI
Servidor MCP
Servidor de recursos
https://mcp.example.com/mcp
Servidor de autorización
Emite tokens
Auth0, Okta, Microsoft Entra ID o tu propio servicio
💡 El servidor MCP y el servidor de autorización pueden estar en un mismo despliegue o pertenecer a dos empresas distintas. Un client ID solo tiene sentido para el servidor de autorización que lo emitió o lo aceptó, así que un cliente nunca debe dar por hecho que un ID funciona en todas partes.
El flujo desde el 401 hasta el token
El handshake es una cadena corta de peticiones HTTP sencillas. Puedes seguir cada una en una terminal, lo que hace la depuración mucho menos misteriosa de lo que sugieren las siglas.
El desafío 401
El cliente envía una petición MCP sin token. El servidor la rechaza e indica al cliente dónde buscar:
El parámetro scope es la pista del servidor sobre el mínimo privilegio necesario para esta petición. Si falta el parámetro resource_metadata, el cliente recurre a las URL well-known, primero /.well-known/oauth-protected-resource/mcp (con la ruta insertada) y luego la versión raíz.
Dos consultas de metadatos
El cliente obtiene el documento de metadatos del recurso protegido y lee qué servidor de autorización usar:
Después pide al servidor de autorización que se describa, probando primero /.well-known/oauth-authorization-server y luego /.well-known/openid-configuration de OpenID Connect. El issuer de la respuesta debe coincidir con la URL que el cliente usó para construir la petición, o el documento se descarta. Una respuesta típica se ve así:
Dos campos de esa respuesta determinan cómo se registra el cliente: client_id_metadata_document_supported (CIMD) y registration_endpoint (DCR). Volveremos a ambos.
PKCE y el parámetro de recurso
Con un client_id en la mano, el cliente genera un verificador PKCE de un solo uso, calcula su hash y abre el navegador. También guarda el issuer esperado para comprobar la respuesta más tarde.
GET https://auth.example.com/authorize?response_type=code
&client_id=https%3A%2F%2Fapp.example.com%2Foauth%2Fclient-metadata.json
&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
&resource=https%3A%2F%2Fmcp.example.com%2Fmcp
&scope=files%3Aread
&state=xyz123
El valor resource es la URI canónica del servidor MCP. Los clientes DEBEN enviarlo aunque el servidor de autorización lo ignore, porque es lo que permite vincular un token a un servidor concreto.
Intercambio del código y uso del token
El usuario aprueba y el navegador vuelve a la URI de redirección con un code, el state y, idealmente, un parámetro iss. La revisión 2026-07-28 añade una comprobación del emisor según la RFC 9207: si iss está presente, el cliente lo compara con el emisor registrado antes de enviar el código a ningún sitio. Así se bloquean los ataques mix-up en los que un servidor de autorización hostil intenta capturar códigos destinados a uno honesto.
A continuación viene la petición de token, que demuestra la posesión del verificador PKCE:
La respuesta trae el token de acceso y, desde ese momento, cada petición al servidor MCP incluye Authorization: Bearer <access-token>. Si más adelante al token le falta un ámbito, el servidor responde 403 con error="insufficient_scope", y el cliente vuelve a autorizar con la unión de los ámbitos antiguos y los nuevos.
DCR: cómo funciona y dónde falla
Dynamic Client Registration viene de la RFC 7591. La idea es sencilla: antes del primer inicio de sesión, el cliente envía sus datos a un registration_endpoint y recibe a cambio un client_id nuevo. Nadie rellena un formulario. Durante años fue la forma principal de incorporar automáticamente un cliente desconocido, por eso lo adoptó MCP en sus primeras versiones.
Una petición de registro
Este es un intercambio realista para un cliente MCP de escritorio:
Fíjate en application_type. Desde la revisión 2026-07-28, los clientes DEBEN establecerlo. Los servidores que hablan OpenID Connect tratan un valor ausente como web, y ese valor por defecto puede rechazar URI de redirección localhost.
Por qué a los servidores les cuesta
DCR funciona, pero traslada mucha carga al servidor de autorización:
Un endpoint de escritura público. Cualquier persona en internet puede crear registros, así que necesitas límites de frecuencia, caducidad y tareas de limpieza.
Un registro por cada emparejamiento. Cada cliente se registra por separado en cada servidor de autorización y debe guardar el resultado de forma segura, indexado por issuer. Cuando cambia el servidor de autorización, el cliente tiene que registrarse de nuevo.
Nombres que nadie verificó. La pantalla de consentimiento muestra el client_name que haya escrito quien se registró, así que una aplicación hostil puede ponerse el nombre que quiera.
Crecimiento de la base de datos. Miles de instalaciones de un cliente popular se convierten en miles de registros que significan lo mismo.
Esos costos son la razón por la que la especificación ahora apunta las nuevas implementaciones a otra vía.
CIMD: la URL es el client ID
Piensa en un pasaporte. Nadie pide al agente de frontera que te memorice de antemano. Entregas un documento y el agente lo verifica con la autoridad que lo emitió. CIMD invierte el registro de la misma forma. El cliente publica un documento JSON en una URL HTTPS estable, y esa URL es el client_id. El servidor de autorización lee el documento la primera vez que ve la URL, así que no hay nada que registrar de antemano.
El documento de metadatos
Las reglas para el cliente son breves. El client_id debe usar https e incluir una ruta, el documento debe contener client_id, client_name y redirect_uris, y el client_id dentro del archivo debe coincidir con la URL desde la que se sirvió, carácter por carácter. El ejemplo de la propia especificación se ve así:
Cuando llega una petición de autorización con una URL con la forma client_id, el servidor de autorización sigue una rutina fija:
Descarga el documento con un simple GET por HTTPS.
Confirma que es un JSON válido y que contiene los campos obligatorios.
Confirma que el client_id del archivo es exactamente igual a la URL.
Confirma que el redirect_uri de la petición coincide con uno de los que figuran en el archivo.
Guarda el resultado en caché, respetando los encabezados de caché HTTP.
Muestra al usuario el client_name y el nombre de host de la redirección en la pantalla de consentimiento.
Un esbozo mínimo de los pasos 1 a 3 en TypeScript, pensado para ser claro más que para producción:
async function loadClient(clientId: string) {
const url = new URL(clientId);
if (url.protocol !== "https:" || url.pathname === "/") throw new Error("invalid_client");
await assertPublicHost(url.hostname); // reject private, loopback and link-local addresses
const res = await fetch(url, { redirect: "error", signal: AbortSignal.timeout(5000) });
const doc = await res.json();
if (doc.client_id !== clientId) throw new Error("invalid_client");
if (!doc.client_name || !Array.isArray(doc.redirect_uris)) throw new Error("invalid_client");
return doc;
}
Anunciar la compatibilidad con CIMD
El servidor de autorización anuncia la función en sus metadatos con "client_id_metadata_document_supported": true. Los clientes que la encuentran usan su URL como client_id y se saltan el registro por completo. Como el ID es una URL pública, también es portable: el mismo cliente puede hablar mañana con otro servidor de autorización sin registrarse de nuevo.
CIMD frente a DCR en una tabla
Pregunta
CIMD
DCR
Estado en la especificación de 2026-07-28
Recomendado (SHOULD)
Obsoleto, se mantiene por compatibilidad (MAY)
Quién guarda el registro del cliente
El cliente lo aloja, el servidor lo guarda en caché
El servidor de autorización lo guarda
Forma del client_id
Una URL como https://app.example.com/oauth/client-metadata.json
Una cadena opaca como s6BhdRkqt3
Necesita un endpoint de registro
No
Sí, anunciado como registration_endpoint
Trabajo antes del primer inicio de sesión
Ninguno para el cliente
Un POST por servidor de autorización
Portable entre servidores de autorización
Sí
No, hay que registrarse de nuevo por emisor
Riesgo principal
SSRF durante la descarga, suplantación de localhost
Abuso de un endpoint abierto, registros basura
Cómo lo anuncia el servidor
client_id_metadata_document_supported
registration_endpoint
Un cliente que admite todas las opciones DEBERÍA elegir en este orden:
Usar los datos de cliente preregistrados si los tiene para este servidor.
Usar CIMD si el servidor de autorización anuncia soporte.
Recurrir a DCR si existe un registration_endpoint.
Pedir al usuario que introduzca los datos del cliente a mano.
💡 El preregistro sigue siendo la mejor opción cuando lo tienes. Si controlas tanto el cliente como el servidor de autorización, un client_id fijo evita todas las consultas anteriores.
Comprobaciones de seguridad que no puedes saltarte
Pasar de DCR a CIMD no elimina el riesgo. Lo traslada a otros lugares, y cada uno necesita un responsable.
SSRF en la descarga
Con CIMD, un visitante anónimo decide qué URL pide tu servidor. Si apunta client_id a https://169.254.169.254/latest/meta-data/ o a un panel de administración interno, un descargador descuidado se convierte en un proxy hacia tu red. Resuelve primero el nombre de host y rechaza los rangos privados, de loopback y de enlace local. Establece un tiempo de espera corto, limita el tamaño de la respuesta y sé estricto con las redirecciones.
Redirecciones a localhost
Un documento de metadatos no puede demostrar que un proceso que escucha en localhost:3000 pertenezca al cliente nombrado en el archivo. Cualquier programa local puede reclamar ese puerto. Por eso el servidor de autorización DEBE mostrar el nombre de host de la redirección en la pantalla de consentimiento, DEBERÍA avisar cuando todas las URI de redirección sean localhost y PUEDE exigir una atestación adicional para obtener mayor garantía. Las propias URI de redirección deben coincidir exactamente, nunca por prefijo ni por patrón.
Audiencia y paso de tokens
El servidor MCP es la última puerta, y debe revisar la tarjeta, no solo echarle un vistazo. Valida la firma, la caducidad, los ámbitos y, sobre todo, la audiencia. Un token emitido para otro servicio debe rechazarse con un 401. Si tu servidor MCP llama a una API upstream, necesita un token distinto para esa API, emitido por el servidor de autorización de esa API. Reenviar el token del cliente se llama paso de tokens (token passthrough), y la especificación lo prohíbe de forma explícita.
Una lista breve para tener junto al monitor:
Sirve todos los endpoints de autorización por HTTPS y permite solo redirecciones HTTPS o localhost.
Mantén los tokens de acceso de vida corta y rota los tokens de refresco en los clientes públicos.
Usa y verifica el parámetro state.
Valida iss cuando esté presente, antes de canjear el código.
Incluye en un único desafío todos los ámbitos necesarios para una operación, para que el usuario no pase por pantallas de aprobación repetidas.
Elegir una estrategia
La decisión es menos dramática de lo que sugiere el debate. Adopta CIMD primero, mantén DCR como puente y sé honesto sobre qué papel te toca en cada caso.
Si ejecutas un servidor MCP
Publica los metadatos del recurso protegido pase lo que pase. Elige un servidor de autorización que soporte CIMD, y si el tuyo todavía no puede, deja DCR activado con límites de frecuencia y caducidad en lugar de bloquear a todos los clientes. Pon un scope en tu desafío WWW-Authenticate, responde con 403 y insufficient_scope cuando un token se quede corto, y verifica la audiencia en cada petición.
Si construyes un cliente MCP
Aloja tu documento de metadatos en una URL que vayas a mantener durante años, porque la URL es tu identidad. Lee los metadatos del servidor de autorización y elige la vía de registro en el código:
Cuando recurras a DCR, guarda las credenciales asociadas al issuer, establece application_type: "native" para las apps de escritorio y CLI, y nunca las reutilices con otro servidor de autorización.
Pruébalo en PicassoIA
Sea cual sea el lado del handshake que construyas, escribirás mucho JSON, fixtures de prueba y documentación. Un modelo de lenguaje capaz acelera ese trabajo, y PicassoIA aloja varios. Esta es una forma rápida de usar Claude Sonnet 5 como revisor de tu documento de metadatos:
Pega tu client-metadata.json y los metadatos del servidor de autorización de tu proveedor.
Pide una revisión con la lista de comprobaciones: "Revisa este documento según las reglas de CIMD: client_id igual a la URL, https con una ruta, campos obligatorios presentes, redirect_uris exactos. Enumera cada fallo."
Pide la respuesta en forma de tabla con regla, resultado y solución, para que sea fácil de pegar en una pull request.
Para una segunda opinión, ejecuta el mismo prompt en GPT 5.6 Sol o haz una pasada rápida con Gemini 3.5 Flash, y compara los fallos que encuentra cada uno.
💡 Los modelos revisan bien los documentos, pero no sustituyen una prueba real. Ejecuta tu flujo contra un servidor de autorización de staging antes de publicar.
La documentación necesita imágenes tanto como necesita JSON. Una imagen principal, un fondo para un diagrama o una tarjeta para redes sociales hace que una publicación sobre OAuth sea mucho más fácil de compartir, y PicassoIA está pensado justo para eso. Los resultados fotorrealistas salen de prompts específicos: nombra el objetivo, la dirección de la luz y las texturas de la escena. Prueba algo como "a hotel receptionist sliding a room card across a marble counter, 50mm lens, soft window light from the right, film grain" y mira qué sale. Los desarrolladores también pueden acceder a los modelos de imagen y video de PicassoIA a través de la API de PicassoIA y de las conexiones MCP, así que el mismo prompt puede ejecutarse desde tu propio agente.
¿Listo para crear tus propias imágenes? Abre PicassoIA, elige un modelo y empieza a experimentar con tu primer prompt hoy mismo.