1. 为什么要在 Workers 上跑 Playwright MCP
Cloudflare Workers 上跑 Playwright MCP,本质是把「浏览器自动化」这件事从你本地机器搬到 Cloudflare 的边缘节点上。它依托的是 Cloudflare Browser Rendering 服务,由 Workers 负责接收 MCP 协议请求,再把导航、点击、输入、截图这些动作转发给远端浏览器实例执行。你不需要在本地装 Chromium,也不用维护一台常驻的自动化服务器,一个wrangler deploy就能得到一个带 SSE 端点的远程浏览器操作入口。
它适合谁?如果你在做 AI Agent 的网页操作能力、需要让模型远程打开页面抓动态内容、跑端到端 UI 测试,或者想给 Claude Desktop、Cursor、VS Code 这类客户端挂一个「能上网点按钮」的工具,这套组合就很合适。MCP 协议负责把工具描述暴露给模型,Playwright 负责真实操作,Browser Rendering 负责在云端把浏览器跑起来,三者拼在一起就是一条完整的远程自动化链路。
这篇按「能跟做」的标准来写:先给wrangler.toml和 MCP 服务入口的可复制骨架,再讲怎么把模型调用通道统一到 TaoToken 的 Key/API 上,最后做一次端到端调用验证,并把几个高频报错拆开讲清楚。全程命令和配置都能直接抄。
2. 前置准备:账号、依赖与 TaoToken 通道
动手前先把三样东西备齐:一个 Cloudflare 账号(Browser Rendering 要在后台开通)、Node.js 16 以上加 npm/pnpm、以及 Wrangler CLI。Wrangler 是 Cloudflare 的部署工具,装完登录一次即可。
npm install -g wrangler wrangler login登录会拉起浏览器授权,成功后本地就存了凭证,后面wrangler deploy不用再输账号。
第二样是模型侧的调用通道。MCP 服务本身只负责浏览器操作,但你在调试 Agent 或让模型决定「下一步点哪里」时,需要一个稳定的模型 API 入口。我习惯把这类调用统一走 TaoToken:一个 Key 覆盖多种模型,接口格式兼容主流 SDK,省得在多个平台之间来回切配置。它的 API 地址是https://taotoken.net/api,控制台里可以创建和管理 Key。
# 把 Key 写进环境变量,避免硬编码进代码 export TAOTOKEN_API_KEY="sk-你的key"注意:Key 只放在服务端环境变量或 Cloudflare 的 Secret 里,不要提交到 Git,也不要在前端代码里出现。
第三样是确认 Browser Rendering 已在 Cloudflare 后台开通。没开通的话,部署能成功,但第一次调用浏览器工具时会报权限或绑定相关的错误,这个在第 5 节会具体讲。
3. 可复制骨架:wrangler.toml 与 MCP 入口
先建项目目录,结构大致是cloudflare/放 Worker 代码,cloudflare/example/放部署配置。核心是wrangler.toml,它决定了 Worker 的名字、入口文件,以及最关键的 Browser Rendering 绑定。
# cloudflare/example/wrangler.toml name = "playwright-mcp" main = "../src/index.ts" compatibility_date = "2024-11-01" compatibility_flags = ["nodejs_compat"] # Browser Rendering 绑定,名字要和代码里读取的一致 [browser] binding = "BROWSER" # 可选:把模型 Key 作为 Secret 注入,不要写明文 [vars] MCP_ENDPOINT = "/sse"[browser]这一段是重点。binding = "BROWSER"声明了一个名为BROWSER的绑定,Worker 代码里通过env.BROWSER拿到它,再交给 Playwright 去启动远端浏览器。nodejs_compat这个 flag 建议加上,Playwright 的部分依赖在 Workers 运行时里需要它。
接着是 MCP 服务入口。MCP over SSE 的模型是:客户端先连/sse建立事件流,服务端通过这条流推送消息,客户端再往/message发请求。下面是一个精简但可运行的入口骨架。
// cloudflare/src/index.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; export default { async fetch(request: Request, env: Env): Promise<Response> { const url = new URL(request.url); // SSE 连接入口 if (url.pathname === "/sse") { const server = new McpServer({ name: "playwright-mcp", version: "1.0.0" }); // 注册浏览器工具,这里以导航和快照为例 server.tool("browser_navigate", { url: { type: "string" } }, async ({ url }) => { const browser = await env.BROWSER.launch(); const page = await browser.newPage(); await page.goto(url); const snapshot = await page.accessibility.snapshot(); await browser.close(); return { content: [{ type: "text", text: JSON.stringify(snapshot) }] }; }); const transport = new SSEServerTransport("/message", server); await server.connect(transport); return transport.response; } // 客户端消息回传入口 if (url.pathname === "/message") { return new Response("ok"); } return new Response("Not Found", { status: 404 }); }, };这段骨架做了两件事:/sse建立事件流并注册工具,/message接收客户端请求。真实项目里工具会更多,browser_click、browser_type、browser_take_screenshot都按同样的模式注册,参数结构参考 MCP 工具定义即可。env.BROWSER.launch()就是 Browser Rendering 的入口,它返回一个远端浏览器实例,后面的newPage、goto都是标准 Playwright 写法。
构建和部署:
cd cloudflare npm ci npm run build cd example npm ci npx wrangler deploy部署成功后会输出一个https://playwright-mcp.<你的子域>.workers.dev地址,SSE 端点就是它加上/sse。
4. 接入 TaoToken 与端到端验证
服务跑起来后,先验证浏览器工具本身能不能用,再验证模型调用通道。浏览器侧可以直接用 curl 探一下 SSE 端点是否活着:
curl -N https://playwright-mcp.<你的子域>.workers.dev/sse如果连接保持不断、能看到事件流输出,说明 Worker 和 Browser Rendering 绑定正常。接着把客户端接上。以 Claude Desktop 为例,它目前只支持本地 MCP 服务器,所以要用mcp-remote做一层代理:
{ "mcpServers": { "cloudflare-playwright-mcp": { "command": "npx", "args": [ "mcp-remote", "https://playwright-mcp.<你的子域>.workers.dev/sse" ] } } }VS Code 则可以直接加:
code --add-mcp '{"name":"cloudflare-playwright","type":"sse","url":"https://playwright-mcp.<你的子域>.workers.dev/sse"}'客户端连上后,模型侧要能正常决策「下一步做什么」,这里就轮到 TaoToken 的通道出场。把模型请求指向https://taotoken.net/api,用同一个 Key 调用:
curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-3-5-sonnet", "messages": [ {"role": "user", "content": "打开 demo.playwright.dev/todomvc 并截图"} ] }'一次完整的端到端验证动作是这样:模型收到指令后,通过 MCP 调用browser_navigate打开页面,再调用browser_take_screenshot截图,结果通过 SSE 回传。你可以在对话里发一句「Go to demo.playwright.dev/todomvc」,正常的话会看到工具被触发、页面被导航、返回页面标题。再发「Take a screenshot」,应返回一张 PNG 或 JPEG 的截图结果。这两步走通,说明 Worker、Browser Rendering、MCP 协议、模型通道四段链路全部打通。
5. 本篇常见报错排查
报错一:Browser binding not found或env.BROWSER is undefined。九成是wrangler.toml里没写[browser]段,或者binding名字和代码里读的不一致。检查两处拼写是否完全对应,改完重新wrangler deploy。
报错二:Browser Rendering is not enabled。这是账号侧没开通服务。去 Cloudflare 后台确认 Browser Rendering 已启用,免费额度有限,超出会计费,调试阶段注意调用频率。
报错三:browser_install相关错误,提示浏览器未安装。远端实例首次使用时可能需要显式安装浏览器。在工具调用里先触发一次browser_install,或者确认你的 Worker 代码在launch()时传了正确的浏览器类型参数。
报错四:SSE 连上但工具列表为空。通常是/message路由没实现或返回了错误状态。客户端发消息走的是/message,这个端点必须能正确接收并转发给对应的 transport 实例,否则工具注册了也调不到。
报错五:Cursor 里截图不显示。Cursor 默认禁用内联图像响应。需要在创建 MCP 代理时设置imageResponses: 'allow',否则截图工具返回了数据但客户端不渲染。
报错六:模型侧 401 或鉴权失败。检查 TaoToken 的 Key 是否写进了环境变量、请求头Authorization格式是否为Bearer <key>。Key 泄露或过期都会导致这个错误,去控制台重新生成即可。
6. 把通道固定下来,后续少折腾
跑通之后,建议把两件事固定成习惯。一是模型调用统一走 TaoToken 的 API 通道,Key 只存服务端 Secret,换模型时只改model字段,不用动接入代码;二是浏览器工具的注册按需裁剪,Snapshot Mode 用可访问性快照,性能和稳定性都更好,Vision Mode 留给需要坐标定位的计算机使用模型场景。
需要长期跑编码或 Agent 任务的话,可以在控制台里把用量和额度看清楚,避免调试期把免费额度打满。接入文档里有各客户端的完整配置示例,排障时对着看比盲猜快得多。