Producto

OAuth en MCP explicado: el puntero 401, PKCE, registro dinámico y scopes, de principio a fin

La autorización MCP es OAuth 2.1: un 401 apunta a los metadatos del servidor, el cliente se registra.

Por Atrix teamPublicado 11 min de lectura
En esta página
  1. Por qué MCP usa OAuth
  2. El flujo, paso a paso
  3. De qué protege cada pieza
  4. PKCE: por qué el código no sirve a un ladrón
  5. Registro dinámico de clientes: por qué nadie crea una app en una consola
  6. Scopes: estrechan, nunca amplían
  7. El mismo flujo en un servidor real
  8. Flujo PKCE frente a token pegado: lo que pierdes
  9. Preguntas frecuentes
  10. Siguiente paso

La autorización en MCP es OAuth 2.1 con unas pocas piezas obligatorias. Una petición sin autenticar a un servidor MCP remoto recibe un 401 que apunta a los metadatos del servidor; el cliente lo sigue hasta el servidor de autorización, se identifica, abre el navegador para que la persona consienta unos scopes, e intercambia un código protegido por PKCE por un token de acceso de corta vida y un token de refresco rotativo. El resultado es una credencial con scopes y revocable en lugar de una clave pegada en un archivo de configuración.

Ese es el flujo completo en un párrafo. El resto del artículo lo recorre paso a paso contra la especificación de autorización de MCP (revisión 2025-11-25), explica de qué protegen PKCE, el registro dinámico de clientes y los scopes, y muestra el flujo tal como ocurre contra un servidor real, el nuestro, para que veas cómo es cada etapa desde el lado del cliente.

Por qué MCP usa OAuth

Un servidor MCP local por stdio lee sus credenciales del entorno, y la especificación dice que no debería usar OAuth. Un servidor remoto es distinto: un despliegue sirve a muchas personas, cada una con permisos diferentes, desde apps de IA que el operador del servidor nunca ha visto. De ahí salen tres problemas.

  1. El servidor necesita saber quién pregunta, en cada llamada.
  2. La persona necesita limitar qué puede hacer la app, sin entregárselo todo.
  3. Ambos necesitan una forma de terminar el acceso más tarde, sin cambiar contraseñas ni rotar claves a mano.

Una clave de API pegada resuelve mal el primer problema y los otros dos no los resuelve. OAuth se diseñó exactamente para esta forma, una app que actúa por una persona ante un servicio, y OAuth 2.1 es su versión consolidada y más estricta. La entrada del glosario sobre OAuth 2.1 enumera lo que eliminó de 2.0; para MCP lo relevante es que PKCE es obligatorio, las URIs de redirección deben coincidir exactamente y los tokens no pueden viajar en la query string.

La especificación de autorización de MCP se apoya en cinco documentos: el borrador de OAuth 2.1 (draft-ietf-oauth-v2-1-13), Authorization Server Metadata (RFC 8414), Dynamic Client Registration (RFC 7591), Protected Resource Metadata (RFC 9728) y el borrador de Client ID Metadata Documents. No necesitas leerlos para usar un servidor MCP, pero cada uno responde a una de las preguntas de abajo.

El flujo, paso a paso

