Electron Viewer

io.github.acertijosapps由 GitHub 帳號 acertijosapps 發布v1.1.0更新於 Nov 7, 2026

Drive Electron apps over CDP: screenshots, clicks, drags, keys, JS in renderer and main, logs.

已驗證STDIO僅桌面瀏覽器自動化開發者工具

概覽

AI 產生的概覽

透過 CDP 操控 Electron 桌面應用程式:截圖、滑鼠、觸控與鍵盤輸入、在渲染程序與主程序執行 JavaScript,以及讀取主控台日誌。

可以做什麼
  • 列出、啟動並附加到 Electron 應用程式及其視窗
  • 擷取視窗畫面,並讀取帶可點擊座標的無障礙樹
  • 點擊、拖曳、懸停、捲動、輸入文字與帶修飾鍵的按鍵
  • 輕觸、滑動、長按與雙指縮放,適用於觸控優先的應用程式
  • 調整或重新載入視窗,並在頁面或主程序中執行 JavaScript
  • 讀取主控台訊息與例外,或已啟動應用程式的原始標準輸出
適用情境
適合需要檢查、測試或操作本機 Electron 應用程式的情況,例如重現介面問題、端對端驗證某個流程,或驅動自助服務機與觸控應用程式。也可讓人在瀏覽器面板中即時觀看代理正在操作的同一視窗。
執行需求
透過 npx 以 stdio 在本機執行,需要 Node.js 18 或更新版本。啟動應用程式需要專案中 node_modules 已安裝 electron,或應用程式已帶遠端偵錯連接埠啟動。選用環境變數:ELECTRON_VIEWER_PROJECT、ELECTRON_VIEWER_URL、ELECTRON_VIEWER_LAUNCH_CMD。僅限桌面,無身分驗證。
安裝前請注意
此伺服器可在應用程式的渲染程序與主程序中執行任意 JavaScript,因此能讀取或修改應用程式可觸及的任何內容。它會啟動程序並送出真實輸入,可能在應用程式中寫入或刪除資料。應固定具體版本號,不要讓 npx 抓取最新版本。標題列、選單、對話框等原生介面不會被擷取或點擊。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Electron Viewer,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

@acertijosapps/electron-viewer

Live viewer for Electron apps in the browser, plus an MCP server so an AI agent can drive them. Built for the browser pane of AI coding tools (such as Claude Code): you and the agent watch and control the same app window, in real time.

[Electron Viewer showing the example app: window selector and launch button on top, the live window in the middle, and the reload, DevTools, window size, touch and screenshot controls at the bottom]
  • Live video: Page.startScreencast from the Chrome DevTools Protocol (CDP) over WebSocket. It keeps streaming while the app window is covered or minimized.
  • Real input: mouse move and hover, click, double click, right click, drag, wheel and full keyboard passthrough (including ⌘C/⌘V/⌘A on macOS, IME and dictation).
  • Touch: a touch mode in the viewer turns the pointer into a finger, and the agent can tap, swipe, long press and pinch, for touch-first and kiosk apps.
  • Every app and window: launch your project with electron . from the viewer, or attach to any app started with --remote-debugging-port. Apps on ports 9222–9231 are found automatically.
  • Main process too: launched apps also expose their main process (Node inspector), so the agent can run code there, resize the real window and open DevTools.
  • MCP server: the same actions as tools, plus JavaScript in the renderer and main process, the accessibility tree with click-ready coordinates, and console logs.
  • Nothing to add to your app: no preload, no dependency, no code changes.

Requirements

  • Node.js 18 or later.
  • An Electron app. To launch it from the viewer, the project must have electron in its node_modules (npm install --save-dev electron); if its binary hasn't been downloaded yet, the viewer downloads it on the first launch.
  • Works on macOS, Linux and Windows.

Quick start

From your Electron project folder:

sh
npx @acertijosapps/[email protected]

Open http://localhost:8094 and click Launch. The viewer runs electron . on free debugging ports (CDP from 9222, Node inspector from 9229). Deep link to a window: ?window=<target id>.

If your app is started by another tool (electron-vite, Electron Forge, a custom script), give the viewer your own start command. {cdpPort} and {inspectPort} are replaced with free debugging ports, and the Launch button (and launch_app) runs it in the project folder:

sh
npx @acertijosapps/[email protected] --launch-cmd "yarn dev --remoteDebuggingPort {cdpPort} --inspect {inspectPort}"

