Tutorial: ¿Quién soy? (Who am I?)
Este tutorial te guiará a través del proceso de configurar MCP Auth para autenticar usuarios y obtener su información de identidad desde el servidor de autorización.
Después de completar este tutorial, tendrás:
- ✅ Una comprensión básica de cómo usar MCP Auth para autenticar usuarios.
- ✅ Un servidor MCP que ofrece una herramienta para obtener información de identidad del usuario.
Descripción general
El tutorial involucrará los siguientes componentes:
- Servidor MCP: Un servidor MCP sencillo que utiliza los SDKs oficiales de MCP para manejar solicitudes.
- Inspector MCP: Una herramienta visual de pruebas para servidores MCP. También actúa como un cliente OAuth / OIDC para iniciar el flujo de autorización y obtener tokens de acceso.
- Servidor de autorización: Un proveedor OAuth 2.1 u OpenID Connect que gestiona identidades de usuario y emite tokens de acceso.
Aquí tienes un diagrama de alto nivel de la interacción entre estos componentes:
Comprende tu servidor de autorización
Obtener información de identidad del usuario
Para completar este tutorial, tu servidor de autorización debe ofrecer una API para obtener información de identidad del usuario:
- Logto
- Keycloak
- OIDC
- OAuth 2
Logto es un proveedor OpenID Connect que admite el endpoint userinfo estándar para obtener información de identidad del usuario.
Para obtener un token de acceso que pueda usarse para acceder al endpoint userinfo, se requieren al menos dos alcances: openid
y profile
. Puedes seguir leyendo, ya que cubriremos la configuración de alcances más adelante.
Keycloak es una solución de gestión de identidad y acceso de código abierto que admite múltiples protocolos, incluido OpenID Connect (OIDC). Como proveedor OIDC, implementa el endpoint userinfo estándar para obtener información de identidad del usuario.
Para obtener un token de acceso que pueda usarse para acceder al endpoint userinfo, se requieren al menos dos alcances: openid
y profile
. Puedes seguir leyendo, ya que cubriremos la configuración de alcances más adelante.
La mayoría de los proveedores OpenID Connect admiten el endpoint userinfo para obtener información de identidad del usuario.
Consulta la documentación de tu proveedor para ver si admite este endpoint. Si tu proveedor admite OpenID Connect Discovery, también puedes comprobar si el userinfo_endpoint
está incluido en el documento de descubrimiento (respuesta del endpoint .well-known/openid-configuration
).
Para obtener un token de acceso que pueda usarse para acceder al endpoint userinfo, se requieren al menos dos alcances: openid
y profile
. Consulta la documentación de tu proveedor para ver el mapeo de alcances a reclamos de identidad del usuario.
Aunque OAuth 2.0 no define una forma estándar de obtener información de identidad del usuario, muchos proveedores implementan sus propios endpoints para hacerlo. Consulta la documentación de tu proveedor para ver cómo obtener información de identidad del usuario usando un token de acceso y qué parámetros se requieren para obtener dicho token al invocar el flujo de autorización.
Registro dinámico de clientes
El registro dinámico de clientes no es necesario para este tutorial, pero puede ser útil si deseas automatizar el proceso de registro del cliente MCP con tu servidor de autorización. Consulta ¿Es necesario el registro dinámico de clientes? para más detalles.
Configura el servidor MCP
Usaremos los SDKs oficiales de MCP para crear un servidor MCP con una herramienta whoami
que obtiene información de identidad del usuario desde el servidor de autorización.
Crea un nuevo proyecto
- Python
- Node.js
mkdir mcp-server
cd mcp-server
uv init # O usa `pipenv` o `poetry` para crear un nuevo entorno virtual
Configura un nuevo proyecto Node.js:
mkdir mcp-server
cd mcp-server
npm init -y # O usa `pnpm init`
npm pkg set type="module"
npm pkg set main="whoami.js"
npm pkg set scripts.start="node whoami.js"
Instala el SDK de MCP y dependencias
- Python
- Node.js
pip install "mcp[cli]" starlette uvicorn
O cualquier otro gestor de paquetes que prefieras, como uv
o poetry
.
npm install @modelcontextprotocol/sdk express
O cualquier otro gestor de paquetes que prefieras, como pnpm
o yarn
.
Crea el servidor MCP
Primero, vamos a crear un servidor MCP que implemente una herramienta whoami
.
- Python
- Node.js
Crea un archivo llamado whoami.py
y añade el siguiente código:
from mcp.server.fastmcp import FastMCP
from starlette.applications import Starlette
from starlette.routing import Mount
from typing import Any
mcp = FastMCP("WhoAmI")
@mcp.tool()
def whoami() -> dict[str, Any]:
"""Una herramienta que retorna la información del usuario actual."""
return {"error": "Not authenticated"}
app = Starlette(
routes=[Mount('/', app=mcp.sse_app())]
)
Ejecuta el servidor con:
uvicorn whoami:app --host 0.0.0.0 --port 3001
Dado que la implementación actual del inspector MCP no maneja flujos de autorización, usaremos el enfoque SSE para configurar el servidor MCP. Actualizaremos el código aquí una vez que el inspector MCP admita flujos de autorización.
También puedes usar pnpm
o yarn
si lo prefieres.
Crea un archivo llamado whoami.js
y añade el siguiente código:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import express from 'express';
// Crear un servidor MCP
const server = new McpServer({
name: 'WhoAmI',
version: '0.0.0',
});
// Añadir una herramienta al servidor que retorna la información del usuario actual
server.tool('whoami', async () => {
return {
content: [{ type: 'text', text: JSON.stringify({ error: 'Not authenticated' }) }],
};
});
// Abajo está el código boilerplate de la documentación del SDK de MCP
const PORT = 3001;
const app = express();
const transports = {};
app.get('/sse', async (_req, res) => {
const transport = new SSEServerTransport('/messages', res);
transports[transport.sessionId] = transport;
res.on('close', () => {
delete transports[transport.sessionId];
});
await server.connect(transport);
});
app.post('/messages', async (req, res) => {
const sessionId = String(req.query.sessionId);
const transport = transports[sessionId];
if (transport) {
await transport.handlePostMessage(req, res, req.body);
} else {
res.status(400).send('No transport found for sessionId');
}
});
app.listen(PORT);
Ejecuta el servidor con:
npm start
Inspecciona el servidor MCP
Clona y ejecuta el inspector MCP
Ahora que tenemos el servidor MCP en funcionamiento, podemos usar el inspector MCP para ver si la herramienta whoami
está disponible.
Debido a la limitación de la implementación actual, hemos bifurcado el inspector MCP para hacerlo más flexible y escalable para autenticación y autorización. También hemos enviado un pull request al repositorio original para incluir nuestros cambios.
Para ejecutar el inspector MCP, puedes usar el siguiente comando (se requiere Node.js):
git clone https://github.com/mcp-auth/inspector.git
cd inspector
npm install
npm run dev
Luego, abre tu navegador y navega a http://localhost:6274/
(u otra URL mostrada en la terminal) para acceder al inspector MCP.
Conecta el inspector MCP al servidor MCP
Antes de continuar, revisa la siguiente configuración en el inspector MCP:
- Tipo de transporte: Establece en
SSE
. - URL: Establece la URL de tu servidor MCP. En nuestro caso, debería ser
http://localhost:3001/sse
.
Ahora puedes hacer clic en el botón "Connect" para ver si el inspector MCP puede conectarse al servidor MCP. Si todo está bien, deberías ver el estado "Connected" en el inspector MCP.
Punto de control: Ejecuta la herramienta whoami
- En el menú superior del inspector MCP, haz clic en la pestaña "Tools".
- Haz clic en el botón "List Tools".
- Deberías ver la herramienta
whoami
listada en la página. Haz clic en ella para abrir los detalles de la herramienta. - Deberías ver el botón "Run Tool" en el lado derecho. Haz clic en él para ejecutar la herramienta.
- Deberías ver el resultado de la herramienta con la respuesta JSON
{"error": "Not authenticated"}
.
Integra con tu servidor de autorización
Para completar esta sección, hay varias consideraciones a tener en cuenta:
La URL del emisor de tu servidor de autorización
Normalmente es la URL base de tu servidor de autorización, como https://auth.example.com
. Algunos proveedores pueden tener una ruta como https://example.logto.app/oidc
, así que asegúrate de consultar la documentación de tu proveedor.
Cómo obtener los metadatos del servidor de autorización
- Si tu servidor de autorización cumple con OAuth 2.0 Authorization Server Metadata o OpenID Connect Discovery, puedes usar las utilidades integradas de MCP Auth para obtener los metadatos automáticamente.
- Si tu servidor de autorización no cumple con estos estándares, deberás especificar manualmente la URL de metadatos o los endpoints en la configuración del servidor MCP. Consulta la documentación de tu proveedor para los endpoints específicos.
Cómo registrar el inspector MCP como cliente en tu servidor de autorización
- Si tu servidor de autorización admite registro dinámico de clientes, puedes omitir este paso ya que el inspector MCP se registrará automáticamente como cliente.
- Si tu servidor de autorización no admite el registro dinámico de clientes, deberás registrar manualmente el inspector MCP como cliente en tu servidor de autorización.
Cómo obtener información de identidad del usuario y cómo configurar los parámetros de la solicitud de autorización
-
Para proveedores OpenID Connect: normalmente necesitas solicitar al menos los alcances
openid
yprofile
al iniciar el flujo de autorización. Esto asegurará que el token de acceso devuelto por el servidor de autorización contenga los alcances necesarios para acceder al endpoint userinfo y obtener información de identidad del usuario.Nota: Algunos proveedores pueden no admitir el endpoint userinfo.
-
Para proveedores OAuth 2.0 / OAuth 2.1: consulta la documentación de tu proveedor para ver cómo obtener información de identidad del usuario usando un token de acceso y qué parámetros se requieren para obtener dicho token al invocar el flujo de autorización.
Aunque cada proveedor puede tener sus propios requisitos específicos, los siguientes pasos te guiarán en el proceso de integración del inspector MCP y el servidor MCP con configuraciones específicas del proveedor.
Registra el inspector MCP como cliente
- Logto
- Keycloak
- OIDC
- OAuth 2
Integrar con Logto es sencillo, ya que es un proveedor OpenID Connect que admite el endpoint userinfo estándar para obtener información de identidad del usuario.
Como Logto aún no admite el registro dinámico de clientes, deberás registrar manualmente el inspector MCP como cliente en tu tenant de Logto:
- Abre tu inspector MCP, haz clic en el botón "OAuth Configuration". Copia el valor de Redirect URL (auto-populated), que debería ser algo como
http://localhost:6274/oauth/callback
. - Inicia sesión en Logto Console (o tu instancia autoalojada de Logto Console).
- Navega a la pestaña "Applications", haz clic en "Create application". En la parte inferior de la página, haz clic en "Create app without framework".
- Completa los detalles de la aplicación y haz clic en "Create application":
- Selecciona un tipo de aplicación: Elige "Single-page application".
- Nombre de la aplicación: Ingresa un nombre para tu aplicación, por ejemplo, "MCP Inspector".
- En la sección "Settings / Redirect URIs", pega el valor de Redirect URL (auto-populated) que copiaste del inspector MCP. Luego haz clic en "Save changes" en la barra inferior.
- En la tarjeta superior, verás el valor "App ID". Cópialo.
- Vuelve al inspector MCP y pega el valor "App ID" en la sección "OAuth Configuration" bajo "Client ID".
- Ingresa el valor
{"scope": "openid profile email"}
en el campo "Auth Params". Esto asegurará que el token de acceso devuelto por Logto contenga los alcances necesarios para acceder al endpoint userinfo.
Keycloak es una solución de gestión de identidad y acceso de código abierto que admite el protocolo OpenID Connect.
Aunque Keycloak admite el registro dinámico de clientes, su endpoint de registro de clientes no admite CORS, lo que impide que la mayoría de los clientes MCP se registren directamente. Por lo tanto, necesitaremos registrar nuestro cliente manualmente.
Aunque Keycloak puede instalarse de varias formas (bare metal, kubernetes, etc.), para este tutorial, usaremos Docker para una configuración rápida y sencilla.
Vamos a configurar una instancia de Keycloak y ajustarla a nuestras necesidades:
- Primero, ejecuta una instancia de Keycloak usando Docker siguiendo la documentación oficial:
docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.2.4 start-dev
-
Accede a la consola de administración de Keycloak (http://localhost:8080/admin) e inicia sesión con estas credenciales:
- Usuario:
admin
- Contraseña:
admin
- Usuario:
-
Crea un nuevo Realm:
- Haz clic en "Create Realm" en la esquina superior izquierda
- Ingresa
mcp-realm
en el campo "Realm name" - Haz clic en "Create"
-
Crea un usuario de prueba:
- Haz clic en "Users" en el menú de la izquierda
- Haz clic en "Create new user"
- Completa los detalles del usuario:
- Usuario:
testuser
- Nombre y apellido pueden ser cualquier valor
- Usuario:
- Haz clic en "Create"
- En la pestaña "Credentials", establece una contraseña y desmarca "Temporary"
-
Registra el inspector MCP como cliente:
- Abre tu inspector MCP, haz clic en el botón "OAuth Configuration". Copia el valor de Redirect URL (auto-populated), que debería ser algo como
http://localhost:6274/oauth/callback
. - En la consola de administración de Keycloak, haz clic en "Clients" en el menú de la izquierda
- Haz clic en "Create client"
- Completa los detalles del cliente:
- Tipo de cliente: Selecciona "OpenID Connect"
- Client ID: Ingresa
mcp-inspector
- Haz clic en "Next"
- En la página "Capability config":
- Asegúrate de que "Standard flow" esté habilitado
- Haz clic en "Next"
- En la página "Login settings":
- Pega la URL de callback del inspector MCP previamente copiada en "Valid redirect URIs"
- Ingresa
http://localhost:6274
en "Web origins" - Haz clic en "Save"
- Copia el "Client ID" (que es
mcp-inspector
)
- Abre tu inspector MCP, haz clic en el botón "OAuth Configuration". Copia el valor de Redirect URL (auto-populated), que debería ser algo como
-
De vuelta en el inspector MCP:
- Pega el Client ID copiado en el campo "Client ID" en la sección "OAuth Configuration"
- Ingresa el siguiente valor en el campo "Auth Params" para solicitar los alcances necesarios:
{ "scope": "openid profile email" }
Esta es una guía genérica de integración con proveedores OpenID Connect. Consulta la documentación de tu proveedor para detalles específicos.
Si tu proveedor OpenID Connect admite el registro dinámico de clientes, puedes ir directamente al paso 8 a continuación para configurar el inspector MCP; de lo contrario, deberás registrar manualmente el inspector MCP como cliente en tu proveedor OpenID Connect:
- Abre tu inspector MCP, haz clic en el botón "OAuth Configuration". Copia el valor de Redirect URL (auto-populated), que debería ser algo como
http://localhost:6274/oauth/callback
. - Inicia sesión en la consola de tu proveedor OpenID Connect.
- Navega a la sección "Applications" o "Clients", luego crea una nueva aplicación o cliente.
- Si tu proveedor requiere un tipo de cliente, selecciona "Single-page application" o "Public client".
- Después de crear la aplicación, deberás configurar la URI de redirección. Pega el valor de Redirect URL (auto-populated) que copiaste del inspector MCP.
- Busca el "Client ID" o "Application ID" de la nueva aplicación y cópialo.
- Vuelve al inspector MCP y pega el valor "Client ID" en la sección "OAuth Configuration" bajo "Client ID".
- Para proveedores OpenID Connect estándar, puedes ingresar el siguiente valor en el campo "Auth Params" para solicitar los alcances necesarios para acceder al endpoint userinfo:
{ "scope": "openid profile email" }
Esta es una guía genérica de integración con proveedores OAuth 2.0 / OAuth 2.1. Consulta la documentación de tu proveedor para detalles específicos.
Si tu proveedor OAuth 2.0 / OAuth 2.1 admite el registro dinámico de clientes, puedes ir directamente al paso 8 a continuación para configurar el inspector MCP; de lo contrario, deberás registrar manualmente el inspector MCP como cliente en tu proveedor OAuth 2.0 / OAuth 2.1:
- Abre tu inspector MCP, haz clic en el botón "OAuth Configuration". Copia el valor de Redirect URL (auto-populated), que debería ser algo como
http://localhost:6274/oauth/callback
. - Inicia sesión en la consola de tu proveedor OAuth 2.0 / OAuth 2.1.
- Navega a la sección "Applications" o "Clients", luego crea una nueva aplicación o cliente.
- Si tu proveedor requiere un tipo de cliente, selecciona "Single-page application" o "Public client".
- Después de crear la aplicación, deberás configurar la URI de redirección. Pega el valor de Redirect URL (auto-populated) que copiaste del inspector MCP.
- Busca el "Client ID" o "Application ID" de la nueva aplicación y cópialo.
- Vuelve al inspector MCP y pega el valor "Client ID" en la sección "OAuth Configuration" bajo "Client ID".
- Lee la documentación de tu proveedor para ver cómo obtener tokens de acceso para información de identidad del usuario. Es posible que debas especificar los alcances o parámetros requeridos para obtener el token de acceso. Por ejemplo, si tu proveedor requiere el alcance
profile
para acceder a la información de identidad del usuario, puedes ingresar el siguiente valor en el campo "Auth Params":
{ "scope": "profile" }
Configura MCP Auth
En tu proyecto del servidor MCP, necesitas instalar el SDK de MCP Auth y configurarlo para usar los metadatos de tu servidor de autorización.
- Python
- Node.js
Primero, instala el paquete mcpauth
:
pip install mcpauth
O cualquier otro gestor de paquetes que prefieras, como uv
o poetry
.
Primero, instala el paquete mcp-auth
:
npm install mcp-auth
MCP Auth requiere los metadatos del servidor de autorización para poder inicializarse. Dependiendo de tu proveedor:
- Logto
- Keycloak
- OIDC
- OAuth 2
La URL del emisor se puede encontrar en la página de detalles de tu aplicación en Logto Console, en la sección "Endpoints & Credentials / Issuer endpoint". Debería verse como https://my-project.logto.app/oidc
.
- Python
- Node.js
Actualiza el archivo whoami.py
para incluir la configuración de MCP Auth:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # Reemplaza con tu endpoint de emisor
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OIDC)
mcp_auth = MCPAuth(server=auth_server_config)
Actualiza el archivo whoami.js
para incluir la configuración de MCP Auth:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // Reemplaza con tu endpoint de emisor
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oidc' }),
});
Ahora, necesitamos crear un verificador personalizado de token de acceso (Access token) que obtendrá la información de identidad del usuario desde el servidor de autorización utilizando el token de acceso proporcionado por el inspector MCP.
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
Si el token es válido, retorna un objeto `AuthInfo` que contiene la información del usuario.
:param token: El token Bearer recibido del inspector MCP.
"""
issuer = auth_server_config.metadata.issuer
endpoint = auth_server_config.metadata.userinfo_endpoint # El proveedor debe soportar el endpoint userinfo
if not endpoint:
raise ValueError(
"El endpoint userinfo no está configurado en los metadatos del servidor de autenticación."
)
try:
response = requests.get(
endpoint,
headers={"Authorization": f"Bearer {token}"}, # Encabezado estándar para token Bearer
)
response.raise_for_status() # Asegura que se lance un error para errores HTTP
json = response.json() # Analiza la respuesta JSON
return AuthInfo(
token=token,
subject=json.get("sub"), # 'sub' es un reclamo estándar para el sujeto (ID del usuario)
issuer=issuer, # Usa el emisor de los metadatos
claims=json, # Incluye todos los reclamos (campos JSON) retornados por el endpoint userinfo
)
# `AuthInfo` es un modelo de Pydantic, así que los errores de validación usualmente significan que la respuesta no coincide
# con la estructura esperada
except pydantic.ValidationError as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN,
cause=e,
)
# Maneja otras excepciones que puedan ocurrir durante la solicitud
except Exception as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.TOKEN_VERIFICATION_FAILED,
cause=e,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
* Si el token es válido, retorna un objeto `AuthInfo` que contiene la información del usuario.
*/
const verifyToken = async (token) => {
const { issuer, userinfoEndpoint } = mcpAuth.config.server.metadata;
if (!userinfoEndpoint) {
throw new Error('El endpoint userinfo no está configurado en los metadatos del servidor');
}
const response = await fetch(userinfoEndpoint, {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer,
subject: String(userInfo.sub), // 'sub' es un reclamo estándar para el sujeto (ID del usuario)
clientId: '', // El Client ID no se usa en este ejemplo, pero puede establecerse si es necesario
scopes: [],
claims: userInfo,
};
};
La URL del emisor se puede encontrar en tu consola de administración de Keycloak. En tu 'mcp-realm', navega a la sección "Realm settings / Endpoints" y haz clic en el enlace "OpenID Endpoint Configuration". El campo issuer
en el documento JSON contendrá tu URL de emisor, que debería verse como http://localhost:8080/realms/mcp-realm
.
- Python
- Node.js
Actualiza el archivo whoami.py
para incluir la configuración de MCP Auth:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # Reemplaza con tu endpoint de emisor
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OIDC)
mcp_auth = MCPAuth(server=auth_server_config)
Actualiza el archivo whoami.js
para incluir la configuración de MCP Auth:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // Reemplaza con tu endpoint de emisor
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oidc' }),
});
Ahora, necesitamos crear un verificador personalizado de token de acceso (Access token) que obtendrá la información de identidad del usuario desde el servidor de autorización utilizando el token de acceso proporcionado por el inspector MCP.
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
Si el token es válido, retorna un objeto `AuthInfo` que contiene la información del usuario.
:param token: El token Bearer recibido del inspector MCP.
"""
issuer = auth_server_config.metadata.issuer
endpoint = auth_server_config.metadata.userinfo_endpoint # El proveedor debe soportar el endpoint userinfo
if not endpoint:
raise ValueError(
"El endpoint userinfo no está configurado en los metadatos del servidor de autenticación."
)
try:
response = requests.get(
endpoint,
headers={"Authorization": f"Bearer {token}"}, # Encabezado estándar para token Bearer
)
response.raise_for_status() # Asegura que se lance un error para errores HTTP
json = response.json() # Analiza la respuesta JSON
return AuthInfo(
token=token,
subject=json.get("sub"), # 'sub' es un reclamo estándar para el sujeto (ID del usuario)
issuer=issuer, # Usa el emisor de los metadatos
claims=json, # Incluye todos los reclamos (campos JSON) retornados por el endpoint userinfo
)
# `AuthInfo` es un modelo de Pydantic, así que los errores de validación usualmente significan que la respuesta no coincide
# con la estructura esperada
except pydantic.ValidationError as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN,
cause=e,
)
# Maneja otras excepciones que puedan ocurrir durante la solicitud
except Exception as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.TOKEN_VERIFICATION_FAILED,
cause=e,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
* Si el token es válido, retorna un objeto `AuthInfo` que contiene la información del usuario.
*/
const verifyToken = async (token) => {
const { issuer, userinfoEndpoint } = mcpAuth.config.server.metadata;
if (!userinfoEndpoint) {
throw new Error('El endpoint userinfo no está configurado en los metadatos del servidor');
}
const response = await fetch(userinfoEndpoint, {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer,
subject: String(userInfo.sub), // 'sub' es un reclamo estándar para el sujeto (ID del usuario)
clientId: '', // El Client ID no se usa en este ejemplo, pero puede establecerse si es necesario
scopes: [],
claims: userInfo,
};
};
El siguiente código también asume que el servidor de autorización admite el endpoint userinfo para obtener información de identidad del usuario. Si tu proveedor no admite este endpoint, deberás consultar la documentación de tu proveedor para el endpoint específico y reemplazar la variable del endpoint userinfo con la URL correcta.
- Python
- Node.js
Actualiza el archivo whoami.py
para incluir la configuración de MCP Auth:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # Reemplaza con tu endpoint de emisor
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OIDC)
mcp_auth = MCPAuth(server=auth_server_config)
Actualiza el archivo whoami.js
para incluir la configuración de MCP Auth:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // Reemplaza con tu endpoint de emisor
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oidc' }),
});
En algunos casos, la respuesta del proveedor puede estar malformada o no ajustarse al formato de metadatos esperado. Si estás seguro de que el proveedor es compatible, puedes transpilar los metadatos mediante la opción de configuración:
- Python
- Node.js
mcp_auth = MCPAuth(
server=fetch_server_config(
# ...other options
transpile_data=lambda data: {**data, 'response_types_supported': ['code']}
)
)
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, {
// ...other options
transpileData: (data) => ({ ...data, response_types_supported: ['code'] }),
}),
});
Si tu proveedor no admite OpenID Connect Discovery, puedes especificar manualmente la URL de los metadatos o los endpoints. Consulta Otras formas de inicializar MCP Auth para más detalles.
Ahora, necesitamos crear un verificador personalizado de token de acceso (Access token) que obtendrá la información de identidad del usuario desde el servidor de autorización utilizando el token de acceso proporcionado por el inspector MCP.
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
Si el token es válido, retorna un objeto `AuthInfo` que contiene la información del usuario.
:param token: El token Bearer recibido del inspector MCP.
"""
issuer = auth_server_config.metadata.issuer
endpoint = auth_server_config.metadata.userinfo_endpoint # El proveedor debe soportar el endpoint userinfo
if not endpoint:
raise ValueError(
"El endpoint userinfo no está configurado en los metadatos del servidor de autenticación."
)
try:
response = requests.get(
endpoint,
headers={"Authorization": f"Bearer {token}"}, # Encabezado estándar para token Bearer
)
response.raise_for_status() # Asegura que se lance un error para errores HTTP
json = response.json() # Analiza la respuesta JSON
return AuthInfo(
token=token,
subject=json.get("sub"), # 'sub' es un reclamo estándar para el sujeto (ID del usuario)
issuer=issuer, # Usa el emisor de los metadatos
claims=json, # Incluye todos los reclamos (campos JSON) retornados por el endpoint userinfo
)
# `AuthInfo` es un modelo de Pydantic, así que los errores de validación usualmente significan que la respuesta no coincide
# con la estructura esperada
except pydantic.ValidationError as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN,
cause=e,
)
# Maneja otras excepciones que puedan ocurrir durante la solicitud
except Exception as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.TOKEN_VERIFICATION_FAILED,
cause=e,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
* Si el token es válido, retorna un objeto `AuthInfo` que contiene la información del usuario.
*/
const verifyToken = async (token) => {
const { issuer, userinfoEndpoint } = mcpAuth.config.server.metadata;
if (!userinfoEndpoint) {
throw new Error('El endpoint userinfo no está configurado en los metadatos del servidor');
}
const response = await fetch(userinfoEndpoint, {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer,
subject: String(userInfo.sub), // 'sub' es un reclamo estándar para el sujeto (ID del usuario)
clientId: '', // El Client ID no se usa en este ejemplo, pero puede establecerse si es necesario
scopes: [],
claims: userInfo,
};
};
Como mencionamos antes, OAuth 2.0 no define una forma estándar de obtener información de identidad del usuario. El siguiente código asume que tu proveedor tiene un endpoint específico para obtener información de identidad del usuario usando un token de acceso. Deberás consultar la documentación de tu proveedor para el endpoint específico y reemplazar la variable del endpoint userinfo con la URL correcta.
- Python
- Node.js
Actualiza el archivo whoami.py
para incluir la configuración de MCP Auth:
from mcpauth import MCPAuth
from mcpauth.config import AuthServerType
from mcpauth.utils import fetch_server_config
auth_issuer = '<issuer-endpoint>' # Reemplaza con tu endpoint de emisor
auth_server_config = fetch_server_config(auth_issuer, type=AuthServerType.OAUTH)
mcp_auth = MCPAuth(server=auth_server_config)
Actualiza el archivo whoami.js
para incluir la configuración de MCP Auth:
import { MCPAuth, fetchServerConfig } from 'mcp-auth';
const authIssuer = '<issuer-endpoint>'; // Reemplaza con tu endpoint de emisor
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, { type: 'oauth' }),
});
En algunos casos, la respuesta del proveedor puede estar malformada o no ajustarse al formato de metadatos esperado. Si estás seguro de que el proveedor es compatible, puedes transpilar los metadatos mediante la opción de configuración:
- Python
- Node.js
mcp_auth = MCPAuth(
server=fetch_server_config(
# ...other options
transpile_data=lambda data: {**data, 'response_types_supported': ['code']}
)
)
const mcpAuth = new MCPAuth({
server: await fetchServerConfig(authIssuer, {
// ...other options
transpileData: (data) => ({ ...data, response_types_supported: ['code'] }),
}),
});
Si tu proveedor no admite Metadatos del servidor de autorización OAuth 2.0, puedes especificar manualmente la URL de los metadatos o los endpoints. Consulta Otras formas de inicializar MCP Auth para más detalles.
Ahora, necesitamos crear un verificador personalizado de token de acceso (Access token) que obtendrá la información de identidad del usuario desde el servidor de autorización utilizando el token de acceso proporcionado por el inspector MCP.
- Python
- Node.js
import pydantic
import requests
from mcpauth.exceptions import (
MCPAuthTokenVerificationException,
MCPAuthTokenVerificationExceptionCode,
)
from mcpauth.types import AuthInfo
def verify_access_token(token: str) -> AuthInfo:
"""
Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
Si el token es válido, devuelve un objeto `AuthInfo` que contiene la información del usuario.
:param token: El token Bearer recibido del inspector MCP.
"""
try:
# El siguiente código asume que tu servidor de autorización tiene un endpoint para obtener la información del usuario
# usando el token de acceso emitido por el flujo de autorización.
# Ajusta la URL y los encabezados según la API de tu proveedor.
response = requests.get(
"https://your-authorization-server.com/userinfo",
headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status() # Asegúrate de lanzar un error para errores HTTP
json = response.json() # Analiza la respuesta JSON
# El siguiente código asume que la respuesta de información del usuario es un objeto con un campo 'sub' que
# identifica al usuario. Puede que necesites ajustar esto según la API de tu proveedor.
return AuthInfo(
token=token,
subject=json.get("sub"),
issuer=auth_issuer, # Usa el emisor configurado
claims=json, # Incluye todos los reclamos (claims) (campos JSON) devueltos por el endpoint
)
# `AuthInfo` es un modelo de Pydantic, por lo que los errores de validación suelen significar que la respuesta no coincide
# con la estructura esperada
except pydantic.ValidationError as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN,
cause=e,
)
# Maneja otras excepciones que puedan ocurrir durante la solicitud
except Exception as e:
raise MCPAuthTokenVerificationException(
MCPAuthTokenVerificationExceptionCode.TOKEN_VERIFICATION_FAILED,
cause=e,
)
import { MCPAuthTokenVerificationError } from 'mcp-auth';
/**
* Verifica el token Bearer proporcionado obteniendo la información del usuario desde el servidor de autorización.
* Si el token es válido, devuelve un objeto `AuthInfo` que contiene la información del usuario.
*/
const verifyToken = async (token) => {
// El siguiente código asume que tu servidor de autorización tiene un endpoint para obtener la información del usuario
// usando el token de acceso emitido por el flujo de autorización.
// Ajusta la URL y los encabezados según la API de tu proveedor.
const response = await fetch('https://your-authorization-server.com/userinfo', {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
throw new MCPAuthTokenVerificationError('token_verification_failed', response);
}
const userInfo = await response.json();
// El siguiente código asume que la respuesta de información del usuario es un objeto con un campo 'sub' que
// identifica al usuario. Puede que necesites ajustar esto según la API de tu proveedor.
if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) {
throw new MCPAuthTokenVerificationError('invalid_token', response);
}
return {
token,
issuer: authIssuer,
subject: String(userInfo.sub), // Ajusta esto según el campo de ID de usuario de tu proveedor
clientId: '', // El Client ID no se usa en este ejemplo, pero puede establecerse si es necesario
scopes: [],
claims: userInfo,
};
};
Actualiza el servidor MCP
¡Ya casi terminamos! Es momento de actualizar el servidor MCP para aplicar la ruta y función middleware de MCP Auth, y luego hacer que la herramienta whoami
retorne la información real de identidad del usuario.
- Python
- Node.js
@mcp.tool()
def whoami() -> dict[str, Any]:
"""Una herramienta que retorna la información del usuario actual."""
return (
mcp_auth.auth_info.claims
if mcp_auth.auth_info # Esto será poblado por el middleware Bearer auth
else {"error": "Not authenticated"}
)
# ...
bearer_auth = Middleware(mcp_auth.bearer_auth_middleware(verify_access_token))
app = Starlette(
routes=[
# Añade la ruta de metadatos (`/.well-known/oauth-authorization-server`)
mcp_auth.metadata_route(),
# Protege el servidor MCP con el middleware Bearer auth
Mount('/', app=mcp.sse_app(), middleware=[bearer_auth]),
],
)
server.tool('whoami', ({ authInfo }) => {
return {
content: [
{ type: 'text', text: JSON.stringify(authInfo?.claims ?? { error: 'Not authenticated' }) },
],
};
});
// ...
app.use(mcpAuth.delegatedRouter());
app.use(mcpAuth.bearerAuth(verifyToken));
Punto de control: Ejecuta la herramienta whoami
con autenticación
Reinicia tu servidor MCP y abre el inspector MCP en tu navegador. Cuando hagas clic en el botón "Connect", deberías ser redirigido a la página de inicio de sesión de tu servidor de autorización.
Una vez que inicies sesión y regreses al inspector MCP, repite las acciones que hicimos en el punto de control anterior para ejecutar la herramienta whoami
. Esta vez, deberías ver la información de identidad del usuario retornada por el servidor de autorización.
- Python
- Node.js
Consulta el repositorio del SDK de MCP Auth para Python para ver el código completo del servidor MCP (versión OIDC).
Consulta el repositorio del SDK de MCP Auth para Node.js para ver el código completo del servidor MCP (versión OIDC). Este directorio contiene versiones en TypeScript y JavaScript del código.
Notas finales
🎊 ¡Felicidades! Has completado exitosamente el tutorial. Recapitulemos lo que hemos hecho:
- Configuración de un servidor MCP básico con la herramienta
whoami
- Integración del servidor MCP con un servidor de autorización usando MCP Auth
- Configuración del Inspector MCP para autenticar usuarios y obtener su información de identidad
También puedes explorar algunos temas avanzados, incluyendo:
- Uso de JWT (JSON Web Token) para autenticación y autorización
- Aprovechar indicadores de recurso (RFC 8707) para especificar los recursos a los que se accede
- Implementar mecanismos de control de acceso personalizados, como control de acceso basado en roles (RBAC) o control de acceso basado en atributos (ABAC)
Asegúrate de consultar otros tutoriales y documentación para sacar el máximo provecho de MCP Auth.