在构建 AI
应用和 Agent
的圈子里,模型上下文协议 (Model Context Protocol
, MCP
) 正成为一个热门话题。许多讨论围绕着在本地计算机上安装和运行 MCP
服务器展开。近期,Cloudflare
宣布支持在其平台上构建和部署远程 MCP
服务器,这标志着 MCP
应用的一个重要转折点。
Cloudflare
为简化远程 MCP
服务器的构建,引入了四项关键能力:
workers-oauth-provider
:一个OAuth
Provider 库,极大简化了远程服务必需的授权流程。McpAgent
:集成在Cloudflare Agents SDK
中的一个类,负责处理MCP
的远程传输细节。mcp-remote
:一个适配器工具,让仅支持本地连接的MCP
客户端也能与远程MCP
服务器交互。AI playground
作为远程MCP
客户端:一个在线聊天界面,可以直接连接并测试远程MCP
服务器,内置了认证检查功能。
开发者可以通过 Cloudflare
提供的示例代码和部署按钮,在短时间内将一个 MCP
服务器部署到生产环境。
https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/ai/tree/main/demos/remote-mcp-server
与之前普遍使用的本地 MCP
服务器不同,远程 MCP
服务器可以公开访问。用户只需通过熟悉的授权流程登录并授予权限,MCP
客户端(如 AI Agent
)就能访问所需工具。这被认为是一个巨大的进步。过去几个月,将编码 Agent
连接到本地 MCP
服务器已让开发者初步体验到其潜力,而远程 MCP
则有望将类似的工作模式扩展到更广泛的用户群体,包括更多的日常消费级应用场景。这不仅仅是技术实现上的差异,更可能预示着 AI Agent
应用模式的根本性转变。
从本地到远程:MCP 走向大众的关键一步
MCP
正迅速成为一种通用协议,让大型语言模型 (LLM
) 的能力超越简单的推理 (inference
) 和检索增强生成 (RAG
),能够执行需要访问外部资源的操作(例如发送邮件、部署代码、发布博客等)。它使得 AI Agent
(MCP
客户端) 能够通过外部服务 (MCP
服务器) 提供的工具和资源进行交互。
然而,到目前为止,MCP
的应用大多局限在本地运行。如果想让 AI Agent
通过 MCP
访问网络上的某个工具,开发者通常需要在自己的机器上设置本地服务器。这意味着无法从网页界面或移动应用中使用 MCP
,也缺少让普通用户进行身份验证和授权的机制。MCP
服务器实际上并未真正“上线”。
对远程 MCP
连接的支持改变了这一局面。它为接触更广泛的互联网用户创造了机会,这些用户不太可能为了使用桌面应用而去本地安装和运行 MCP
服务器。远程 MCP
的支持,好比是从桌面软件向 Web
软件的过渡。用户期望跨设备连续工作,登录后一切就能正常使用。本地 MCP
对开发者来说很方便,但远程连接才是让 MCP
服务触达所有互联网用户的关键缺失环节。当然,远程连接也需要考虑网络延迟可能带来的影响,这与本地 stdio
通信是不同的。
让认证和授权在 MCP 中“开箱即用”
将 MCP
从本地推向远程,不仅仅是改变传输层(从 stdio
到可流式 HTTP
)。当构建一个需要访问用户账户信息的远程 MCP
服务器时,身份验证 (authentication
) 和授权 (authorization
) 变得至关重要。需要一种方式让用户登录并证明身份,还需要一种方式让用户控制 AI Agent
在使用服务时能够访问哪些内容。
MCP
规范采用了 OAuth 2.0
来解决这个问题。OAuth
是允许用户授权应用访问其信息或服务而无需共享密码的标准协议。在 MCP
场景下,MCP
服务器本身扮演 OAuth Provider
的角色。然而,自行完整实现符合 MCP
规范的 OAuth
流程相当复杂且容易出错。Cloudflare
提供的方案旨在解决这一痛点。
workers-oauth-provider
:为 Cloudflare Workers 定制的 OAuth 2.1 Provider 库
当开发者在 Cloudflare
上部署 MCP
服务器时,其 Worker
可以利用 workers-oauth-provider
这个新的 TypeScript
库来充当 OAuth Provider
。该库封装了 Worker
代码,为 API
端点(包括但不限于 MCP
服务器端点)添加了授权层。
MCP
服务器将直接收到已认证的用户信息作为参数,无需自行执行令牌验证或管理。同时,开发者仍然可以完全控制用户认证的方式:从登录界面 (UI
) 到选择何种身份提供商(如 Google
, GitHub
或自建系统)。
完整的 MCP OAuth
流程如下:
在这个流程中,MCP
服务器既是上游服务(如 GitHub
, Google
)的 OAuth
客户端,又是面向 MCP
客户端(如 AI Agent
)的 OAuth
服务器(Provider
)。开发者可以使用任何上游认证流程,而 workers-oauth-provider
确保 MCP
服务器符合 MCP
规范的授权要求,能够与各种客户端应用和网站配合工作。这包括支持动态客户端注册 (RFC 7591
) 和授权服务器元数据 (RFC 8414
)。相比自行实现,使用此库能显著降低开发复杂性,并提高安全性与合规性。
简洁、可插拔的 OAuth 接口
使用 Cloudflare Workers
构建 MCP
服务器时,开发者只需提供 OAuth Provider
相关路径(授权、令牌、客户端注册端点)的实例,以及 MCP
服务器和认证逻辑的处理器 (handler
):
import OAuthProvider from "@cloudflare/workers-oauth-provider";
import MyMCPServer from "./my-mcp-server";
import MyAuthHandler from "./auth-handler";
export default new OAuthProvider({
apiRoute: "/sse", // MCP 客户端连接服务器的路由
apiHandler: MyMCPServer.mount('/sse'), // MCP 服务器实现
defaultHandler: MyAuthHandler, // 认证实现
authorizeEndpoint: "/authorize",
tokenEndpoint: "/token",
clientRegistrationEndpoint: "/register",
});
这种抽象使得插入自定义认证逻辑变得容易。例如,一个使用 GitHub
作为身份提供商的 MCP
服务器,可以通过实现 /callback
和 /authorize
路由,在不到 100 行代码内完成集成。
为何 MCP 服务器要发行自己的 Token?
在上面的授权图中以及 MCP
规范的授权部分,值得注意的是 MCP
服务器会向 MCP
客户端发行自己的 Token
,而不是直接传递从上游服务获取的 Token
。
具体来说,Worker
会将从上游获取的访问令牌 (access token
) 加密存储(例如使用 Workers KV
),然后生成并发行一个全新的、独立的 Token
给 MCP
客户端。workers-oauth-provider
库会自动处理这个过程,开发者的代码无需直接接触明文的上游令牌或自行管理存储,从而避免潜在的安全风险。
// 调用 completeAuthorization 时传入的 accessToken 会被加密存储,绝不会暴露给 MCP 客户端
// 一个新的、独立的 token 会在 /token 端点生成并提供给客户端
const { redirectTo } = await c.env.OAUTH_PROVIDER.completeAuthorization({
request: oauthReqInfo,
userId: login,
metadata: { label: name },
scope: oauthReqInfo.scope,
props: {
accessToken, // 加密存储,不发送给 MCP 客户端
},
})
return Response.redirect(redirectTo)
表面上看,这种间接方式似乎更复杂。为何如此设计?
通过发行自己的 Token
,MCP
服务器可以实施比上游提供商更细粒度的访问控制。即使发放给 MCP
客户端的 Token
泄露,攻击者获得的也仅仅是该 MCP
服务器明确授予的有限权限(通过其提供的 tools
),而不是上游服务的完整访问权限。
例如,假设一个 MCP
服务器请求用户授权读取 Gmail
邮件的权限(使用 gmail.readonly scope
)。但该服务器暴露的 tool
功能更窄,只允许读取特定发件人的旅行预订通知,以回答诸如“我明天酒店的退房时间是几点?”之类的问题。开发者可以在 MCP
服务器中强制执行此约束。如果发放给 MCP
客户端的 Token
被盗,由于该 Token
对应的是 MCP
服务器而非原始的上游提供商 (Google
),攻击者无法用它读取任意邮件,只能调用 MCP
服务器提供的特定工具。OWASP
将“过度代理”(Excessive Agency
) 列为构建 AI
应用的主要风险之一。通过发行自有 Token
并强制执行约束,MCP
服务器可以限制工具的访问权限,仅提供客户端所需的功能,遵循最小权限原则。
另一个例子,基于前述的 GitHub
认证,可以强制只有特定用户才能访问某个工具。下面的示例中,只有白名单内的用户 (geelen
) 才能看到并调用 generateImage
工具,该工具使用 Workers AI
根据提示生成图像:
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const USER_ALLOWLIST = new Set(["geelen"]); // 使用 Set 提高查找效率
export class MyMCP extends McpAgent<Props, Env> {
server = new McpServer({
name: "Github OAuth Proxy Demo",
version: "1.0.0",
});
async init() {
// 根据用户身份动态添加工具
if (USER_ALLOWLIST.has(this.props.login)) {
this.server.tool(
'generateImage',
'使用 flux-1-schnell 模型生成图像。',
{
prompt: z.string().describe('你想要生成的图像的文本描述。')
},
async ({ prompt }) => {
const response = await this.env.AI.run('@cf/black-forest-labs/flux-1-schnell', {
prompt,
steps: 8
});
// 检查 response.image 是否存在
if (!response.image) {
throw new Error("图像生成失败,未返回图像数据。");
}
return {
content: [{ type: 'image', data: response.image, mimeType: 'image/jpeg' }],
}
}
)
}
}
}
引入 McpAgent:兼容当前与未来的远程传输
将 MCP
带出本地机器的下一步是开放远程传输层。本地运行的 MCP
服务器通常通过标准输入输出 (stdio
) 进行通信,但要让 MCP
服务器能通过互联网被调用,就必须实现远程传输协议,目前规范草案中是基于 HTTP
的 Server-Sent Events (SSE)
。
Cloudflare
在其 Agents SDK
中引入的 McpAgent
类处理了远程传输的复杂性。它在后台利用 Durable Objects
来维持持久连接,使得 MCP
客户端可以通过 SSE
向 MCP
服务器发送消息。开发者无需编写处理传输或序列化的底层代码。一个极简的 MCP
服务器可以仅用十几行代码实现:
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
export class MyMCP extends McpAgent {
server = new McpServer({
name: "Demo",
version: "1.0.0",
});
async init() {
this.server.tool("add", "计算两个数字的和", { a: z.number(), b: z.number() }, async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}));
}
}
值得注意的是,经过社区讨论,MCP
规范中的远程传输正在修订,计划用可流式 HTTP
(Streamable HTTP
) 替代当前的 HTTP+SSE
方案。这将允许与 MCP
服务器建立无状态、纯粹的 HTTP
连接,并可选升级到 SSE
,同时消除了客户端需要向不同端点发送消息的复杂性。Cloudflare
表示 McpAgent
类将随规范更新而演进,以支持新的 Streamable HTTP
标准,确保开发者不必重写代码来适应传输方式的变化。
这种对未来传输协议演进的考虑同样重要。目前,绝大多数 MCP
服务器主要暴露 tools
,它们本质上是简单的远程过程调用 (RPC
),可以通过无状态传输提供。但更复杂的“人在环路中” (human-in-the-loop
) 和 Agent
间交互场景,将需要 prompts
和 sampling
等 MCP
概念的支持。这些需要双向、实时通信的场景,如果没有双向传输层很难高效实现。届时,Cloudflare
平台、Agents SDK
和 Durable Objects
都原生支持 WebSockets
,能够提供全双工、双向的实时通信能力,为未来更高级的 MCP
应用奠定基础。
有状态、具备 Agent 特性的 MCP 服务器
在 Cloudflare
上构建 MCP
服务器时,每个 MCP
客户端会话都由一个 Durable Object
支持(通过 Agents SDK
)。这意味着每个会话都可以管理和持久化自己的状态,甚至可以拥有自己的 SQL
数据库。
这为构建有状态的 MCP
服务器打开了大门。MCP
服务器不再仅仅是客户端应用和外部 API
之间的无状态转换层,它们本身可以是有状态的应用——例如游戏、带购物车的结账流程、持久化知识图谱等。在 Cloudflare
上,MCP
服务器的潜力远不止于充当 REST API
的前端。
通过一个简单的计数器示例来理解其基本工作原理:
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
type State = { counter: number }
export class MyMCP extends McpAgent<Env, State, {}> {
server = new McpServer({
name: "Demo",
version: "1.0.0",
});
// 定义初始状态
initialState: State = {
counter: 1,
}
async init() {
// 定义一个资源,用于读取计数器当前值
this.server.resource(`counter`, `mcp://resource/counter`, (uri) => {
return {
contents: [{ uri: uri.href, text: String(this.state.counter) }],
}
})
// 定义一个工具,用于增加计数器的值
this.server.tool('add', '增加存储在 MCP 服务器中的计数器的值', { a: z.number() }, async ({ a }) => {
// 更新状态
this.setState({ ...this.state, counter: this.state.counter + a });
return {
content: [{ type: 'text', text: `增加了 ${a}, 当前总数是 ${this.state.counter}` }],
}
})
}
// 状态更新时的回调(可选)
onStateUpdate(state: State) {
console.log({ stateUpdate: state });
}
}
对于给定的会话,上述 MCP
服务器会在多次 tool
调用之间记住计数器的状态。
在 MCP
服务器内部,开发者可以利用 Cloudflare
完整的开发者平台能力,例如让 MCP
服务器启动浏览器进行网页浏览、触发 Workflow
、调用 AI
模型等。这预示着 MCP
生态系统将向更高级、更智能化的用例演进。
连接现有 MCP 客户端到远程服务器
Cloudflare
较早地支持了远程 MCP
,甚至在主流 MCP
客户端应用普遍支持远程、带认证的 MCP
之前。这为开发者提供了先行一步的机会。
但这也带来一个现实挑战:如果还没有支持远程 MCP
的客户端,开发者如何测试和让用户使用他们构建的远程 MCP
服务器?
Cloudflare
提供了两个新工具来应对:
Workers AI Playground
更新:该在线聊天界面现在是一个功能完整的远程MCP
客户端,支持连接到任何远程MCP
服务器,并内置了认证流程。开发者只需输入远程服务器的URL
(例如https://remote-server.example.com/sse
)并点击连接,即可立即测试,无需本地安装任何软件。点击连接后,用户将经历认证流程(如果设置了),之后便能直接在聊天界面中与
MCP
服务器的工具交互。mcp-remote
适配器:对于那些已经支持MCP
但尚未处理远程连接和认证的客户端(如Claude Desktop
或Cursor
),可以使用mcp-remote
。这是一个npm
包,充当本地客户端和远程服务器之间的桥梁。它让开发者和用户可以在他们熟悉的工具中预览与远程MCP
服务器的交互体验,而无需等待客户端本身更新支持。Cloudflare
提供了关于如何将mcp-remote
与Claude Desktop
,Cursor
,Windsurf
等流行MCP
客户端配合使用的指南。例如,在Claude Desktop
中,只需在配置文件中添加类似如下配置:{ "mcpServers": { "remote-example": { "command": "npx", "args": [ "mcp-remote", "https://remote-server.example.com/sse" // 替换为你的远程服务器 URL ] } } }
远程 MCP 的时代正在到来
远程模型上下文协议 (Remote MCP
) 无疑是 AI Agent
领域的一个重要发展方向。当客户端应用广泛支持远程 MCP
服务器时,其用户群体将从开发者扩展到更广泛的人群——他们甚至可能从未听说过 MCP
这个术语。
对于服务提供商而言,构建远程 MCP
服务器是将自身服务集成到数百万用户使用的 AI
助手和工具中的关键途径。许多大型互联网公司据称已在积极构建 MCP
服务器,同时,也让人期待那些以 Agent-first
、MCP-native
方式诞生的新兴业务。
基于 Cloudflare
提供的工具和平台,开发者现在就可以开始构建面向未来的远程 MCP
应用。这不仅是技术栈的一次升级,更是对 AI Agent
如何融入互联网服务的一次重要探索。随着生态系统的成熟,远程 MCP
有望催生出更加智能和个性化的用户体验。开发者可以查阅 Cloudflare 开发者文档 获取更多信息并开始实践。