1. 项目概述当AI指令遇上浏览器自动化最近在折腾一个老项目需要频繁地对一个Web应用进行回归测试。传统的自动化脚本写起来固然稳定但每次需求有细微变动比如某个按钮的CSS选择器变了或者新增了一个表单验证步骤我就得去翻代码、改定位器、重新调试一来二去时间成本不低。就在我琢磨着有没有更“智能”一点的方式时微软的MCPModel Context Protocol协议进入了我的视野特别是它结合AI指令来驱动浏览器自动化的玩法让我眼前一亮。简单来说这个项目的核心就是用自然语言告诉AI你想让浏览器做什么AI通过MCP协议理解你的意图并调用后端的Playwright等自动化工具来执行操作最后把结果反馈给你。整个过程你不需要写一行Selenium或Playwright的代码也不需要关心元素定位的细节就像跟一个懂技术的助手聊天一样“帮我在某某网站搜索一下‘Playwright教程’把第一个结果的标题和链接摘出来给我。” 它就能去办妥。这听起来是不是有点像“低代码”或“无代码”测试但它更进了一步是“自然语言驱动”的自动化。对于测试工程师、爬虫开发者或者任何需要与浏览器进行重复性交互的角色来说这极大地降低了技术门槛。你不需要是编程专家只要你能清晰地描述任务就能构建出可执行的自动化流程。当然它的价值远不止于简化操作。在快速原型验证、探索性测试、甚至是给非技术同事制作数据抓取小工具等场景下这种“聊天式”自动化都能发挥出惊人的效率。我花了些时间基于微软的MCP规范和一些开源工具搭建了一套可用的原型。实测下来虽然还不能完全替代所有精密控制的脚本但对于大量常见的、流程化的网页操作其便捷性已经足够让人兴奋。下面我就把自己从原理摸索到实战落地的全过程包括核心的MCP协议解读、服务端Server与客户端Client的搭建、AI指令的编写技巧以及踩过的那些坑毫无保留地分享出来。2. MCP协议核心打通AI与工具的“翻译官”要理解如何用AI指令驱动浏览器首先得弄明白MCP是什么。MCP全称Model Context Protocol你可以把它想象成AI模型比如Claude、GPT-4和外部工具比如浏览器自动化引擎、数据库、文件系统之间的一套标准“对话协议”和“接线手册”。在没有MCP之前我们想让AI操作浏览器通常有两种蹩脚的方式一是让AI生成一段Playwright或Selenium代码然后我们手动去执行这段代码二是需要开发一套非常定制化的、充满提示词工程的复杂中间层来“翻译”AI的意图。前者交互不流畅后者开发成本高且难以通用。MCP的出现就是为了标准化这个过程。它定义了一套清晰的“资源Resources”、“工具Tools”和“提示词模板Prompts”模型让工具提供者我们可以以一种标准化的方式向AI模型“宣告”“嗨我这里有这些能力工具你可以这样调用它们参数格式调用后会返回那样的结果响应格式。”2.1 MCP的三大核心组件资源Resources可以理解为AI模型可以读取的“只读数据源”。比如一个指向某个配置文件URI或者一个动态生成的日志流。在浏览器自动化场景下我们可以把一个“当前浏览器页面快照的HTML内容”或“控制台日志”作为一个资源暴露给AI让AI能“看到”页面状态。工具Tools这是核心中的核心。工具是AI模型可以调用的“函数”。每个工具都有明确的输入参数inputSchema和输出格式。例如我们可以定义一个名为navigate_to_url的工具它接受一个url字符串参数。当AI模型想让你打开某个网页时它就会按照MCP协议规定的JSON格式发起一个调用这个工具的请求。提示词模板Prompts这是一些预定义的、参数化的提示词片段。AI模型可以组合使用这些模板来引导用户或构建更复杂的查询。比如可以有一个“分析页面结构”的提示词模板AI在需要时可以直接调用它而不必每次都重新组织语言。对于我们的“AI驱动浏览器自动化”项目我们主要关注和利用的就是“工具Tools”这个组件。我们将Playwright的所有核心能力打开页面、点击、输入、截图、获取文本等封装成一个个MCP工具然后通过MCP服务器Server暴露出去。2.2 协议交互流程整个交互的流程可以概括为以下几步启动MCP服务器我们编写一个后台程序MCP Server这个程序内部集成了Playwright并按照MCP协议实现了上述“工具”的接口。服务器启动后会在一个本地端口如3000上监听。AI客户端连接支持MCP协议的AI应用如Claude Desktop、支持MCP的代码编辑器插件启动时会读取配置连接到我们启动的这个MCP服务器。这个过程称为“传输Transport”常用的是标准输入输出stdio或HTTP。能力宣告连接建立后服务器会主动向客户端发送一个清单说“我这里有这些工具可用click_elementtype_textget_text...”自然语言指令用户在AI客户端的界面中输入“去百度首页搜索‘天气预报’。”AI理解与工具调用AI模型如Claude理解用户的指令将其分解为一系列步骤。然后它根据已知的MCP工具清单决定调用navigate_to_url工具参数url“https://www.baidu.com”。调用请求按照MCP的JSON-RPC格式发送给服务器。服务器执行MCP服务器收到请求解析出要调用navigate_to_url工具和参数。服务器内部的Playwright实例执行page.goto(“https://www.baidu.com”)操作。结果返回Playwright执行成功页面加载完毕。服务器将执行结果可能包含成功状态、页面标题、最终URL等包装成MCP协议格式返回给AI客户端。AI继续决策AI收到“导航成功”的反馈后继续下一步决策“现在需要在搜索框输入文本”。于是它调用type_text工具参数可能是selector“#kw”, text“天气预报”如此循环直到完成用户的所有指令。最终回复所有步骤执行完毕后AI模型将各步骤的结果汇总用自然语言组织成一段回复给用户“已完成。已在百度首页搜索框输入‘天气预报’并已按下搜索键。当前页面第一条结果标题是‘XX市天气预报’。”通过这套协议AI模型不再是一个只会“空想”的语言模型它变成了一个可以实际操作数字世界的“智能体”。而我们开发者要做的就是为它提供足够多、足够好用的“工具手”。注意MCP协议本身是语言和模型无关的。这意味着你既可以用它服务Claude也可以服务GPT-4o或者其他任何兼容MCP的AI应用。服务器端的实现语言也可以自由选择官方提供了TypeScript/Python等SDK大大降低了开发门槛。3. 实战搭建从零构建你的MCP浏览器自动化服务器理论讲完了我们动手搭一个。我的技术栈选择是TypeScript Playwright 官方的modelcontextprotocol/sdk。选择TS/Node.js生态是因为Playwright对其支持极好且MCP的官方SDK用起来非常顺手。3.1 环境准备与项目初始化首先确保你的系统已经安装了Node.js建议18以上版本和npm。然后我们创建一个新的项目目录并初始化。mkdir mcp-browser-automation cd mcp-browser-automation npm init -y接下来安装核心依赖npm install modelcontextprotocol/sdk playwright npm install -D typescript tsx types/nodemodelcontextprotocol/sdk微软官方提供的MCP服务器SDK封装了协议细节让我们可以专注于工具的实现。playwright我们的浏览器自动化引擎。安装时会自动下载Chromium、Firefox和WebKit的浏览器二进制文件。typescript,tsx用于编写和运行TypeScript代码。初始化TypeScript配置npx tsc --init在生成的tsconfig.json中确保target是ES2022或更高module是commonjs或NodeNext并设置outDir为./dist。3.2 构建MCP服务器核心我们在项目根目录创建src/server.ts文件这是服务器的入口。首先导入必要的模块并初始化Playwright浏览器实例。这里有一个关键点为了在服务器生命周期内高效管理浏览器我们通常采用单例模式启动一个浏览器实例并创建一个独立的上下文Context和页面Page供所有工具调用。这比每次调用都启动新浏览器要快得多。import { Server } from modelcontextprotocol/sdk/server/index.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { chromium, Browser, Page } from playwright; class BrowserAutomationServer { private server: Server; private browser: Browser | null null; private page: Page | null null; constructor() { // 1. 创建MCP服务器实例 this.server new Server( { name: browser-automation-server, version: 1.0.0, }, { capabilities: { tools: {}, // 声明我们支持工具 }, } ); // 2. 注册工具 this.setupTools(); // 3. 设置连接关闭时的清理逻辑 this.server.onclose async () { console.error(Connection closed, cleaning up...); await this.cleanup(); }; } // 初始化浏览器和页面懒加载 private async ensurePage(): PromisePage { if (!this.browser) { this.browser await chromium.launch({ headless: true, // 默认无头模式调试时可设为false args: [--disable-blink-featuresAutomationControlled] // 绕过一些自动化检测 }); const context await this.browser.newContext({ viewport: { width: 1280, height: 720 }, userAgent: MCP-Browser-Automation/1.0 }); this.page await context.newPage(); } if (!this.page) { throw new Error(Page initialization failed); } return this.page; } // 清理资源 private async cleanup() { if (this.page) { await this.page.close(); this.page null; } if (this.browser) { await this.browser.close(); this.browser null; } } // 核心注册MCP工具 private setupTools() { // 工具1: 导航到指定URL this.server.setRequestHandler(tools/call, async (request) { const { name, arguments: args } request.params; const page await this.ensurePage(); try { switch (name) { case navigate: { const { url } args as { url: string }; const response await page.goto(url, { waitUntil: networkidle }); return { content: [ { type: text, text: 导航成功: ${url}\n状态: ${response?.status()}\n标题: ${await page.title()}, }, ], }; } case click: { const { selector } args as { selector: string }; // 等待元素可交互 await page.waitForSelector(selector, { state: visible }); await page.click(selector); return { content: [ { type: text, text: 已点击元素: ${selector}, }, ], }; } case type: { const { selector, text } args as { selector: string; text: string }; await page.waitForSelector(selector, { state: visible }); // 先清空再输入模拟用户行为 await page.fill(selector, ); await page.type(selector, text, { delay: 50 }); // 加入延迟更拟人 return { content: [ { type: text, text: 已在 ${selector} 输入文本: ${text}, }, ], }; } case get_text: { const { selector } args as { selector: string }; await page.waitForSelector(selector, { state: visible }); const text await page.textContent(selector); return { content: [ { type: text, text: 元素 ${selector} 的文本内容为: ${text || (空)}, }, ], }; } case screenshot: { const { path } args as { path?: string }; const screenshotPath path || screenshot_${Date.now()}.png; const buffer await page.screenshot({ path: screenshotPath, fullPage: false }); return { content: [ { type: text, text: 截图已保存至: ${screenshotPath}, }, // MCP协议支持返回图片等多媒体内容这里我们简单返回路径 ], }; } case evaluate: { // 这是一个更强大的工具允许执行任意JavaScript代码片段 const { script } args as { script: string }; const result await page.evaluate(script); return { content: [ { type: text, text: 执行脚本结果: ${JSON.stringify(result, null, 2)}, }, ], }; } default: throw new Error(未知工具: ${name}); } } catch (error: any) { // 错误处理非常重要需要将错误信息清晰地返回给AI return { content: [ { type: text, text: 工具执行失败 (${name}): ${error.message}\n堆栈: ${error.stack}, }, ], isError: true, }; } }); } // 启动服务器使用Stdio传输这是与Claude Desktop等客户端通信的常用方式 async run() { const transport new StdioServerTransport(); await this.server.connect(transport); console.error(MCP Browser Automation Server is running on stdio...); } } // 启动服务器 const server new BrowserAutomationServer(); server.run().catch(console.error);这段代码构建了一个功能完整的MCP服务器核心。它提供了6个基础工具导航、点击、输入、获取文本、截图和评估脚本。ensurePage方法确保了浏览器实例的单一和高效复用。3.3 配置AI客户端以Claude Desktop为例服务器写好了我们需要一个AI客户端来连接它。Claude Desktop是当前对MCP支持最友好的客户端之一。编译并运行服务器首先我们需要将TypeScript编译成JavaScript并运行。在package.json中添加脚本scripts: { build: tsc, start: node dist/server.js }运行npm run build npm start。服务器会在后台通过stdio运行。配置Claude Desktop找到Claude Desktop的配置文件位置。macOS:~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.json编辑配置文件在配置文件中添加你的MCP服务器配置。关键是要指定服务器的启动命令。{ mcpServers: { browser-automation: { command: node, args: [/你的绝对项目路径/dist/server.js], env: { NODE_ENV: production } } } }重要提示args中的路径必须是绝对路径。相对路径在Claude Desktop的上下文中可能无法正确解析。这是第一个容易踩的坑。重启Claude Desktop保存配置文件后完全退出并重启Claude Desktop。验证连接重启后在Claude的输入框里你可以尝试输入一些指令比如“你能用浏览器做什么”或者“列出可用的工具”。如果配置成功Claude应该能识别出MCP服务器提供的工具并告诉你它现在可以通过浏览器进行导航、点击等操作。4. 编写高效AI指令从“能听懂”到“干得好”服务器搭好了客户端也连上了但你会发现一开始的指令可能并不总是那么顺利。AI可能会误解你的意图或者选择效率不高的工具组合。要让“聊天式自动化”真正流畅我们需要在指令编写上下点功夫。这本质上是在做“提示词工程”但目标是与我们定义的MCP工具协同工作。4.1 指令编写的基本原则原子化与清晰化尽量让每个指令只完成一个明确的、原子的任务。比如“去百度搜索MCP点开第一个结果”这个指令包含了导航、输入、点击三个步骤。对于复杂AI它可以分解但有时它可能会困惑。更好的方式是分步“第一步导航到 https://www.baidu.com”“第二步在搜索框id是kw输入‘MCP协议’”“第三步点击搜索按钮id是su”“第四步等待结果加载然后获取第一个搜索结果的标题和链接” 分步指令虽然看起来啰嗦但在初期调试和复杂任务中成功率更高。熟练后可以尝试更复合的指令。提供上下文与选择器提示AI不是浏览器开发者工具它不知道页面上哪个元素是搜索框。虽然高级的AI模型可以通过“资源”获取页面DOM进行分析但在基础工具集下我们需要在指令中提供线索。差的指令“点击登录按钮。”好的指令“点击页面上文字是‘登录’或‘Sign In’的按钮。”更好的指令“使用click工具选择器可以是button:has-text(‘登录’)或者a:has-text(‘Sign In’)。” 你可以直接使用Playwright支持的选择器语法如text登录#submit-btn.primary-button来指导AI。AI在调用工具时会将这些选择器直接作为参数传入。明确等待与状态确认网络有延迟页面加载需要时间。指令中应包含等待或确认状态的逻辑。“导航到X页面等待页面加载完成网络空闲。”“输入密码后等待页面跳转或出现‘登录成功’的提示元素再执行下一步。” 你可以通过evaluate工具让AI执行一段JavaScript来检查页面状态例如检查 document.readyState 是否为 ‘complete’或者检查某个特定元素是否存在。4.2 高级技巧利用“提示词模板”和“资源”我们之前在MCP协议中提到了“提示词模板Prompts”和“资源Resources”。在更高级的用法中我们可以利用它们来极大提升AI的决策能力。创建“分析页面”提示词模板在MCP服务器中我们可以注册一个名为analyze_page_structure的提示词模板。当AI需要理解一个陌生页面时它可以调用这个模板。模板的内容可以是“请分析当前页面的主要结构。找出所有表单输入框、按钮、链接并推测它们的功能。用JSON格式返回包含元素的选择器建议和用途描述。” 然后AI可以结合get_page_html一个暴露页面HTML内容的资源工具的结果来生成分析报告为后续的自动化操作提供精准的选择器建议。暴露“当前页面截图”作为资源对于一些难以用文本描述的验证如验证码、图形状态我们可以定义一个资源其URI指向当前页面的截图Base64编码或临时文件路径。AI模型可以“读取”这个资源结合其视觉能力如果模型具备来分析页面做出更准确的判断。实现这些高级功能需要更深入地定制MCP服务器但它们是让自动化从“机械执行”走向“智能适应”的关键。例如你可以实现一个工具让AI先调用“分析页面”模板根据返回的JSON自动生成下一步的操作序列从而实现一定程度的“自我规划”。4.3 一个完整的实战指令示例假设我们要自动化一个简单的场景“去GitHub Trending页面获取今天排名前3的TypeScript仓库的名字和星数。”我们可以给AI这样一段指令请执行以下浏览器自动化任务分步进行 1. 使用 navigate 工具打开网址https://github.com/trending/typescript?sincedaily 2. 等待页面加载完成网络空闲状态。 3. 使用 evaluate 工具执行以下JavaScript代码来提取数据 (请将以下代码作为script参数传入) const repos []; const items document.querySelectorAll(article.Box-row); for (let i 0; i Math.min(3, items.length); i) { const item items[i]; const titleElem item.querySelector(h2 a); const starElem item.querySelector(a[href$/stargazers]); const name titleElem?.textContent?.trim().replace(/\s/g, ) || N/A; const stars starElem?.textContent?.trim() || N/A; repos.push({ rank: i1, name, stars }); } return repos; 4. 将 evaluate 工具返回的结果用清晰易读的格式总结告诉我。AI在接收到这个指令后会逐步调用对应的工具。第一步调用navigate第二步它可能会内部等待或直接进行第三步第三步调用evaluate并传入我们的JS代码最后将执行结果组织成一段话回复给我们。整个过程我们只需要用自然语言描述任务和提供关键的选择器或代码片段而不需要自己编写完整的Playwright脚本。5. 避坑指南与效能优化在实际搭建和使用的过程中我遇到了不少问题也总结出一些提升稳定性和效率的经验。5.1 常见问题与解决方案问题现象可能原因解决方案Claude Desktop 提示“无法连接MCP服务器”或毫无反应1. 配置文件路径错误。2.command或args中的路径不是绝对路径。3. Node.js环境问题。4. 服务器脚本有语法错误启动即崩溃。1. 确认配置文件位置和名称正确。2.务必使用绝对路径。可以用pwd(Linux/macOS) 或cd(Windows) 命令获取。3. 在终端直接运行node /path/to/server.js看是否能正常启动并等待输入。4. 检查服务器代码使用try-catch包裹初始化逻辑并确保在console.error输出日志以便在Claude Desktop的日志中查看。AI执行点击或输入失败1. 元素选择器不准或页面未加载完成。2. 元素在iframe内。3. 网站有反自动化检测。1. 在指令中明确加入等待条件如waitForSelector。在服务器工具实现中像我们示例代码那样内置等待是好的实践。2. 需要先使用Playwright的page.frameLocator()切换到iframe上下文。这需要专门定义一个switch_to_frame工具。3. 启动浏览器时添加args: [--disable-blink-featuresAutomationControlled]并在newContext时设置合理的userAgent。对于更复杂的检测可能需要使用playwright-stealth等插件。执行速度慢感觉卡顿1. 每次工具调用都启动新浏览器。2. 网络延迟或页面资源过多。3. AI模型思考时间过长。1.务必使用浏览器/页面单例模式如我们示例中的ensurePage方法。2. 在page.goto中使用waitUntil: domcontentloaded而非networkidle如果不需要所有资源加载完毕。在工具中合理设置超时时间。3. 这取决于AI模型本身。可以尝试将复杂任务拆解成多个独立指令分别发送。evaluate工具返回undefined或错误1. 页面上下文错误如在iframe内执行。2. JavaScript代码本身有错误。3. 选择器在页面中不存在。1. 确保执行evaluate前页面上下文正确。可以通过page.mainFrame()确保在主框架。2. 先在浏览器控制台测试JS代码片段。在服务器端用try-catch包裹page.evaluate调用返回错误信息。3. 在evaluate前先用waitForSelector确保目标元素存在。5.2 效能优化与进阶思路工具设计的粒度工具不是越细越好也不是越粗越好。click和type是细粒度工具login_to_site包含导航、输入用户名密码、点击登录则是粗粒度工具。对于高度重复的固定流程定义粗粒度工具可以提高AI的决策效率和指令的简洁性。我的建议是先实现一组覆盖Playwright核心API的细粒度工具作为基础再根据你的高频业务场景封装几个粗粒度的“组合工具”。状态管理浏览器页面是有状态的登录态、弹窗状态、标签页等。简单的单页面单例模式可能不够。可以考虑在MCP服务器内维护一个简单的会话Session机制每个会话对应一个独立的浏览器上下文和页面并通过一个会话ID来关联。这样可以在同一个服务器实例中处理多个独立的自动化任务。错误恢复与重试网络不稳定、元素偶尔加载慢是常态。在服务器端工具实现中加入智能重试逻辑非常重要。例如对于click工具如果因为元素被遮挡或短暂不可点击而失败可以等待一小段时间后重试一两次。结果格式化与反馈AI模型依赖清晰的反馈来做后续决策。工具返回的结果应该结构化、信息丰富。例如get_text工具不应只返回文本字符串可以返回一个包含选择器、文本内容、是否成功等字段的JSON对象。这能帮助AI更好地理解执行上下文。安全边界开放浏览器自动化能力存在风险。务必在服务器端设置安全边界例如限制可访问的域名白名单、禁止执行某些危险的JS代码如while(true)循环、设置总的任务执行超时时间等。切勿将未加限制的MCP服务器暴露在公网。6. 超越测试MCP浏览器自动化的应用场景展望通过上面的实战我们已经看到了“AI指令浏览器自动化”在软件测试领域的潜力。但它能做的远不止于此。这种将自然语言意图直接转化为数字行动的能力为许多场景打开了新的大门。1. 数据采集与市场调研对于产品经理或市场人员不再需要学习复杂的爬虫或恳求工程师帮忙。他们可以直接对AI说“帮我监控这三个竞争对手官网的价格页面如果价格有变动把新旧价格和变动日期整理成表格发给我。” MCP服务器可以定期执行这些任务并将结果通过资源的形式暴露出来甚至触发通知。2. 内部工作流自动化许多企业内部系统OA、CRM、ERP没有提供完善的API或者API调用复杂。员工经常需要手动重复一些数据录入、报表导出的操作。现在可以构建一个专用的MCP服务器将对这些内部系统的常见操作封装成工具。员工只需用自然语言描述任务AI就能驱动浏览器去完成比如“把上周所有‘已关闭’的客户支持工单导出为Excel文件并邮件发送给经理。”3. 个人效率助手这可能是最贴近普通用户的场景。想象一下你可以告诉你的AI助手“帮我预约下周四下午牙医诊所最早的空档。” 助手通过MCP调用浏览器工具自动打开诊所的预约网站登录你的账户密码通过安全方式管理查询时间表并完成预约。或者“把我收藏夹里所有未读的技术文章批量保存到Notion数据库里。”4. 无障碍辅助对于行动不便或视力障碍的用户精确操作图形界面非常困难。通过语音输入自然语言指令由AI解析后驱动浏览器完成复杂的网页操作如在线购物、办理业务可以极大地提升他们的数字生活体验。5. 教育与培训创建交互式的软件操作教程。学员不需要在真实环境中操作而是通过向AI描述步骤来驱动一个模拟的浏览器环境完成练习。AI可以即时判断操作是否正确并给出指导。当然当前的方案仍处于早期阶段。它的稳定性严重依赖AI模型对指令的理解精度和工具调用的可靠性。对于需要像素级精确操作、极端稳定性或处理复杂验证如高级验证码的场景传统的脚本自动化仍是更优选择。但毋庸置疑MCP协议为我们指明了一个方向一个更自然、更普惠的人机交互未来正在通过“对话”和“工具”的结合逐渐成为现实。我的体会是这不仅仅是技术的叠加更是一种思维方式的转变——从“教会机器每一步”到“告诉机器我想要什么”。