Configurar autenticação Bearer no servidor MCP
Com a especificação MCP mais recente, seu servidor MCP atua como um Resource Server (Servidor de Recursos) que valida tokens de acesso para recursos protegidos. O MCP Auth oferece várias formas de configurar a autorização Bearer:
- Modo JWT (JSON Web Token): Um método de autorização integrado que verifica JWTs com afirmações de reivindicações.
- Modo personalizado: Permite que você implemente sua própria lógica de autorização.
O middleware de autenticação Bearer agora exige a especificação de qual recurso o endpoint pertence, permitindo a validação adequada do token em relação aos servidores de autorização configurados.
Configurar autenticação Bearer com modo JWT
Se seu provedor OAuth / OIDC emite JWTs para autorização, você pode usar o modo JWT integrado no MCP Auth. Ele verifica a assinatura do JWT, expiração e outras reivindicações que você especificar; em seguida, preenche as informações de autenticação no contexto da requisição para processamento posterior em sua implementação MCP.
Validação de escopo (Scope validation)
Aqui está um exemplo de validação básica de escopo:
- Python
- Node.js
from mcpauth import MCPAuth
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.routing import Mount
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("MyMCPServer")
mcp_auth = MCPAuth(
# Initialize with your auth server config
)
bearer_auth = mcp_auth.bearer_auth_middleware("jwt",
resource="https://api.example.com", # Especifique a qual recurso este endpoint pertence
audience="https://api.example.com", # Habilite a validação do público para segurança
required_scopes=["read", "write"]
)
app = Starlette(
routes=[Mount('/', app=mcp.sse_app(), middleware=[Middleware(bearer_auth)])]
)
import express from 'express';
import { MCPAuth } from 'mcp-auth';
const app = express();
const mcpAuth = new MCPAuth({
/* ... */
});
const bearerAuth = mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com', // Especifique a qual recurso este endpoint pertence
audience: 'https://api.example.com', // Habilite a validação do público para segurança
requiredScopes: ['read', 'write']
});
app.use('/mcp', bearerAuth, (req, res) => {
// Agora `req.auth` contém as informações de autenticação
console.log(req.auth);
});
No exemplo acima, especificamos que o JWT exige os escopos read
e write
. Se o JWT não contiver nenhum desses escopos, a requisição será rejeitada com um erro 403 Forbidden.
Validação de público (Audience validation) (RFC 8707)
Para validação segura do token, você deve sempre incluir a validação de público especificando o parâmetro audience
. Isso valida a reivindicação aud
(público) no JWT para garantir que o token foi emitido especificamente para o recurso do seu servidor MCP.
O parâmetro audience
é obrigatório pela especificação OAuth 2.0 para validação segura do token. No entanto, atualmente é opcional para manter a compatibilidade com servidores de autorização que ainda não suportam identificadores de recurso. Por motivos de segurança, sempre inclua o parâmetro audience quando possível. Versões futuras tornarão a validação de público obrigatória para cumprir totalmente a especificação.
O valor do público geralmente deve corresponder ao seu identificador de recurso:
- Python
- Node.js
bearer_auth = mcp_auth.bearer_auth_middleware(
"jwt",
resource="https://api.example.com", # Especifique a qual recurso este endpoint pertence
audience="https://api.example.com", # Habilite a validação do público para segurança
required_scopes=["read", "write"]
)
const bearerAuth = mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com', // Especifique a qual recurso este endpoint pertence
audience: 'https://api.example.com', // Habilite a validação do público para segurança
requiredScopes: ['read', 'write'],
});
No exemplo acima, o MCP Auth validará tanto a reivindicação aud
no JWT quanto os escopos necessários.
Forneça opções personalizadas para a verificação do JWT
Você também pode fornecer opções personalizadas para a biblioteca de verificação JWT subjacente:
- Python
- Node.js
No SDK Python, usamos PyJWT para verificação de JWT. Você pode usar as seguintes opções:
leeway
: Permite uma certa margem ao verificar o tempo de expiração do JWT (em segundos). O padrão é 60 segundos.
bearer_auth = mcp_auth.bearer_auth_middleware(
"jwt",
resource="https://api.example.com",
audience="https://api.example.com",
required_scopes=["read", "write"],
leeway=10, # Reduza a diferença de relógio permitindo 10 segundos de margem
)
No SDK Node.js, usamos a biblioteca jose para verificação de JWT. Você pode fornecer as seguintes opções:
jwtVerify
: Opções para o processo de verificação do JWT (funçãojwtVerify
dojose
).remoteJwtSet
: Opções para buscar o conjunto JWT remoto (funçãocreateRemoteJWKSet
dojose
).
const bearerAuth = mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com',
audience: 'https://api.example.com',
requiredScopes: ['read', 'write'],
jwtVerify: {
clockTolerance: 60, // Permite uma diferença de relógio de 60 segundos
},
remoteJwtSet: {
timeoutDuration: 10 * 1000, // Timeout de 10 segundos para busca do JWT remoto
},
});
Configurar autenticação Bearer com verificação personalizada
Se seu provedor OAuth / OIDC não emite JWTs, ou se você deseja implementar sua própria lógica de autorização, o MCP Auth permite criar uma função de verificação personalizada:
Como o middleware de autenticação Bearer verificará o emissor (iss
), público (aud
) e escopos necessários (scope
) com o resultado da verificação fornecido, não há necessidade de implementar essas verificações em sua função de verificação personalizada. Você pode focar em verificar a validade do token (por exemplo, assinatura, expiração, etc.) e retornar o objeto de informações de autenticação.
- Python
- Node.js
from mcpauth.exceptions import MCPAuthJwtVerificationException, MCPAuthJwtVerificationExceptionCode
from mcpauth.types import AuthInfo
async def custom_verification(token: str) -> AuthInfo:
# Implemente sua lógica personalizada de verificação aqui
info = await verify_token(token)
if not info:
raise MCPAuthJwtVerificationException(
MCPAuthJwtVerificationExceptionCode.JWT_VERIFICATION_FAILED
)
return info # Retorne o objeto de informações de autenticação
bearer_auth = mcp_auth.bearer_auth_middleware(
custom_verification,
resource="https://api.example.com",
audience="https://api.example.com", # Habilite a validação do público para segurança
required_scopes=["read", "write"]
)
const bearerAuth = mcpAuth.bearerAuth(
async (token) => {
// Implemente sua lógica personalizada de verificação aqui
const info = await verifyToken(token);
if (!info) {
throw new MCPAuthJwtVerificationError('jwt_verification_failed');
}
return info; // Retorne o objeto de informações de autenticação
},
{
resource: 'https://api.example.com',
audience: 'https://api.example.com', // Habilite a validação do público para segurança
requiredScopes: ['read', 'write']
}
);
Aplicar autenticação Bearer em seu servidor MCP
Para proteger seu servidor MCP com autenticação Bearer, você precisa aplicar o middleware de autenticação Bearer à sua instância do servidor MCP.
- Python
- Node.js
bearer_auth = mcp_auth.bearer_auth_middleware("jwt",
resource="https://api.example.com",
audience="https://api.example.com", # Habilite a validação do público para segurança
required_scopes=["read", "write"]
)
app = Starlette(
routes=[Mount('/', app=mcp.sse_app(), middleware=[Middleware(bearer_auth)])]
)
const app = express();
app.use(mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com',
audience: 'https://api.example.com', // Habilite a validação do público para segurança
requiredScopes: ['read', 'write']
}));
Isso garantirá que todas as requisições recebidas sejam autenticadas e autorizadas de acordo com as configurações Bearer auth, e as informações de autenticação estarão disponíveis no contexto da requisição.
Você pode então acessar as informações em sua implementação do servidor MCP:
- Python
- Node.js
@mcp.tool()
async def whoami() -> dict:
# `mcp_auth.auth_info` é o objeto de contexto para a requisição atual
auth_info = mcp_auth.auth_info
print(f"Usuário autenticado: {auth_info.subject}")
return {"subject": auth_info.subject}
// `authInfo` será carregado a partir do objeto `req.auth`
server.tool('whoami', ({ authInfo }) => {
console.log(`Usuário autenticado: ${authInfo.subject}`);
return { subject: authInfo.subject };
});