Files
registry/entries/electron-mcp/usage.md
Yige e06a0b74d0 feat: 新增 electron-mcp 条目 — Electron 桌面应用 CDP 自动化 (#1)
- entries/electron-mcp/manifest.json:4 工具、stdio 连接,截图密钥走 {{secrets.*}} 占位
- install.md:端口硬编码扫描范围、CDP 无鉴权风险、密钥强制校验
- usage.md:与 playwright/chrome-devtools MCP 的选型分工,以及 9 条实测限制与规避
- manifest.json:stats 20→21、mcpServices 7→8
2026-07-29 16:04:02 +08:00

7.4 KiB
Raw Blame History

使用 Electron MCP

服务描述

通过 Chrome DevTools Protocol 操控本机正在运行的 Electron 桌面应用:发现窗口、在渲染进程里 执行 JavaScript、点击/填表、截图、读日志。

它不启动应用,只连接已经在跑、且开放了调试端口的应用。

什么时候用它

场景 选择
验证 Electron 桌面应用改动后的真实 UI 表现 Electron MCP
对着运行中的桌面应用截图取证、断言 DOM Electron MCP
抓桌面应用的渲染进程 console 报错 Electron MCP
自动化普通网站、需要自己开浏览器 用 Playwright MCP
需要网络面板、性能 trace、Lighthouse 用 Chrome DevTools MCP
驱动应用的原生部分(菜单栏、系统对话框、托盘) CDP 够不着,见「已知限制」

连接方式

  • 传输协议stdio
  • 启动命令npx -y electron-mcp-server@1.5.0

连接配置

{
  "transport": "stdio",
  "command": "npx",
  "args": ["-y", "electron-mcp-server@1.5.0"],
  "env": {
    "SCREENSHOT_ENCRYPTION_KEY": "{{secrets.SCREENSHOT_ENCRYPTION_KEY}}"
  }
}

该密钥在 ~/.desirecore/config/secrets.json 中配置;缺失或不足 32 字符时截图工具直接报错, 详见 install.md

可用能力

共提供 4 个工具。

工具 用途
get_electron_window_info 扫描本机调试端口,列出 Electron 应用的窗口标题、URL、尺寸
send_command_to_electron 在渲染进程执行命令(含 eval 与一组封装好的 UI 交互命令)
take_screenshot 截取窗口图像,返回 base64outputPath 才落盘
read_electron_logs 读取 console / main / renderer 日志

send_command_to_electron 的参数形状

参数必须是对象,传裸字符串会被拒。常用命令:

{ "command": "get_page_structure" }                                   // 先看页面有什么
{ "command": "debug_elements" }                                       // 按钮/表单元素调试信息
{ "command": "click_by_text",    "args": { "text": "保存" } }
{ "command": "click_by_selector","args": { "selector": "button.submit" } }
{ "command": "fill_input",       "args": { "selector": "#email", "value": "a@b.com" } }
{ "command": "fill_input",       "args": { "placeholder": "请输入名称", "value": "测试" } }
{ "command": "select_option",    "args": { "selector": "#lang", "value": "zh-CN" } }
{ "command": "send_keyboard_shortcut", "args": { "text": "Enter" } }
{ "command": "navigate_to_hash", "args": { "text": "#settings" } }
{ "command": "get_title" }  { "command": "get_url" }  { "command": "get_body_text" }
{ "command": "eval",             "args": { "code": "document.title" } }

推荐工作流

  1. get_electron_window_info每次动作前先做这一步,确认连上的是哪个应用、哪个端口
  2. get_page_structuredebug_elements — 摸清当前页面有哪些可交互元素
  3. click_by_text / fill_input 等封装命令驱动 UI比手写 eval 可靠,见下)
  4. take_screenshot 取证
  5. 出问题时 read_electron_logs 看渲染进程报错

已知限制与规避

1. 端口不可配置,超出扫描范围就完全连不上

v1.5.0 硬编码扫描 9222-92259200-92059300-93059400-9405不读任何环境变量。 应用若把调试端口自动分配到列表外多实例并行开发时很常见MCP 会直接报「未找到运行中的 Electron 应用」。此时只能改用直连 CDP见第 5 条)。

