跳转到主要内容

在 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) 验证​

受众 (Audience) 验证

根据 OAuth 2.0 规范,audience 参数是必需的,用于安全的令牌 (Token) 验证。但目前为了兼容尚未支持资源指示器 (Resource indicators) 的授权 (Authorization) 服务器,该参数为可选。出于安全考虑,请尽可能始终包含 audience 参数。未来版本将强制要求受众 (Audience) 验证,以完全符合规范。

始终校验权限 (Scopes)

在 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 };
  }
);