That line is for electron-vite; for an npm script that ends in electron ., pass the flags after --: --launch-cmd "npm start -- --remote-debugging-port={cdpPort} --inspect={inspectPort}". The command is only read from the command line or ELECTRON_VIEWER_LAUNCH_CMD, never from the HTTP API or the MCP.

Or start the app yourself with the flags and the viewer finds it:

sh
electron --remote-debugging-port=9222 --inspect=9229 .

Apps on CDP ports 9222–9231 are found automatically, and so is their main process when its inspector is on 9229–9238. --inspect is optional; without it you get everything except the main-process features (evaluate_main, real window resizing and in-app DevTools). To attach on other ports, use the form in the viewer or --attach and --inspect.

text
electron-viewer [options]        Start the viewerelectron-viewer mcp [options]    Start the MCP server on stdio
      --project <dir>      Project to launch with "electron ." (default: current folder)      --launch-cmd <cmd>   Launch with this shell command instead; {cdpPort} and {inspectPort}                           are replaced with the debugging ports  -p, --port <port>        Viewer port (default 8094, env PORT)      --host <host>        Interface to bind (default 127.0.0.1, env HOST)      --attach <port>      Attach at startup to an app on this CDP port      --inspect <port>     With --attach: the app's main process inspector port      --viewer-url <url>   Viewer the MCP talks to (default http://localhost:8094)

Other environment variables: MAX_DIM (longest side of the streamed frames, default 1920), QUALITY (JPEG quality, default 80), SCREENSHOT_MAX (longest side of MCP screenshots, default 1024), CDP_PORT / INSPECT_PORT (first ports to scan and launch on, default 9222 / 9229) and ELECTRON_VIEWER_STATE_DIR (where launched and attached apps are remembered, default ~/.cache/electron-viewer).

Use it with an AI agent (MCP)

Claude Code:

sh
claude mcp add electron-viewer -- npx -y @acertijosapps/[email protected] mcp

Any other MCP client:

json
{  "mcpServers": {    "electron-viewer": {      "command": "npx",      "args": ["-y", "@acertijosapps/[email protected]", "mcp"]    }  }}

Also listed in the official MCP Registry as io.github.acertijosapps/electron-viewer.

The examples pin an exact version. The viewer and the MCP can run code in your app, so pin the version you reviewed instead of letting npx fetch whatever was published last, and update it on purpose.

Keep the viewer running (npx @acertijosapps/[email protected]) to watch what the agent does. Without it, the MCP drives the app over CDP directly. Apps launched by either one are visible to the other.

ToolWhat it does
list_windowsRunning apps (with main when the main process is reachable) and their windows
launch_appRun electron . in the project on free debugging ports and wait for the first window
attachAttach to an app on a CDP port, optionally with its inspector port
screenshotPNG of the window content, longest side ≤ 1024 px
clickLeft, right or middle click; count: 2 for a double click; optional modifiers
dragPress, move in steps and release: a real drag
hoverMove the mouse without clicking
tapOne-finger tap (touch events, pointerType: "touch")
swipeOne-finger swipe: scrolls touch lists and drives swipe gestures
long_pressHold one finger down for a while, 800 ms by default
pinchTwo-finger pinch around a point; scale > 1 zooms in, < 1 zooms out
scrollMouse wheel at a point, deltas in CSS px
type_textInsert text into the focused element (any Unicode)
press_keyEnter, Tab, Escape, arrows, F1–F12… or any character, with modifiers
resize_windowResize the content area: the real window with the main process, an emulated viewport when the window can't reach the size (or with emulate: true)
reloadReload the window's page
evaluateRun JavaScript in the window's page and return the value
evaluate_mainRun JavaScript in the main process, with require('electron') available
get_accessibility_treeRoles, names, values and states; interactive elements carry their normalized center
get_console_logsConsole messages and exceptions from renderer windows and the main process, or the raw stdout

Coordinates are normalized to 0–1 over the content screenshot (x = pixel_x / image_width), so they hold at any window size. window is optional when only one window is open; it takes the target id from list_windows or part of the window title.

In the Claude Code browser pane

Add the viewer to .claude/launch.json and open it with preview_start electron-viewer:

json
{  "version": "0.0.1",  "configurations": [    {      "name": "electron-viewer",      "runtimeExecutable": "npx",      "runtimeArgs": ["-y", "@acertijosapps/[email protected]"],      "port": 8094,      "autoPort": false    }  ]}