Esto es lo que ocurre entre el momento en que añades un servidor remoto y el momento en que el modelo hace su primera llamada a una herramienta. El cliente lo hace todo; tú ves una pestaña del navegador.

  1. El cliente llama al servidor sin token. El servidor, actuando como servidor de recursos OAuth, responde 401 Unauthorized con una cabecera WWW-Authenticate: Bearer que contiene resource_metadata, una URL. La especificación exige a los servidores implementar RFC 9728 y a los clientes interpretar esta cabecera. Si falta, el cliente debe probar las URIs well-known.
  2. El cliente obtiene los metadatos del recurso protegido. El documento nombra al menos una entrada en authorization_servers y puede listar scopes_supported.
  3. El cliente descubre el servidor de autorización. Obtiene sus metadatos vía RFC 8414 (/.well-known/oauth-authorization-server) o OpenID Connect Discovery; los clientes deben soportar ambos. Los metadatos listan los endpoints de autorización, token y registro, los métodos PKCE soportados y, si existe, client_id_metadata_document_supported.
  4. El cliente comprueba el soporte de PKCE. Si code_challenge_methods_supported no aparece en los metadatos, el cliente debe negarse a continuar. No hay degradación silenciosa.
  5. El cliente se identifica. Tres opciones, en el orden de prioridad de la especificación: credenciales prerregistradas si las tiene; un Client ID Metadata Document, donde el ID de cliente es una URL HTTPS a un archivo JSON que el cliente aloja; o registro dinámico de clientes, un POST al endpoint de registro que devuelve un client_id al instante. La especificación dice ahora que servidores y clientes deberían soportar los documentos de metadatos y pueden soportar el registro dinámico como alternativa.
  6. El cliente abre el navegador. La URL de autorización lleva el ID de cliente, la URI de redirección, los scopes solicitados, un valor state, el code_challenge de PKCE con code_challenge_method=S256 y el parámetro resource que nombra al servidor MCP (RFC 8707). La persona inicia sesión y ve una pantalla de consentimiento con el nombre del cliente y los scopes.
  7. El servidor de autorización redirige de vuelta con un código. El código es de corta vida y de un solo uso.
  8. El cliente intercambia el código por tokens. La petición de token lleva el código, el code_verifier original de PKCE y el mismo parámetro resource. La respuesta es un token de acceso y, normalmente, un token de refresco.
  9. Cada petición MCP lleva el token en Authorization: Bearer, nunca en la URL, y el servidor valida en cada llamada que el token es válido y se emitió para este servidor en concreto.
  10. Cuando una llamada necesita más scope, el servidor responde 403 con error="insufficient_scope" y los scopes necesarios. El cliente repite el flujo para el conjunto más amplio; la especificación lo llama autorización escalonada (step-up) y pide a los clientes limitar los reintentos.

De qué protege cada pieza

MecanismoDefinido enEl ataque que evita
Metadatos del recurso protegidoRFC 9728Que el cliente adivine o sea engañado para usar un servidor de autorización equivocado
Metadatos del servidor de autorizaciónRFC 8414Endpoints fijos en el código que se rompen cuando el servidor cambia
PKCE (S256)RFC 7636, OAuth 2.1Que alguien canjee un código de autorización robado
Coincidencia exacta de la URI de redirecciónOAuth 2.1Redirecciones abiertas que envían el código a un atacante
Parámetro stateOAuth 2.1Falsificación de petición entre sitios en el callback
Parámetro resourceRFC 8707Que un token de un servidor se reutilice en otro
Validación de audiencia en el servidorRFC 8707, OAuth 2.1Reenvío de tokens y ataques de confused deputy
Tokens de acceso de corta vidaOAuth 2.1Que un token filtrado siga siendo útil mucho tiempo
Tokens de refresco rotativosOAuth 2.1Que un token de refresco robado se reutilice en silencio
Scopes y consentimientoOAuth 2.0/2.1Que una app haga más de lo que la persona aceptó

Dos de ellas merecen una mirada más detenida porque son las que la gente pregunta.

PKCE: por qué el código no sirve a un ladrón

La mayoría de clientes MCP son clientes públicos: una app de escritorio, un editor o una CLI sin ningún secreto que pudieran guardar. En el flujo de código de autorización, el código vuelve mediante una redirección, y en un portátil o un móvil una redirección puede ser interceptada por otro programa registrado para la misma URL. Antes de PKCE, quien tuviera el código podía canjearlo.

