electromcp
v1.2.0
Published
Connect Claude to any Electron app — testing, debugging, visual QA, and full automation
Maintainers
Readme
ElectroMCP
An Electron · Playwright · MCP Server

Your AI is flying blind inside your Electron app.
Whether you're working with Claude, Gemini, Codex, Cursor, Windsurf, or GitHub Copilot — every time you want your AI to help with your UI, you're doing the same painful loop:
Run the app. Screenshot it. Paste it in. Describe what's wrong. Wait. Get an answer. Make a change. Start over.
You've become a human copy-paste machine. Manually bridging the gap between the most capable AI tools in history and the product you're building, one screenshot at a time.
ElectroMCP removes you from that loop entirely.
It's an MCP server. Connect it once to any MCP-compatible AI. Now your AI opens your app, takes its own screenshots, clicks through your flows, reads the console, runs your test suite, and comes back with a full report before you've even looked. Not a guess. A report — bugs, visual inconsistencies, broken interactions, console errors, the lot.
The QA session that used to take you an hour? It's a ten-second conversation now.
This isn't AI-assisted QA. This is AI-operated QA. There's a difference.
What This Looks Like In Practice
You open your AI of choice. You say: "Check my onboarding flow. Make sure every screen looks right and the button on step 3 works."
Your AI launches the app, navigates every screen, takes screenshots, clicks the button, reads the result, and comes back with a full breakdown. You didn't paste a single screenshot. You didn't describe a single UI element. You just asked.
That is what this tool does.
Install
The core command is the same everywhere — npx electromcp. Only the config location differs by AI tool.
Claude Code (one command)
claude mcp add electromcp -- npx electromcpClaude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"electromcp": {
"command": "npx",
"args": ["electromcp"]
}
}
}Gemini CLI
Edit ~/.gemini/settings.json:
{
"mcpServers": {
"electromcp": {
"command": "npx",
"args": ["electromcp"]
}
}
}Cursor
Edit ~/.cursor/mcp.json (global) or .cursor/mcp.json (project-level):
{
"mcpServers": {
"electromcp": {
"command": "npx",
"args": ["electromcp"]
}
}
}Windsurf
Edit ~/.codeium/windsurf/mcp_settings.json:
{
"mcpServers": {
"electromcp": {
"command": "npx",
"args": ["electromcp"]
}
}
}VS Code (GitHub Copilot)
Edit .vscode/mcp.json in your project:
{
"servers": {
"electromcp": {
"command": "npx",
"args": ["electromcp"]
}
}
}Smithery (any AI)
npx @smithery/cli install electromcpSmithery handles the config automatically for whichever AI tool you're using.
Connecting Your AI to Your App
Launch from source
app_launch {
executablePath: "/path/to/electron",
args: ["/path/to/your-app"]
}Full feature set: screenshots, accessibility tree, HAR recording, dialog stubs, everything.
Attach to a running instance
app_connect { port: 9222 }Add one line to main.js to enable the debug port:
app.commandLine.appendSwitch('remote-debugging-port', '9222');Or via package.json:
{
"scripts": {
"start:debug": "electron . --remote-debugging-port=9222"
}
}Tools
App Lifecycle
| Tool | What It Does |
|------|-------------|
| app_launch | Launch an Electron app via Playwright. Full fidelity: screenshots, HAR, dialog stubs. Accepts executablePath, args, debugPort, harPath. |
| app_connect | Attach to a running app over CDP. Accepts port (default 9222) or a full url. |
| app_disconnect | Disconnect without killing the app. |
| app_stop | Shut down the app and disconnect. |
| app_health | Ping the connection. If the page is dead, triggers automatic reconnect. |
Visual Inspection
| Tool | What It Does |
|------|-------------|
| ui_screenshot | Take a full screenshot of the current window. |
| ui_accessibility_snapshot | Return the full accessibility tree. Faster and cheaper than a screenshot. Use this first when you want to understand structure rather than visuals. |
| ui_get_dom | Get the raw HTML of the page or a specific element. |
| ui_observe | Capture the visual state for AI analysis. Returns the screenshot with context so the AI can reason about what it sees. |
Interaction
| Tool | What It Does |
|------|-------------|
| ui_click | Click any element by selector or visible text. |
| ui_fill | Fill an input field instantly (no typing delay). |
| ui_type | Type text character by character. Useful when apps respond to keystrokes rather than final values. |
| ui_press | Press a keyboard shortcut: Enter, Escape, Ctrl+S, Cmd+K, anything. |
| ui_hover | Hover over an element to trigger tooltips or hover states. |
| ui_scroll | Scroll the page or a specific element in any direction. |
| ui_wait_for | Wait for a selector to appear, disappear, or become visible. |
| ui_get_element | Get the attributes, text content, bounding box, visibility, and enabled state of an element. |
| ui_act | Returns a screenshot so the AI can decide what to do next. You describe the goal, the AI figures out the selector. |
Debugging
| Tool | What It Does |
|------|-------------|
| app_console_logs | Pull the console output from the renderer process. Everything console.log, console.error, and console.warn produced since launch. |
| app_evaluate_renderer | Run any JavaScript in the renderer process and get the return value. Inspect live state, query the DOM, check variables. |
| app_evaluate_main | Run JavaScript in the main process. Requires ALLOW_MAIN_EVAL=1. Intentionally gated. |
| app_crash_status | Check whether the renderer has crashed. |
| app_crash_reset | Clear the crash flag and continue. |
Test Runner
| Tool | What It Does |
|------|-------------|
| test_run | Run any shell command and parse it as a test run: pass/fail counts, failure details, raw output. Works with Jest, Vitest, Playwright, Mocha, or anything that exits non-zero on failure. |
| test_run_file | Run a specific test file. |
| test_run_grep | Run tests matching a name pattern. |
| test_get_results | Return the parsed results from the last test run. |
Window Management
| Tool | What It Does |
|------|-------------|
| window_list | List every open window: title, URL, dimensions, focus state. |
| window_switch | Switch to a window by title substring or index. |
| window_get_by_title | Find the first window whose title contains a given string. |
Electron-Specific
| Tool | What It Does |
|------|-------------|
| electron_ipc_send | Send a message on any IPC channel via ipcRenderer. Works in launch and CDP modes. Tries contextBridge first, then nodeIntegration fallback. |
| electron_stub_dialog | Stub native OS dialogs before the action that opens them. Native dialogs block Playwright, so stub them so flows don't hang. |
| electron_on_crash | Wait for a renderer crash or timeout. Useful for crash-recovery testing. |
Network Recording
| Tool | What It Does |
|------|-------------|
| batch_run | Plan a multi-step sequence. Returns an ordered list for the AI to execute one tool at a time. |
| app_record_har | Start HAR network recording. Relaunches the app with recordHar enabled and captures every HTTP request and response. |
| app_stop_har | Flush and save the HAR file. Ends the session; call app_launch to reconnect. |
Video Recording
| Tool | What It Does |
|------|-------------|
| app_record_video | Start .webm video recording of the app session. Relaunches with Playwright recordVideo enabled. Launch mode only. Accepts outputDir. |
| app_stop_video | Flush and save the video file. Returns the .webm file path. Ends the session; call app_launch to reconnect. |
The Recommended Flow
1. app_health confirm the connection is alive
2. ui_accessibility_snapshot understand what's on screen (no image cost)
3. ui_screenshot capture the visual state (only when layout matters)
4. ui_click / ui_fill / ... interact with the app
5. ui_accessibility_snapshot verify the resultFor debugging:
1. app_console_logs what did the renderer actually log?
2. app_evaluate_renderer inspect live DOM, variables, state
3. app_evaluate_main check main process (needs ALLOW_MAIN_EVAL=1)Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| ALLOW_MAIN_EVAL | unset | Set to 1 to enable app_evaluate_main |
Limitations Worth Knowing
electron_ipc_send sends from the renderer. If your app uses contextIsolation: true without a contextBridge-exposed ipcRenderer and without nodeIntegration: true, the call fails with a clear error.
HAR recording requires launch mode. It cannot be added to an existing CDP session.
app_evaluate_main is launch mode only and requires ALLOW_MAIN_EVAL=1.
Headless mode is not officially supported by Electron. On Linux CI: xvfb-run npm test.
Development
git clone https://github.com/TheRealSeanDonahoe/electromcp
cd electromcp
npm install
npm run build # tsc -> build/
npm run dev # tsx src/index.ts
npm test # builds + runs 8 integration tests against a real Electron windowOn Linux: xvfb-run npm test
License
MIT
