授权
构建一个 Model Context Protocol (MCP) ↗ 服务器时,你既需要让用户登录(认证),也需要让他们授权 MCP client 访问其账户上的资源(授权)。
Model Context Protocol 使用 OAuth 2.1 的一个子集进行授权 ↗。OAuth 让用户能够授予对资源的有限访问权限,而不必分享 API key 或其他凭证。
Cloudflare 提供了一个 OAuth Provider 库 ↗,实现了 OAuth 2.1 协议的 provider 端,让你可以方便地为 MCP 服务器添加授权。
你可以以四种方式使用这个 OAuth Provider 库:
- 把 Cloudflare Access 用作 OAuth provider。
- 直接集成第三方 OAuth provider,例如 GitHub 或 Google。
- 集成你自己的 OAuth provider,包括你可能已在使用的 authorization-as-a-service provider,如 Stytch、Auth0 或 WorkOS。
- 由你的 Worker 自行处理授权和认证。运行在 Cloudflare 上的 MCP 服务器处理完整的 OAuth 流程。
下文介绍每个选项,并链接到可运行的代码示例。
授权选项
(1) Cloudflare Access OAuth provider
Cloudflare Access 让你能为 MCP 服务器添加单点登录 (SSO) 功能。用户使用已配置的身份提供商或一次性 PIN向 MCP 服务器认证,只有他们的身份匹配你设定的 Access 策略时才会被授予访问权。
要部署一个使用 Cloudflare Access 作为 OAuth provider 的示例 MCP 服务器 ↗,参阅 使用 Access for SaaS 保护 MCP 服务器。
(2) 第三方 OAuth Provider
OAuth Provider 库 ↗可以配置为使用第三方 OAuth provider,例如 GitHub 或 Google。完整示例参阅 GitHub 示例。
使用第三方 OAuth provider 时,你必须为 OAuthProvider 提供一个 handler,实现该第三方 provider 的 OAuth 流程。
TypeScript
import MyAuthHandler from "./auth-handler";
export default new OAuthProvider({
apiRoute: "/mcp",
// Your MCP server:
apiHandler: MyMCPServer.serve("/mcp"),
// Replace this handler with your own handler for authentication and authorization with the third-party provider:
defaultHandler: MyAuthHandler,
authorizeEndpoint: "/authorize",
tokenEndpoint: "/token",
clientRegistrationEndpoint: "/register",
});
Explain Code
注意 如 Model Context Protocol 规范所定义 ↗,当你使用第三方 OAuth provider 时,MCP 服务器(即你的 Worker)会生成并向 MCP client 发放自己的 token:
sequenceDiagram participant B as User-Agent (Browser) participant C as MCP Client participant M as MCP Server (your Worker) participant T as Third-Party Auth Server
C->>M: Initial OAuth Request
M->>B: Redirect to Third-Party /authorize
B->>T: Authorization Request
Note over T: User authorizes
T->>B: Redirect to MCP Server callback
B->>M: Authorization code
M->>T: Exchange code for token
T->>M: Third-party access token
Note over M: Generate bound MCP token
M->>B: Redirect to MCP Client callback
B->>C: MCP authorization code
C->>M: Exchange code for token
M->>C: MCP access token
更多详情请阅读 Workers OAuth Provider 库 ↗ 的文档。
(3) 自带 OAuth Provider
如果你的应用本身已经实现了 OAuth Provider,或你使用 authorization-as-a-service provider,可以按上面 (2) 第三方 OAuth Provider 中描述的方式使用它。
你可以用授权 provider 来:
- 让用户通过邮箱、社交登录、SSO(单点登录)和 MFA(多因素认证)向 MCP 服务器认证。
- 定义直接对应到 MCP 工具的 scope 和权限。
- 向用户呈现一个对应所请求权限的同意页。
- 强制执行权限,使 agent 只能调用被允许的工具。
Stytch
试用一个使用 Stytch ↗ 的远程 MCP 服务器,让用户通过邮箱、Google 登录或企业 SSO 登录,并授权他们的 AI agent 代为查看和管理公司 OKR。Stytch 会根据用户在组织中的角色和权限,限制授予 AI agent 的 scope。授权 MCP Client 时,每个用户会看到一个同意页,列出 agent 请求的、且用户根据其角色可授予的权限。
更偏 C 端的场景,可以部署一个为 To Do 应用使用 Stytch 做认证和 MCP client 授权的远程 MCP 服务器。用户用邮箱登录后立即可以访问与其账户关联的 To Do 列表,并允许任意 AI 助手帮他们管理任务。
Auth0
试用一个使用 Auth0 通过邮箱、社交登录或企业 SSO 认证用户的远程 MCP 服务器,让用户通过 AI agent 与他们的待办事项和个人数据交互。MCP 服务器代表用户安全地连接 API 端点,并明确显示在获得用户同意后 agent 能访问哪些资源。在这个实现中,access token 在长时间运行的交互中会自动刷新。
要进行配置,首先部署受保护的 API 端点:
然后,部署通过 Auth0 处理认证并把 AI agent 安全地连接到 API 端点的 MCP 服务器。
WorkOS
试用一个使用 WorkOS 的 AuthKit 来认证用户并管理授予 AI agent 权限的远程 MCP 服务器。在这个例子中,MCP 服务器根据用户的角色和访问权限动态暴露工具。所有已认证用户都可以使用 add 工具,但只有在 WorkOS 中被分配了 image_generation 权限的用户才能授予 AI agent 访问图像生成工具的权限。这展示了 MCP 服务器如何根据已认证用户的角色和权限,有条件地向 AI agent 暴露能力。
Descope
试用一个使用 Descope ↗ Inbound Apps 来认证和授权用户(例如,邮箱、社交登录、SSO)、让他们通过 AI agent 与自己数据交互的远程 MCP 服务器。利用 Descope 自定义 scope 来定义和管理权限,实现更精细的控制。
(4) 你的 MCP Server 自行处理授权与认证
你的 MCP Server 通过 OAuth Provider 库 ↗,可以处理完整的 OAuth 授权流程,无需任何第三方介入。
Workers OAuth Provider 库 ↗ 是一个实现了 fetch() handler 的 Cloudflare Worker,处理发往你 MCP 服务器的请求。
你提供 MCP Server API 的 handler,以及认证、授权逻辑和 OAuth 端点的 URI 路径,如下所示:
TypeScript
export default new OAuthProvider({
apiRoute: "/mcp",
// Your MCP server:
apiHandler: MyMCPServer.serve("/mcp"),
// Your handler for authentication and authorization:
defaultHandler: MyAuthHandler,
authorizeEndpoint: "/authorize",
tokenEndpoint: "/token",
clientRegistrationEndpoint: "/register",
});
Explain Code
参阅 入门示例,其中包含 OAuthProvider 的完整示例及一个模拟的认证流程。
这种情况下的授权流程是这样的:
sequenceDiagram participant B as User-Agent (Browser) participant C as MCP Client participant M as MCP Server (your Worker)
C->>M: MCP Request
M->>C: HTTP 401 Unauthorized
Note over C: Generate code_verifier and code_challenge
C->>B: Open browser with authorization URL + code_challenge
B->>M: GET /authorize
Note over M: User logs in and authorizes
M->>B: Redirect to callback URL with auth code
B->>C: Callback with authorization code
C->>M: Token Request with code + code_verifier
M->>C: Access Token (+ Refresh Token)
C->>M: MCP Request with Access Token
Note over C,M: Begin standard MCP message exchange
记住 — 认证不同于授权 ↗。你的 MCP Server 可以自己处理授权,同时仍然依赖外部认证服务先完成用户认证。入门指南中的 示例 提供了一个模拟的认证流程。你需要实现自己的认证 handler — 要么自行处理认证,要么使用外部认证服务。
在工具中使用认证上下文
当用户通过 OAuth Provider 完成认证后,他们的身份信息可在你的工具中访问。具体如何访问,取决于你使用的是 McpAgent 还是 createMcpHandler。
使用 McpAgent
McpAgent 的第三个类型参数定义了认证上下文的形状。在 init() 和工具 handler 中通过 this.props 访问。
TypeScript
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
type AuthContext = {
claims: { sub: string; name: string; email: string };
permissions: string[];
};
export class MyMCP extends McpAgent<Env, unknown, AuthContext> {
server = new McpServer({ name: "Auth Demo", version: "1.0.0" });
async init() {
this.server.tool("whoami", "Get the current user", {}, async () => ({
content: [{ type: "text", text: `Hello, ${this.props.claims.name}!` }],
}));
}
}
Explain Code
使用 createMcpHandler
使用 getMcpAuthContext() 在工具 handler 中访问相同信息。它在底层使用 AsyncLocalStorage。
TypeScript
import { createMcpHandler, getMcpAuthContext } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
function createServer() {
const server = new McpServer({ name: "Auth Demo", version: "1.0.0" });
server.tool("whoami", "Get the current user", {}, async () => {
const auth = getMcpAuthContext();
const name = (auth?.props?.name as string) ?? "anonymous";
return {
content: [{ type: "text", text: `Hello, ${name}!` }],
};
});
return server;
}
Explain Code
基于权限的工具访问控制
你可以根据用户权限控制哪些工具可用。有两种方式:在工具 handler 中检查权限,或有条件地注册工具。
TypeScript
export class MyMCP extends McpAgent<Env, unknown, AuthContext> {
server = new McpServer({ name: "Permissions Demo", version: "1.0.0" });
async init() {
this.server.tool("publicTool", "Available to all users", {}, async () => ({
content: [{ type: "text", text: "Public result" }],
}));
this.server.tool(
"adminAction",
"Requires admin permission",
{},
async () => {
if (!this.props.permissions?.includes("admin")) {
return {
content: [
{ type: "text", text: "Permission denied: requires admin" },
],
};
}
return {
content: [{ type: "text", text: "Admin action completed" }],
};
},
);
if (this.props.permissions?.includes("special_feature")) {
this.server.tool("specialTool", "Special feature", {}, async () => ({
content: [{ type: "text", text: "Special feature result" }],
}));
}
}
}
Explain Code
在 handler 中检查权限会返回错误消息给 LLM,LLM 可以向用户解释拒绝的原因。有条件地注册工具,LLM 永远看不到用户无权访问的工具 — 它根本无法尝试调用它们。
下一步
Workers OAuth Provider Workers 的 OAuth provider 库。
MCP 门户 设置 MCP 门户以提供治理与安全。