README
🚀 React Native Web的MCP浏览器服务器
这是一个专门为 React Native Web 应用程序设计的模型上下文协议(MCP)浏览器自动化服务器。它支持多标签页、具备截图功能,并且能保持持久的浏览器会话。
🚀 快速开始
React Native Web 使用手势响应系统,监听 mousedown/mouseup 事件,而非标准的 click 事件,这导致像 Playwright 的 locator.click() 这类标准浏览器自动化工具无法正常工作。而本 MCP 服务器使用 Playwright 的底层 page.mouse API 进行 基于坐标的点击,能够正确触发 React Native Web 组件监听的鼠标事件。
✨ 主要特性
- 基于坐标的点击:使用
page.mouse.down()/page.mouse.up()替代合成点击。 - 多种元素查找策略:支持 CSS 选择器、文本内容、testID 或精确坐标查找元素。
- 自定义页面快照:显示带有位置信息的交互式元素(不依赖可访问性树)。
- 截图支持:返回 AI 代理可查看的 base64 编码的 PNG 图像。
- 多标签管理:可创建、切换和关闭浏览器标签页。
- 持久会话:浏览器在工具调用之间保持打开状态,实现持续交互。
- 全浏览器控制:支持导航、输入、滚动、按键和执行 JavaScript 代码。
📦 安装指南
从 npm 安装
npm install @nizarius/mcp-rnw-browser
npx playwright install chromium
从源代码安装
git clone https://github.com/nizarius/mcp-rnw-browser.git
cd mcp-rnw-browser
npm install
npm run build
npx playwright install chromium
📚 详细文档
为 Cursor 进行配置
将以下内容添加到你的 Cursor MCP 设置(~/.cursor/mcp.json 或 Cursor 设置 > MCP)中:
使用 npm 包(推荐)
{
"mcpServers": {
"rnw-browser": {
"command": "npx",
"args": ["@nizarius/mcp-rnw-browser"]
}
}
}
使用本地安装
{
"mcpServers": {
"rnw-browser": {
"command": "node",
"args": ["/path/to/mcp-rnw-browser/dist/index.js"]
}
}
}
可用工具
导航
rnw_navigate
导航到指定 URL。若不存在浏览器会话,则会创建一个。
{ "url": "http://localhost:8081" }
返回值:包含所有交互式元素的页面快照。
截图与快照
rnw_snapshot
获取页面上交互式元素及其位置的文本快照。返回元素标签、文本内容、testID、角色、位置和点击中心坐标。
// 无需参数
{}
返回值:包含所有交互式元素及其位置的文本列表。
rnw_screenshot
进行截图并返回 base64 编码的 PNG 图像。
// 视口截图(默认)
{}
// 全页截图(捕获整个可滚动区域)
{ "fullPage": true }
// 元素截图(捕获特定元素)
{ "selector": "#my-component" }
返回值:AI 代理可直接查看的 base64 编码的 PNG 图像。
交互
rnw_click
使用与 React Native Web 兼容的鼠标事件(mousedown/mouseup)点击元素。
// 通过 CSS 选择器
{ "selector": "button.submit", "findBy": "css" }
// 通过文本内容(部分匹配)
{ "selector": "Sign In", "findBy": "text" }
// 通过 testID(data-testid 属性)
{ "selector": "login-button", "findBy": "testid" }
// 通过精确坐标(元素检测失败时有用)
{ "x": 500, "y": 300, "findBy": "coordinates" }
返回值:点击坐标和更新后的页面快照。
rnw_type
在聚焦元素中输入文本,或先查找元素再输入文本。
// 在当前聚焦元素中输入
{ "text": "Hello World" }
// 先查找元素,然后输入(点击以聚焦)
{ "text": "Hello World", "selector": "input", "findBy": "css" }
// 输入并按下 Enter 键(例如,用于搜索/提交)
{ "text": "Hello World", "selector": "input", "findBy": "css", "pressEnter": true }
返回值:输入文本的确认信息。
rnw_scroll
滚动页面或特定的可滚动元素。
// 页面向下滚动 300 像素
{ "direction": "down", "amount": 300 }
// 页面向上滚动
{ "direction": "up", "amount": 500 }
// 在特定容器内滚动
{ "direction": "down", "amount": 200, "selector": ".scroll-container" }
参数:direction(上/下/左/右),amount(像素,默认值:300),selector(可选)。
返回值:更新后的页面快照。
rnw_wait
等待指定时间或直到元素出现在页面上。
// 等待 1 秒(1000 毫秒)
{ "time": 1000 }
// 等待元素出现(超时时间 5 秒)
{ "selector": "button.loaded", "findBy": "css" }
// 等待文本出现
{ "selector": "Loading complete", "findBy": "text" }
返回值:等待完成的确认信息,若超时则返回错误信息。
rnw_press_key
按下键盘按键。适用于导航、表单提交或触发快捷键。
// 按下 Enter 键
{ "key": "Enter" }
// 按下 Escape 键
{ "key": "Escape" }
// 按下箭头键
{ "key": "ArrowDown" }
// 按下 Tab 键移动焦点
{ "key": "Tab" }
常用按键:Enter、Escape、Tab、ArrowUp、ArrowDown、ArrowLeft、ArrowRight、Backspace、Delete、Space。
返回值:按键按下的确认信息。
rnw_evaluate
在浏览器上下文中执行 JavaScript 代码。适用于调试、读取状态或执行自定义交互。
// 获取页面标题
{ "script": "document.title" }
// 获取当前 URL
{ "script": "window.location.href" }
// 读取 localStorage 值
{ "script": "localStorage.getItem('authToken')" }
// 获取元素数量
{ "script": "document.querySelectorAll('button').length" }
// 触发自定义操作
{ "script": "window.scrollTo(0, document.body.scrollHeight)" }
返回值:脚本执行结果的 JSON 字符串化内容。
标签管理
rnw_tabs_list
列出所有打开的浏览器标签页,显示其索引、标题和 URL。
// 无需参数
{}
返回值:包含所有标签页的索引、活动状态、标题和 URL 的列表。
rnw_tabs_new
创建一个新的浏览器标签页,并可选择导航到指定 URL。新标签页将成为活动标签页。
// 创建空的新标签页(about:blank)
{}
// 创建新标签页并导航到 URL
{ "url": "http://localhost:8081/settings" }
返回值:新标签页的索引和页面快照。
rnw_tabs_select
通过索引(从 0 开始)切换到特定标签页。可使用 rnw_tabs_list 查看可用标签页。
// 切换到第二个标签页
{ "index": 1 }
// 切换到第一个标签页
{ "index": 0 }
返回值:所选标签页的页面快照。
rnw_tabs_close
关闭浏览器标签页。若关闭的是活动标签页,则切换到最近的剩余标签页。
// 关闭当前活动标签页
{}
// 通过索引关闭特定标签页
{ "index": 2 }
返回值:关闭确认信息和新活动标签页的快照。
会话管理
rnw_session_status
获取当前浏览器会话状态。在执行操作前检查会话是否活跃很有用。
// 无需参数
{}
返回值:
isRunning:浏览器是否处于活动状态tabCount:打开的标签页数量currentTabIndex:活动标签页的索引currentUrl:活动标签页的 URLviewport:浏览器窗口尺寸(宽度 x 高度)
rnw_close
关闭浏览器并结束会话。所有标签页将关闭,资源将被释放。
// 无需参数
{}
返回值:浏览器会话已结束的确认信息。
工作原理
标准 Playwright 点击(不适用于 RNW)
// 这会分发一个合成的 'click' 事件,RNW 会忽略该事件
await element.click();
本 MCP 服务器的点击(适用于 RNW)
// 这会触发 RNW 会响应的真实 mousedown/mouseup 事件
await page.mouse.move(x, y);
await page.mouse.down();
await page.mouse.up();
与 AI 代理的使用示例
代理:我要导航到你的 React Native Web 应用,进行截图,并点击登录按钮。
> rnw_navigate { "url": "http://localhost:8081" }
页面已加载。我可以看到以下交互式元素:
[0] button testid="login-button"
文本:"Sign In"
中心坐标:(640, 400)
> rnw_screenshot {}
[返回页面的 PNG 图像]
> rnw_click { "selector": "login-button", "findBy": "testid" }
在 (640, 400) 处点击。登录表单现在可见。
> rnw_tabs_new { "url": "http://localhost:8081/settings" }
创建了新标签页 [1] 并导航到设置页面。
> rnw_tabs_list {}
打开的标签页(2 个):
[0] 主页 - http://localhost:8081/
[1](活动)设置 - http://localhost:8081/settings
持续会话工作流程
浏览器会话在工具调用之间保持持久,支持以下操作:
- 多步骤交互:导航、截图、交互、再次截图。
- 视觉验证:通过截图验证操作后的 UI 状态。
- 多页面工作流程:打开多个标签页以进行复杂的测试场景。
- 调试:使用
rnw_evaluate检查页面状态。
代理:我将测试多步骤表单提交。
> rnw_navigate { "url": "http://localhost:8081/form" }
> rnw_screenshot {} // 验证初始状态
> rnw_type { "text": "John Doe", "selector": "[data-testid='name-input']", "findBy": "css" }
> rnw_screenshot {} // 验证输入的文本
> rnw_click { "selector": "Submit", "findBy": "text" }
> rnw_screenshot {} // 验证提交结果
> rnw_close {} // 完成后结束会话
故障排除
元素未找到
- 确保你的 React Native Web 组件设置了
testID属性。 - 使用
rnw_snapshot查看可用元素。 - 尝试使用
findBy: "text"通过文本内容查找元素。
点击未注册
- 确保元素可见且未被其他元素覆盖。
- 尝试在点击前使用
rnw_wait增加延迟。 - 若元素查找失败,可直接使用坐标。
截图无法工作
- 确保浏览器会话处于活动状态(
rnw_session_status)。 - 对于元素截图,验证选择器是否匹配可见元素。
版本历史
v2.0.0
- 增加了支持返回 base64 图像的截图功能。
- 增加了多标签管理功能(列出、新建、选择、关闭)。
- 增加了会话状态工具。
- 改进了工具响应格式。
- 支持持久的浏览器会话。
v1.0.0
- 初始版本,支持与 RNW 兼容的点击功能。
- 具备基本的导航、快照和交互工具。
📄 许可证
本项目采用 MIT 许可证。
Scan to join WeChat group