关于 Electron Driver
Electron Driver 是一个基于 Playwright 的 MCP 服务,让 AI Agent 操作已构建的 Electron 应用,适用于应用测试、调试和无障碍检查。它提供交互、状态读取、多窗口控制,以及在渲染进程和主进程中执行 JavaScript 的工具。
主要功能
- 01启动和关闭 Electron 应用
- 02点击、输入、拖动及滚动
- 03截图并读取控制台日志
- 04检查 DOM、ARIA 树和元素状态
- 05列出及切换应用窗口
- 06在渲染进程或主进程执行 JavaScript
适用场景
- 01验证新实现的应用功能
- 02进行视觉回归测试
- 03通过 ARIA 树开展无障碍检查
- 04复现描述中的界面问题
MCP 相关
该 MCP 服务向兼容 MCP 的 Agent 主机提供 38 个 Electron 应用操作与检查工具。README 提及可接入 Claude Code、Claude Desktop、Cursor 等主机。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
electron-driver
通过 AI Agent 驱动 Electron 应用。 点击、输入、拖动、截屏,在渲染进程或主进程中执行 JavaScript,读取控制台日志,处理多窗口应用,捕获无障碍快照——所有操作都通过一个 MCP(Model Context Protocol)服务完成,该服务可接入 Claude Code、Claude Desktop、Cursor 以及其他兼容 MCP 的 Agent 宿主。
https://github.com/user-attachments/assets/a95500d2-28d2-4ee1-9965-8f7e1ef54caa
基于 Playwright 的实验性 _electron API 构建。适用于任何 Electron 应用——React、Vue、Svelte 或原生应用——只要能指定其编译后的主进程入口即可。
状态: v0.3.0。首次公开发布。包含 38 个工具,覆盖实际工作流。
为什么要开发它
AI Agent 能够推理桌面应用应该如何运行,但无法独立查看或与应用交互。Web 浏览器有大量 Agent 自动化方案,而 Electron 几乎没有。本包填补了这一空白:向 Agent 提供编译后的 Electron 应用路径,它就能像人一样驱动应用。
常见用例:
- Agent 通过实际运行应用并检查可见结果,验证刚刚实现的功能
- 重构过程中的视觉回归测试
- 通过 ARIA 树快照进行无障碍审计
- 根据自然语言描述复现 Bug
- 指导子 Agent 反复调整 UI,直到通过规范检查
安装
需要 Node 18+,并且已有构建好的 Electron 应用。
npm install electron-driver
无需单独安装 Playwright 浏览器——_electron 会直接驱动 Electron 二进制文件。
在 Agent 宿主中注册
Claude Code(项目范围)
在仓库根目录创建 .mcp.json:
{
"mcpServers": {
"electron-driver": {
"command": "npx",
"args": ["electron-driver"]
}
}
}
Claude Code(用户范围——适用于每个项目)
claude mcp add electron-driver --scope user -- npx electron-driver
Claude Desktop / Cursor / 其他
在宿主的 MCP 配置中添加条目,指向 npx electron-driver 或 node_modules/electron-driver/index.mjs 的绝对路径。
核心理念
服务一次只管理 一个 Electron 会话。start_app 启动应用,其他所有工具都与其交互,stop_app 则关闭应用。截屏会保存到会话目录中;每次调用 start_app 时都会清空该目录,避免文件堆积或残留过时内容。会话期间,所有工具调用都会记录到 <project>/.electron-driver/driver.log。
错误包含稳定的 code 字段,调用方无需通过正则表达式匹配错误文本,即可按程序逻辑分支处理:
| 代码 | 含义 |
|---|---|
NOT_RUNNING | 工具需要正在运行的会话,但当前没有会话 |
ALREADY_RUNNING | 已存在会话时调用了 start_app |
TIMEOUT | 操作超时 |
NOT_FOUND | 选择器或文件未匹配到内容 |
FILE_NOT_FOUND | 基于路径的输入指向不存在的文件 |
BAD_ARGUMENT | 参数未通过验证 |
UNKNOWN_TOOL | 无法识别工具名称 |
ERROR | 其他所有错误 |
工具
全部 38 个工具按用途分组。所有基于选择器的工具都支持 Playwright 的完整选择器引擎:CSS、text=、role=、[aria-label=]、:has-text()、作用域(main >> button)等。
生命周期
start_app — 启动应用。接受 main(编译后的主进程入口的绝对路径)、可选的 cwd、args、env、screenshotsDir 和 timeoutMs。返回 { title, url, viewport, screenshotsDir, logFile }。能够检测单实例锁导致的失败,并提供有用提示,而不是返回原始断开连接错误。
stop_app — 正常关闭。会话已经停止时也可安全调用。
info — { title, url, viewport: {width, height, devicePixelRatio}, uptimeMs }。视口信息取自 window.innerWidth/innerHeight。
捕获
screenshot — 全页 PNG。传入 name(不带扩展名)以指定文件名。返回 { path }。
cleanup_screenshots — 清空当前会话的截图目录。
console_logs — 最近的渲染进程控制台消息(log/info/warn/error/
debug/pageerror)以及主进程 stdout/stderr。滚动缓冲区最多保留 1000 条记录。可按 source(renderer/main/all)、type 和 limit 筛选。传入 clear: true 可在读取后清空缓冲区。
交互
click — 点击元素。选项:timeoutMs、button
(left/right/middle)、clickCount、force(跳过可操作性
检查)、position(点击元素内的偏移位置)。
type — 对文本输入框执行 fill,替换已有内容。速度快,但
仅适用于真正的输入框。对于编辑器/CodeMirror/contenteditable 元素,请使用
keyboard_type。
keyboard_type — 通过真实的逐字符 keydown 事件输入。传入
focusSelector 可先点击某个元素。如果没有元素获得焦点且未传入焦点选择器,结果中会发出警告。
press — 按下某个键或组合键:"Escape"、"Enter"、"Control+S"、
"Shift+Tab"、"Control+Shift+P"。
press_sequence — keyboard_type 的别名,不带焦点选择器。
hover — 将鼠标悬停在元素上。选项:timeoutMs、force。
drag — 使用真实的 Chromium 输入事件(通过 Playwright 的 CDP 鼠标
管线)从一个点拖动到另一个点。由于这些是可信的浏览器事件,Chromium 的指针
管线会同时生成对应的 PointerEvent,因此 React onPointerDown、原生的
pointerdown 监听器、setPointerCapture、CSS :hover/:active 以及
所有其他指针事件处理方,都会像真实用户执行拖动一样准确地接收到事件。坐标单位为 CSS 像素。传入 detectSelector 后,
驱动程序会测量拖动前后的元素,并在结果中包含
detect.moved ——这是唯一可靠的方式,可捕获被 min/max 限制静默拦截的拖动。
{
"from": { "x": 275, "y": 400 },
"to": { "x": 420, "y": 400 },
"detectSelector": ".sidebar-resize-handle"
}
如果主要策略未能移动检测目标,驱动程序会自动回退,通过 fiber 属性访问直接调用 React 处理程序,并在 document 和 window 上派发 move/up 事件——涵盖所有已知的 React 分隔器模式。传入 fiberFallback: false 可禁用
此回退机制。结果中会包含 strategy
("pointer-capture" 或 "react-fiber")。
clear_input — 清空输入框或文本区域。
select_option — 按 value、label 或
index 从 <select> 中选择选项。
check — 勾选复选框或单选按钮。选项:timeoutMs、force。
uncheck — 取消勾选复选框。
scroll — 滚动容器(传入 selector)或窗口。支持
绝对位置(x、y)或增量(dx、dy)。
scroll_into_view — 确保元素可见。如果元素已经可见,也可以安全调用。
drop_file — 通过合成
DragEvent 和重建的 File,结合 DataTransfer,模拟将文件拖放到目标上。适用于
通过 Web API(FileReader、File.text() 等)读取文件的应用。不会
填充 file.path ——依赖 webUtils.getPathForFile()
的应用必须使用 eval_main 直接调用自己的 IPC 处理程序。
set_input_files — 测试文件上传界面的正确方式。无需原生对话框,即可将文件设置到 <input type="file"> 上。应用使用真实文件输入框时,这种方式比 drop_file 可靠得多。
等待
wait — 固定暂停指定毫秒数。优先使用其他等待方式。
wait_for_selector — 等待选择器达到指定状态
(attached/detached/visible/hidden)。遵循 timeoutMs。成功时返回
count、box 和 elapsedMs;超时则错误信息中包含
elapsed vs requested。
wait_for — 轮询 JavaScript 谓词(函数体,请使用 return),
直到其返回真值。选项:timeoutMs、pollMs。
检查和读取状态
exists — { exists, count } 快速检查,不会等待。支持完整的选择器引擎。
get_text — 第一个匹配项的文本内容。支持完整的选择器引擎。返回 { exists, text }。
get_attribute — 按名称读取 HTML 属性。返回 { exists, value }。
get_value — 读取 input/textarea/select 的当前值。
get_bbox — 以 CSS 像素为单位的边界框 { x, y, width, height }。在拖动或按偏移量点击前使用。
get_computed_style — 读取一个或多个计算后的 CSS 属性。传入 properties 数组。
elements_list — 列出与选择器匹配的元素及其标签、id、类名、文本片段、边界框和关键属性。非常适合查看“此屏幕上有哪些按钮”。默认上限为 50;可通过 limit 调整。
focused_element — 当前获得焦点的元素及其标签、id、类名、文本和边界框。如果没有有意义的焦点元素,则返回 { focused: false }。
accessibility_snapshot — 将 ARIA 树捕获为 JSON。适用于无障碍审计和按角色查找元素。传入 interestingOnly: false 可包含所有节点。传入 root 可对某个子树进行快照。
多窗口
windows_list — 应用打开的每个 BrowserWindow,包括 id、标题、URL、焦点/可见性/状态标志。
switch_window — 将后续工具调用路由到其他窗口。传入 index 或 titleMatch。
对话框
dialog_handler — 为 JavaScript 对话框(alert/confirm/prompt/beforeunload)安装自动响应器。传入 action: "accept" | "dismiss"、prompt() 的可选 text,以及 once: true(默认值),即可在第一个对话框出现后自动卸载。
求值逃生通道
eval_renderer 和 eval_main 使用相同的约定:传入函数体,使用 return 返回值,支持 async/await,并且可通过局部变量 arg 使用可选的 arg 负载。
eval_renderer — 在渲染器(页面)上下文中求值。
{
"js": "return document.querySelectorAll(arg.selector).length",
"arg": { "selector": ".item" }
}
eval_main — 在 Electron 主进程中求值。函数体可接收 electron(完整的 Electron 模块)和 arg。
{
"js": "return electron.app.getName()"
}
{
"js": "const w = electron.BrowserWindow.getAllWindows()[0]; w.webContents.send('open-file', arg.path); return true",
"arg": { "path": "C:/docs/README.md" }
}
对于 DOM 侧无法访问的所有内容,使用 eval_main 作为逃生通道:调用 IPC 处理程序、读取用户路径、控制辅助窗口,以及绕过使用原生对话框的应用中的这些对话框。
选择器速查表
text=Open File // exact text match
text=/^Save$/ // regex
[aria-label="Settings"] // ARIA attribute
role=button[name="Close"] // ARIA role
button:has-text("Save") // CSS with text predicate
button.primary // plain CSS
main >> text=Save // scoped
选择器引擎一致性
所有基于选择器的工具(click、hover、wait_for_selector、get_text、get_attribute、get_value、get_bbox、exists、elements_list、scroll_into_view、select_option、check、uncheck、set_input_files)都使用 Playwright 的完整定位器引擎。Playwright 接受的选择器,这些工具都接受,包括 text=、role= 和 :has-text()。
底层通过 eval_renderer 读取 DOM 的工具(get_computed_style、scroll、focused_element、drop_file)使用原生 document.querySelector,仅支持 CSS。相关工具的说明中会注明这一点。
故障排除
“Electron 进程启动后立即退出。” 已有另一个应用实例正在运行并占用了单实例锁——第二个进程会通过 app.requestSingleInstanceLock() 退出。关闭正在运行的实例(检查任务栏和后台进程),然后重试。
drag 返回了 ok:true,但 detect.moved 为 false。 最常见的原因是目标受到最小值/最大值限制(例如,可调整大小的侧边栏已达到其 MAX_WIDTH)。尝试向相反方向拖动,以确认拖动流程正常。如果确实不是限制导致的,React fiber 回退机制应该会自动捕获——检查结果中的 strategy 字段。如果这样仍返回 moved:false,请使用 eval_renderer 或 eval_main 直接调用应用自身的拖动 API。
type 抛出“Element is not an <input>...” 你操作的是按钮、div 或 contenteditable。请改用带有 focusSelector 的 keyboard_type。
click 在一个明显存在的元素上超时。 有东西挡住了它——模态框背景、工具提示或提示消息。先使用 exists 确认数量,然后尝试 force: true,或者使用 eval_renderer 检查 getComputedStyle(el).pointerEvents。
看不到原生对话框。 Playwright 无法看到操作系统级别的文件选择器、保存对话框或系统警告。请使用 eval_main 调用 UI 按钮使用的同一个 IPC 处理程序。对于 JavaScript 对话框(alert/confirm/prompt),请使用 dialog_handler 自动响应。
开发构建与编译后的应用。 此工具驱动的是构建后的应用,而不是开发服务器的输出。运行构建命令后再调用 start_app;源代码更改后,请重新构建并重启会话。
一次只能运行一个会话。 会话正在运行时调用 start_app 会返回 ALREADY_RUNNING。请先调用 stop_app。
日志。 会话处于活动状态时,每次工具调用都会记录到
<project>/.electron-driver/driver.log。调试 Agent 卡住的原因时,这些日志很有用。
截图位置。 默认位置为 <project>/.electron-driver/screenshots,
其中 <project> 是最近的、包含 .git 或 package.json 的目录。可通过 start_app 中的 screenshotsDir 覆盖。
安全
此服务可让已连接的 Agent 完全控制 Electron 应用,包括在主进程中执行任意代码(通过 eval_main)。 Electron 主进程拥有不受限制的 Node.js 访问权限——文件系统、网络、子进程,等等。这是有意为之:正是这一点让驱动程序能够强大到足以驱动真实应用。
这对你意味着:
- 仅通过 stdio 使用(默认方式)。绝不要通过 HTTP、WebSocket 或任何网络传输方式暴露此服务。stdio 会将其绑定到启动它的进程——你本地的 Claude Code 或 Claude Desktop 会话。
- 信任该 Agent。 调用这些工具的 Agent 可以通过
eval_main在你的机器上执行任何操作。只连接你信任的 Agent。 - 不要在多租户环境中使用。 这是面向单个用户的本地工具,并非为共享服务器、包含不可信输入的 CI 流水线,或调用方可能具有恶意的任何环境而设计。
drop_file和set_input_files会读取本地文件,并将其内容传递给渲染进程。文件路径应来自可信来源。
如果你使用 Claude Code 运行此工具,其风险等级与授予 Claude Code 终端访问权限相同(你已经授予了)。此驱动程序不会增加任何超出终端中 eval 能力范围的新功能——它只是让 Agent 使用起来更方便。
已知限制
- Playwright 的
_electron命名空间在上游官方仍处于实验阶段。 在速度较慢的机器上偶尔会出现启动超时;通常重试即可解决。 - 主要在 Windows 上开发。Mac 和 Linux 应该也能正常运行——Playwright 会处理这些平台——但测试覆盖较少。欢迎提交错误报告。
switch_window会将后续调用路由到所选窗口,但控制台日志缓冲区的数据来自初始窗口。多窗口控制台捕获计划列入 v0.4。drop_file不会填充file.path。使用webUtils.getPathForFile()的应用必须通过自己的 IPC 使用eval_main。- 目前尚无内置的网络请求捕获功能——计划列入 v0.4。
实现说明
供感兴趣或希望参与贡献的人参考:
- 使用单个 Electron 会话,由 MCP 服务进程持有。
- 每次
start_app时都会清除屏幕截图——这是有意为之。 - 控制台日志会捕获到一个最多容纳 1000 条记录的滚动缓冲区中。
- 每次工具调用都会记录日志;错误会带有稳定的
code字段。 - 错误消息会重写为归因于驱动工具,而非底层 Playwright 方法。
- 单实例锁检测以“启动后 5s 内进程断开连接”为判断依据,这正是实际故障的表现形式。
- 求值代码会用异步立即调用函数表达式包装,因此
return和await均可使用。 arg负载会在服务端进行强制转换(对字符串执行 JSON 解析),以兼容会将arg字段转换为字符串的 MCP 客户端。- 状态消息使用 stderr;stdout 保留用于 MCP 协议帧。
贡献
欢迎提交问题和 PR。可在本地运行:
cd electron-driver
npm install
node index.mjs # stdio MCP server
服务器会向 stderr 输出就绪提示,并在 stdin 上等待 MCP 帧。通过任意 MCP 客户端,对真实的 Electron 应用进行测试。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。