在 MCP 服务器中配置 Bearer 认证 (auth)
根据最新的 MCP 规范,你的 MCP 服务器充当资源服务器,用于验证受保护资源的访问令牌 (Access tokens)。MCP Auth 提供了多种方式来配置 Bearer 授权 (Authorization):
- JWT (JSON Web Token) 模式:内置的授权 (Authorization) 方法,通过声明 (Claims) 断言验证 JWT。
- 自定义模式:允许你实现自己的授权 (Authorization) 逻辑。
Bearer 认证 (auth) 中间件现在需要指定端点属于哪个资源,以便针对配置的授权 (Authorization) 服务器进行正确的令牌 (Token) 验证。
使用 JWT 模式配置 Bearer 认证 (auth)
如果你的 OAuth / OIDC 提供方为授权 (Authorization) 签发 JWT,你可以在 MCP Auth 中使用内置的 JWT 模式。它会验证 JWT 的签名、过期时间以及你指定的其他声明 (Claims);然后会将认证 (Authentication) 信息填充到请求上下文中,供你的 MCP 实现进一步处理。
权限 (Scope) 和受众 (Audience) 验证
根据 OAuth 2.0 规范,audience 参数是必需的,用于安全的令牌 (Token) 验证。但目前为了兼容尚未支持资源指示器 (Resource indicators) 的授权 (Authorization) 服务器,该参数为可选。出于安全考虑,请尽可能始终包含 audience 参数。未来版本将强制要求受众 (Audience) 验证,以完全符合规范。
在 OAuth 2.0 中,权限 (Scopes) 是权限控制的主要机制。一个具有正确 audience 的有效令牌并不保证用户有执行某个操作的权限 —— 授权 (Authorization) 服务器可能会签发带有空或受限权限 (Scope) 的令牌。
始终使用 requiredScopes 来强制令牌包含每个操作所需的权限 (Permissions)。切勿假设一个有效令牌就意味着完全访问权限。
以下是基本权限 (Scope) 和受众 (Audience) 验证的示例:
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', // 指定该端点属于哪个资源
audience: 'https://api.example.com', // 启用受众 (Audience) 验证以增强安全性
requiredScopes: ['read', 'write'],
});
app.use('/mcp', bearerAuth, (req, res) => {
// 现在 `req.auth` 包含认证 (Authentication) 信息
console.log(req.auth);
});
在上面的示例中:
audience参数会验证 JWT 中的aud声明 (Claim),以确保令牌 (Token) 是专门为你的 MCP 服务器资源签发的。受众 (Audience) 的值通常应与你的资源标识符一致。requiredScopes参数指定 JWT 需要包含read和write权限 (Scopes)。如果令牌 (Token) 未包含所有这些权限 (Scopes),将会抛出错误。
为 JWT 验证提供自定义选项
你还可以为底层的 JWT 验证库提供自定义选项。在 Node.js SDK 中,我们使用 jose 库进行 JWT 验证。你可以提供以下选项:
jwtVerify:JWT 验证过程的选项(jose的jwtVerify函数)。remoteJwtSet:用于获取远程 JWT 集的选项(jose的createRemoteJWKSet函数)。
const bearerAuth = mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com',
audience: 'https://api.example.com',
requiredScopes: ['read', 'write'],
jwtVerify: {
clockTolerance: 60, // 允许 60 秒的时钟偏差
},
remoteJwtSet: {
timeoutDuration: 10 * 1000, // 获取远程 JWT 集的超时时间为 10 秒
},
});
使用自定义验证配置 Bearer 认证 (auth)
如果你的 OAuth / OIDC 提供方不签发 JWT,或者你希望实现自己的授权 (Authorization) 逻辑,MCP Auth 允许你创建自定义验证函数:
由于 Bearer 认证 (auth) 中间件会根据发行者 (Issuer)(iss)、受众 (Audience)(aud)和所需权限 (Scopes)(scope)对给定的验证结果进行检查,因此你无需在自定义验证函数中实现这些检查。你只需专注于验证令牌 (Token) 的有效性(如签名、过期等)并返回认证 (Authentication) 信息对象即可。
const bearerAuth = mcpAuth.bearerAuth(
async (token) => {
// 在这里实现你的自定义验证逻辑
const info = await verifyToken(token);
if (!info) {
throw new MCPAuthJwtVerificationError('jwt_verification_failed');
}
return info; // 返回认证 (Authentication) 信息对象
},
{
resource: 'https://api.example.com',
audience: 'https://api.example.com', // 启用受众 (Audience) 验证以增强安全性
requiredScopes: ['read', 'write']
}
);
在你的 MCP 服务器中应用 Bearer 认证 (auth)
要使用 Bearer 认证 (auth) 保护你的 MCP 服务器,你需要将 Bearer 认证 (auth) 中间件应用到 MCP 服务器实例上。
const app = express();
app.use(mcpAuth.bearerAuth('jwt', {
resource: 'https://api.example.com',
audience: 'https://api.example.com', // 启用受众 (Audience) 验证以增强安全性
requiredScopes: ['read', 'write']
}));
这将确保所有传入请求都根据配置的 Bearer 认证 (auth) 设置进行认证 (Authentication) 和授权 (Authorization),并且认证 (Authentication) 信息会在请求上下文中可用。
你随后可以在 MCP 服务器实现中访问这些信息:
// `authInfo` 会从 `req.auth` 对象中传递过来
server.registerTool(
'whoami',
{
description: '返回当前用户信息',
inputSchema: {},
},
({ authInfo }) => {
console.log(`认证 (Authentication) 用户: ${authInfo.subject}`);
return { subject: authInfo.subject };
}
);