PKCE añade un secreto de un solo uso por inicio de sesión. El cliente genera un code_verifier aleatorio, lo guarda y envía code_challenge = BASE64URL(SHA256(code_verifier)) con la petición de autorización. Al intercambiar el código, presenta el verifier original. El servidor de autorización lo hashea, lo compara con el challenge almacenado y rechaza el intercambio si difieren. Un ladrón con el código pero sin el verifier no obtiene nada. La entrada sobre PKCE explica el método plain y por qué OAuth 2.1 y MCP piden usar S256 siempre que sea posible.

Registro dinámico de clientes: por qué nadie crea una app en una consola

El OAuth clásico asumía que un desarrollador registraba cada app de antemano. Eso no escala en un mundo donde cualquiera de miles de clientes de IA puede conectarse a cualquiera de miles de servidores MCP sin relación previa. El registro dinámico de clientes (RFC 7591) permite al cliente enviar por POST sus propios metadatos, un nombre y las URIs de redirección, al endpoint de registro y recibir un client_id de inmediato.

La revisión 2025-11-25 añade una respuesta más limpia, los Client ID Metadata Documents: el ID de cliente es en sí mismo una URL HTTPS que apunta a un documento JSON que describe al cliente. El servidor de autorización lo obtiene, comprueba que el client_id del documento coincide exactamente con la URL y valida las URIs de redirección contra él. La especificación dice que clientes y servidores deberían soportarlo y pueden mantener el registro dinámico por compatibilidad. Como cualquier cliente puede registrarse, un servidor de autorización cuidadoso trata el registro como algo que no aporta confianza: muestra con claridad el nombre del cliente y el host de redirección en la pantalla de consentimiento y avisa cuando la redirección es un simple puerto de localhost, que la especificación señala que los documentos de metadatos por sí solos no pueden proteger del todo.

Scopes: estrechan, nunca amplían

Los scopes son los nombres de la pantalla de consentimiento: work.read, crm.write, etcétera. Una app pide un conjunto, la persona aprueba algunos o todos, y el token lleva el resultado. La especificación MCP indica a los clientes pedir los scopes del parámetro scope del desafío 401 si existe, y si no, los scopes_supported del servidor, y escalar después en lugar de pedirlo todo de golpe.

La regla que más importa es una que el estándar OAuth deja a cada API: un scope describe lo que la app puede pedir en nombre de la persona, y nunca debe exceder lo que esa persona puede hacer por sí misma. Un buen servidor comprueba ambas cosas en cada llamada: ¿el token tiene el scope, y la persona detrás tiene permiso para hacer esto con este registro?

El mismo flujo en un servidor real

Así se ven los pasos anteriores contra el servidor MCP de Atrix en https://atrix.dev/api/mcp, que operamos y usamos a diario, para que puedas emparejar el flujo abstracto con un comportamiento concreto. La guía para desarrolladores tiene las instrucciones cliente por cliente.

En Claude Code, toda la configuración es claude mcp add --transport http atrix https://atrix.dev/api/mcp, y después /mcp y Authenticate. El comando no lleva ninguna credencial a propósito. Lo que ocurre después:

  • La primera petición recibe 401 con el puntero de RFC 9728. El descubrimiento sigue RFC 8414 y RFC 9728.
  • El cliente se registra dinámicamente; no hay secreto de cliente en ningún sitio, porque todos los clientes, incluidas nuestras propias apps, son clientes públicos.
  • PKCE es solo S256. El servidor anuncia únicamente S256 en sus metadatos y rechaza plain.
  • Se abre el navegador; eliges un espacio de trabajo y apruebas scopes. Los códigos viven 60 segundos y funcionan una sola vez.
  • El cliente recibe un token de acceso con el prefijo atx_oat_, válido una hora, y un token de refresco con el prefijo atx_ort_, válido 90 días y rotado en cada uso.
  • Los scopes nunca añaden permisos. Se resuelven en cada llamada contra la cuenta detrás del token, así que si se revoca el acceso de un compañero, todos los tokens que creó dejan de llegar a nada en la siguiente petición. Nueve scopes requieren además el permiso correspondiente en la cuenta, como el valor de los deals o los registros laborales, y la nómina no se puede conceder en absoluto.
  • Los límites son 120 llamadas y 30 escrituras por minuto por token. Cada llamada se audita por herramienta, resultado y sujeto, nunca por contenido.