HTTP API

The MCP uses the viewer's API; you can call it too. window (target id or part of the title) goes in the query string or the body and is optional with a single window. The server only listens on 127.0.0.1, only accepts a local Host and origin, and POST requests require content-type: application/json, so other websites can't drive your apps.

Endpoint
GET /api/windows[{ id, name, cdpPort, inspectPort, main, windows: [{ id, title, url }] }]
GET /api/projectThe project the viewer launches and whether it has Electron installed
GET /api/screenshot?max=<px>PNG; viewport size in X-Viewport-Width / X-Viewport-Height
GET /api/ax-tree?interactiveOnly=true{ tree }
GET /api/logs?level=&source=&limit={ logs } or { stdout }
POST /api/launch{ project? }
POST /api/attach{ port, inspectPort? }
POST /api/click{ x, y, button?, count?, modifiers? }
POST /api/drag{ x1, y1, x2, y2, ms? }
POST /api/hover{ x, y }
POST /api/tap{ x, y }
POST /api/swipe{ x1, y1, x2, y2, ms? }
POST /api/long-press{ x, y, ms? }
POST /api/pinch{ x?, y?, scale, ms? }
POST /api/scroll{ x, y, dx, dy }
POST /api/text{ text }
POST /api/key{ key, modifiers? }
POST /api/resize{ width, height, emulate? } (0 × 0 restores the window size)
POST /api/reload{ ignoreCache? }
POST /api/evaluate{ expression }
POST /api/evaluate-main{ expression, app? }
POST /api/devtoolsToggles DevTools; without the main process returns the DevTools url

How it works

  • Everything goes through CDP with ws: no Playwright, no Puppeteer, nothing injected into the app. The renderer is reached through --remote-debugging-port (one page target per window) and the main process through the Node inspector (--inspect), where the console API provides require.
  • One screencast session per window, shared by every viewer tab and stopped when the last one closes. The last frame is kept for late joiners. Focus and page lifecycle are emulated while someone is watching, so a covered or minimized window keeps painting.
  • Viewer input is queued in order and mouse moves are coalesced to one per animation frame. A hidden textarea holds the focus: keys are sent with Input.dispatchKeyEvent, and text that arrives without key events (IME, dictation) with Input.insertText. On macOS, ⌘A, ⌘C, ⌘V, ⌘X and ⌘Z are sent as editing commands, because the native menu that normally handles them never sees CDP events.
  • Touch goes through Input.dispatchTouchEvent. The first touch action on a window also turns on touch emulation (navigator.maxTouchPoints 5, pointer: coarse) until the viewer or MCP that sent it exits.
  • Each process keeps one connection per window and per main process, which also collects console messages and exceptions (the last 1000 per app).
  • For an app with no known inspector, each Node inspector on ports 9229–9238 is asked once, read only, whether it is Electron and which CDP port its app listens on. Any other Node process started with --inspect in that range gets one short connection (it logs Debugger attached.) and is left alone.
  • Launched and attached apps are remembered in ~/.cache/electron-viewer, so the viewer and the MCP see the same apps. Launched apps write their output to a log file there and keep running if the viewer or MCP exits.

Limitations

  • CDP only sees web content. Native UI (title bar, menus, dialogs, tray, notifications) isn't shown or clickable; use evaluate_main to drive it from the main process. Capturing it would mean capturing the screen, and with it any other window on top of the app, so the viewer doesn't.
  • Synchronous dialogs (dialog.showMessageBoxSync) block the main process: evaluate_main waits until the dialog is closed.
  • Each WebContentsView is a separate CDP target, so it is listed as its own window. <webview> tags are not listed.
  • A long press reaches the app as a held touch, so apps that time touchstart themselves see it, but Chromium on desktop doesn't turn it into a context menu. The viewer's touch mode is one finger; use pinch for two.
  • No audio.
  • A --launch-cmd must pass the ports on to Electron; how depends on the tool. Launched apps keep running when the viewer exits; close them from the app (or its terminal).

Contributing

Branching model (main · beta), Conventional Commits and releases are described in CONTRIBUTING.md; changes are listed in CHANGELOG.md. The example app in example/ is there to try changes.

Author

Made by AcertijosApps. See the rest of our libraries at acertijosapps.com/librerias.

Questions or proposals: [email protected] or open an issue.

License

MIT

來源:README.md,提交 980e6e6

工具

20