2. 多实例时会连错应用(最容易踩的坑)

工具连的是「扫描到的第一个」应用,本机同时跑多个 Electron 应用(或同一应用的多个实例、 或遗留的 SSH 隧道占着端口)时,动作会打到非预期的目标上。

铁律:先 get_electron_window_info 核对窗口标题与 URL 再动手。 端口归属存疑时用 lsof -nP -i :9222WindowsGet-NetTCPConnection -LocalPort 9222)确认占用进程。

判断「截图是不是同一个窗口」不要靠往页面加视觉标记(document.body 加边框在高度为 0 的 应用里根本不可见,会误判),改成改 document.title 后用 curl http://127.0.0.1:9222/json 核对 target 标题。

3. eval 被安全策略静默过滤(不是报错,是悄悄返回错值)

v1.5.0 的安全级别永远是 balanced——运行代码里没有任何地方读取 SECURITY_LEVEL 环境变量,配了也不生效。balanced 下:

  • 赋值语句被禁allowAssignments: false
  • 只放行白名单函数:querySelector(All)getElementByIdgetElementsBy*getComputedStylegetBoundingClientRectfocusblurscrollIntoViewdispatchEvent

典型症状是返回 falsesuccess: true 但没有 result,而不是抛异常:复杂表达式、 IIFE、任何赋值都可能这样悄悄失败。简单表达式document.title...length)正常。

另外 get_page_structure / debug_elements 只返回前若干个元素,大页面不够用。

规避:能用封装命令(click_by_text 等)就别用 eval;需要任意复杂表达式时走第 5 条。

4. eval 的顶层 const 会驻留全局

同名变量第二次执行报 already declared。复杂代码一律包进 IIFE。

5. 绕行方案:直连 CDP

上述限制端口范围、eval 过滤、返回值丢失)在直连 CDP 时都不存在。Node 22+ 有全局 WebSocket,无需任何依赖:

// 1. 列出 target挑 webSocketDebuggerUrl
//    curl -s http://127.0.0.1:<port>/json
const ws = new WebSocket(wsUrl)
ws.addEventListener('open', () => {
  ws.send(JSON.stringify({
    id: 1,
    method: 'Runtime.evaluate',
    params: { expression: '(() => { /* 任意代码 */ })()', returnByValue: true, awaitPromise: true },
  }))
})
ws.addEventListener('message', e => console.log(JSON.parse(e.data)))

截图同理用 Page.captureScreenshot,键盘用 Input.dispatchKeyEvent

6. CDP 够不着的东西

  • 原生对话框dialog.showOpenDialog / showSaveDialog、原生菜单、托盘CDP 完全操作不到。 绕行是直接调用接收路径参数的 IPC跳过对话框环节
  • contextBridge 暴露的对象是冻结的writable: false / configurable: false,无法 monkey-patch 去 mock 主进程调用(赋值静默失败)
  • 主进程逻辑:只能通过渲染进程可达的 IPC 间接触发

7. 关闭连接可能触发应用退出

CDP 的 Browser.close 会让应用走完整的退出流程(before-quit 等钩子照常执行,可能触发 安装更新、写盘、清理等副作用)。调试结束想断开,断 WebSocket 即可,不要发 Browser.close

8. React / 虚拟滚动应用的断言假阴性

  • 虚拟滚动列表只渲染视口内的条目,querySelectorAll 可能返回 0。先滚动到目标位置再断言
  • loading="lazy" 的图片未进视口时 naturalWidth === 0 / complete === false 这不代表加载失败,scrollIntoView 后再查
  • 改动前端源码会触发 HMR 重置组件状态,注入状态做验证时不要中途改代码

9. 生产包通常不开放调试端口

多数应用只在开发态开 CDP。要调试打包版本得用应用自身提供的开关环境变量/启动参数), 且用完立即关闭——CDP 无鉴权,开着等于把应用控制权敞开给本机任何进程。