Para trabajos de CI y servidores sin navegador existe en su lugar un token de acceso personal, con prefijo atx_pat_, enviado como --header "Authorization: Bearer ...". Funciona, y es la peor opción allí donde haya un navegador: vive en texto plano en disco, dura lo que elegiste al crearlo y se salta la pantalla de consentimiento. Mantenemos esa opción para pipelines y recomendamos OAuth para personas.

Flujo PKCE frente a token pegado: lo que pierdes

OAuth 2.1 con PKCEToken de acceso personal pegado
Cómo te conectasAñades la URL, apruebas en el navegadorCreas el token en ajustes, lo pegas en la configuración
DuraciónAcceso 1 hora, refresco 90 días rotativo (Atrix)De 30 días a para siempre, según elijas
Dónde se guardaAlmacén seguro del clienteArchivo de configuración, a menudo en texto plano
Acotado porPantalla de consentimiento, escalado despuésElegido al crearlo
Se revocaRevocando la concesión o la cuentaBorrando el token
Necesita navegadorSíNo
Adecuado paraPersonas que usan una app de IACI, cron, servidores sin interfaz

Preguntas frecuentes

¿MCP exige OAuth?

La autorización es opcional en el protocolo. Cuando un servidor usa un transporte HTTP y soporta autorización, la especificación dice que debería ajustarse a la especificación de autorización basada en OAuth 2.1. Los servidores stdio no deberían usarla y deberían tomar las credenciales del entorno.

¿Qué diferencia hay entre OAuth 2.0 y OAuth 2.1 para MCP?

OAuth 2.1 elimina los grants implícito y de contraseña, exige PKCE en el flujo de código de autorización, exige coincidencia exacta de la URI de redirección, prohíbe tokens bearer en la query string y exige rotación o vinculación al emisor de los tokens de refresco para clientes públicos. MCP hereda todo esto.

¿Por qué mi cliente MCP se niega a conectarse a un servidor de autorización?

La razón más común es la falta de soporte de PKCE: si code_challenge_methods_supported no aparece en los metadatos del servidor de autorización, un cliente MCP debe negarse a continuar. La segunda es una cabecera WWW-Authenticate ausente o mal formada en el 401.

¿Sigue siendo obligatorio el registro dinámico de clientes?

No. La revisión 2025-11-25 dice que clientes y servidores deberían soportar Client ID Metadata Documents y pueden soportar el registro dinámico como alternativa. Muchos servidores, incluido Atrix, siguen ofreciendo registro dinámico porque los clientes más antiguos dependen de él.

¿Puede un token MCP hacer más que la persona que lo creó?

No debería. Los scopes estrechan el acceso; no lo amplían. Un servidor bien construido resuelve los permisos de la persona en cada llamada, así que un token nunca puede llegar a más que su dueño, y pierde el acceso en el momento en que lo pierde el dueño.

¿Cuándo debería usar un token de acceso personal en vez de OAuth?

Solo donde no haya navegador: pipelines de CI, tareas cron, servidores sin interfaz. En todos los demás casos, OAuth te da una credencial de vida más corta, con scopes y revocable sin guardar un secreto en disco.

Siguiente paso

La guía para desarrolladores recorre el flujo de Atrix cliente por cliente, con los comandos exactos para Claude Code, Claude Desktop, ChatGPT y Cursor. Si algún término de arriba era nuevo, las entradas sobre OAuth 2.1 y PKCE son las explicaciones más cortas que conocemos.

Comparte este artículo

Comparte este artículo

Pon en práctica las ideas de este artículo.

Pruébalo 7 días. Hace falta una tarjeta para empezar y se cobra al terminar la prueba, salvo que canceles; cancelar durante la prueba no cuesta nada.

Prueba de 7 días · requiere tarjeta · cancela cuando quieras