list_windows

List windows

Lists the running Electron apps (found on CDP ports 9222–9231, launched or attached) and their windows. main=true means the main process is reachable (evaluate_main, real window resizing). Includes the viewer URL to watch a window live in a browser pane.

無需輸入參數。

launch_app

Launch app

Starts the Electron project on free debugging ports, so both the renderer (CDP) and the main process (Node inspector) are reachable, and waits for the first window. It runs `electron .` with the project's own Electron, or the launch command configured with --launch-cmd (e.g. a dev server).

輸入參數project

attach

Attach to app

Attaches to an Electron app already running with --remote-debugging-port=<port> (and optionally --inspect=<inspect_port> for the main process). Apps on ports 9222–9231 are found without attaching.

輸入參數port必填inspect_port

screenshot

Screenshot

Captures the window content (PNG). For click, drag, hover and scroll use normalized coordinates: x = pixel_x / image width, y = pixel_y / image height. Native UI (title bar, menus, dialogs) is not included.

輸入參數window

click

Click

Clicks a point of the window content (Input.dispatchMouseEvent). count=2 is a double click.

輸入參數x必填y必填countbuttonwindowmodifiers

drag

Drag

Presses the left button at one point, moves to another with intermediate steps and releases (a real drag).

輸入參數x1必填x2必填y1必填y2必填windowmodifiersduration_ms

hover

Hover

Moves the mouse to a point without clicking (hover effects, tooltips).

輸入參數x必填y必填window

tap

Tap

Taps a point with one finger (Input.dispatchTouchEvent): the page gets touch and pointer events with pointerType "touch". The first touch action turns on touch emulation for the window (maxTouchPoints, pointer: coarse).

輸入參數x必填y必填window

swipe

Swipe

Swipes one finger from one point to another (touch events; use drag for the mouse). Scrolls touch lists and drives swipe gestures.

輸入參數x1必填x2必填y1必填y2必填windowduration_ms

long_press

Long press

Holds one finger on a point and releases it. Apps that time touchstart themselves see a long press; Chromium on desktop doesn't turn it into a context menu.

輸入參數x必填y必填windowduration_ms

pinch

Pinch

Two-finger pinch centered on a point: scale > 1 spreads the fingers (zoom in), scale < 1 brings them together.

輸入參數xyscale必填windowduration_ms

scroll

Scroll

Scrolls with the mouse wheel at a point. Positive delta_y scrolls down; deltas are in CSS pixels.

輸入參數xywindowdelta_xdelta_y

type_text

Type text

Types text into the focused element (Input.insertText; any Unicode). Click the field first; for Enter or shortcuts use press_key.

輸入參數text必填window

press_key

Press key

Presses a key, optionally with modifiers (e.g. key "a" + ["meta"] selects all on macOS). Named keys: Enter, Tab, Backspace, Delete, Escape, Space, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Home, End, PageUp, PageDown, Insert, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12; or any single character.

輸入參數key必填windowmodifiers

resize_window

Resize window

Sets the size of the window content area in CSS px. With the main process it resizes the real window; if the window cannot reach that size (smaller screen, kiosk, full screen), without the main process or with emulate=true, the page viewport is emulated at the exact size instead. Width and height 0 restore the window size.

輸入參數width必填height必填windowemulate

reload

Reload

Reloads the page of the window (renderer only; the main process keeps running).

輸入參數windowignore_cache

evaluate

Evaluate in renderer

Evaluates a JavaScript expression in the window page (main world) and returns its JSON value. Promises are awaited.

輸入參數windowexpression必填

evaluate_main

Evaluate in main process

Evaluates a JavaScript expression in the app's main process (Node inspector) and returns its JSON value. `require` is available, e.g. require('electron').BrowserWindow.getAllWindows().map(w => w.getTitle()). Promises are awaited. Needs main=true in list_windows.

輸入參數appexpression必填

get_accessibility_tree

Accessibility tree

Returns the accessibility tree of the window as indented text (role "name" value [state]). Interactive elements carry @(x, y): their center, normalized like click coordinates.

輸入參數windowinteractive_only

get_console_logs

Console logs

Console messages and uncaught exceptions of the app: renderer windows and main process (up to the last 1000). source "stdout" returns the raw output of an app started with launch_app.

輸入參數applevellimitsourcewindow

版本歷史

2
  1. v1.1.0最新Nov 4, 2026
  2. v1.0.0Nov 3, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分