electron-ui-mcp
v0.1.3
Published
Electron UI automation MCP server with Playwright-style primitives
Maintainers
Readme
electron-ui-mcp
⚠️ WARNING: This project is under active development and not ready for production use.
APIs, tool names, and configuration formats may change without notice.
Electron UI automation MCP server with Playwright-style primitives.
This package provides a Model Context Protocol (MCP) server that enables AI assistants to automate Electron desktop applications using a familiar Playwright-like API.
Features
- Electron-focused tool naming - Uses
electron_*for renderer tools andmain_*for main process tools - Auto-detection - Automatically finds Electron entry points when run from a project root
- Lazy initialization - App launches automatically on first tool call
- Lifecycle guards - State machine ensures tools only run when app is ready
- Snapshot-based element addressing - ARIA tree snapshots with element refs (
e0,e1, etc.) - Annotated screenshots - Overlay ref labels on screenshots for visual debugging
- Dev and packaged app support - Works with both development builds and packaged executables
- Session-scoped app override - Tools accept an optional
appfield to override entry/path detection
Quick Start
No installation required - use npx directly:
Add to Claude Code
claude mcp add electron-ui-mcp -- npx electron-ui-mcp --dev .vite/build/main.js --cwd /path/to/your-electron-appAdd to Codex CLI
codex mcp add electron-ui-mcp -- npx electron-ui-mcp --dev .vite/build/main.js --cwd /path/to/your-electron-appAdd to Gemini CLI
gemini mcp add electron-ui-mcp -- npx electron-ui-mcp --dev .vite/build/main.js --cwd /path/to/your-electron-appUsage
CLI
# Dev mode - launch from main.js entry
electron-ui-mcp --dev .vite/build/main.js --cwd /path/to/app
# With Vite dev server
electron-ui-mcp --dev .vite/build/main.js --dev-server http://localhost:5173
# Packaged app (macOS)
electron-ui-mcp --packaged /Applications/MyApp.app
# Packaged app (Windows)
electron-ui-mcp --packaged "C:\Program Files\MyApp\MyApp.exe"
# With isolated userData (default) + E2E
electron-ui-mcp --dev .vite/build/main.js --e2e
# Disable isolation (use real userData)
electron-ui-mcp --dev .vite/build/main.js --no-isolatedCLI Options
Options:
--dev <path> Launch dev mode with main.js entry (auto-detects if omitted)
--packaged <path> Launch packaged app executable
--cwd <path> Working directory
--user-data-dir <path> Custom userData directory
--no-isolated Disable isolated userData (default: enabled)
--dev-server <url> Dev server URL for renderer
--e2e Enable E2E mode
--timeout <ms> Launch timeout (default: 60000)
--config <path> Path to config fileConfiguration
Claude Desktop
Add to your Claude Desktop config (~/.claude.json):
{
"mcpServers": {
"electron": {
"command": "npx",
"args": ["electron-ui-mcp", "--dev", ".vite/build/main.js"],
"cwd": "/path/to/your-electron-app"
}
}
}Codex CLI
Codex stores MCP config in ~/.codex/config.toml:
[mcp_servers.electron]
command = "npx"
args = ["electron-ui-mcp", "--dev", ".vite/build/main.js", "--cwd", "/path/to/your-electron-app"]Gemini CLI
Gemini stores MCP config in ~/.gemini/settings.json:
{
"mcpServers": {
"electron": {
"command": "npx",
"args": ["electron-ui-mcp", "--dev", ".vite/build/main.js", "--cwd", "/path/to/your-electron-app"]
}
}
}Configuration File
Create electron-ui-mcp.json in your project root:
{
"mode": "dev",
"appPath": ".vite/build/main.js",
"rendererUrl": "http://localhost:5173",
"isolated": true,
"e2e": true,
"timeout": 60000
}Environment Variables
| Variable | Description |
|----------|-------------|
| ELECTRON_APP_PATH | Path to executable or main.js |
| ELECTRON_CWD | Working directory |
| ELECTRON_USER_DATA_DIR | Custom userData directory |
| ELECTRON_RENDERER_URL | Dev server URL for renderer |
| E2E | Enable E2E mode (sets E2E=1) |
| ELECTRON_LAUNCH_TIMEOUT | Launch timeout in ms |
| ELECTRON_MODE | dev or packaged |
Auto-Detection
When run from an Electron project root without explicit --dev or --packaged flags, the MCP server automatically detects the entry point by checking (in order):
.vite/build/main.js(Electron Forge + Vite)dist/main.jsdist/main/index.js(Electron Builder)out/main.jsout/main/index.jsbuild/main.jspackage.json#main(if it exists on disk)
The server validates that package.json contains an Electron dependency before attempting auto-detection.
Session-Scoped App Override
All renderer tools accept an optional app field to override detection for the current session (until another override is provided):
{
"name": "electron_snapshot",
"arguments": {
"app": {
"path": "/path/to/my-electron-app",
"entry": "out/main/index.js",
"isolated": true,
"e2e": true
}
}
}| Field | Description |
|-------|-------------|
| path | App root directory (defaults to CWD) |
| entry | Explicit entry point (relative to path) |
| devServer | Dev server URL for renderer |
| isolated | Use isolated userData (default: true) |
| e2e | Enable E2E mode |
Available Tools
Renderer Tools (electron_*)
| Tool | Description |
|------|-------------|
| electron_navigate | Navigate to URL |
| electron_navigate_back | Go back in history |
| electron_snapshot | Capture accessibility tree with refs |
| electron_screenshot | Take screenshot (with optional ref annotations) |
| electron_click | Click element by ref |
| electron_type | Type into element |
| electron_press_key | Press keyboard key |
| electron_fill_form | Fill multiple form fields |
| electron_select_option | Select dropdown option |
| electron_hover | Hover over element |
| electron_drag | Drag and drop |
| electron_file_upload | Upload files |
| electron_handle_dialog | Handle JS dialogs |
| electron_wait_for | Wait for condition |
| electron_evaluate | Execute JS in renderer |
| electron_windows | List/select windows |
| electron_resize | Resize window |
| electron_close | Close application |
| electron_console | Get console log |
| electron_network | Get network log |
Main Process Tools (main_*)
| Tool | Description |
|------|-------------|
| main_evaluate | Execute JS in main process |
| main_app_info | Get app metadata |
How It Works
Snapshot and Refs
The electron_snapshot tool captures an accessibility tree of the current page:
- [e0] heading "Welcome" [level 1]
- [e1] button "Sign In"
- [e2] textbox "Email"
- [e3] textbox "Password"
- [e4] button "Submit"Use these refs with interaction tools:
{
"name": "electron_click",
"arguments": {
"element": "Submit button",
"ref": "e4"
}
}Important: Refs are invalidated when a new snapshot is taken or when switching between windows. Always take a fresh snapshot before interacting with elements.
Annotated Screenshots
Use electron_screenshot with annotate: true to overlay ref labels on the screenshot:
{
"name": "electron_screenshot",
"arguments": {
"annotate": true
}
}This draws red highlight boxes and ref labels (e0, e1, etc.) at each element's position, making it easy to visually identify which ref corresponds to which UI element.
Note: If no snapshot has been taken yet, annotate: true will automatically capture one, which generates new refs. This can invalidate refs from a previous snapshot.
┌─────────────────────────────────┐
│ e0 │
│ ┌───────────────────────────┐ │
│ │ Welcome to App │ │
│ └───────────────────────────┘ │
│ │
│ e1 e2 │
│ ┌──────┐ ┌─────────────────┐ │
│ │Email │ │_________________│ │
│ └──────┘ └─────────────────┘ │
│ │
│ e3 │
│ ┌────────┐ │
│ │ Submit │ │
│ └────────┘ │
└─────────────────────────────────┘If no snapshot has been taken yet, one will be captured automatically before annotating.
Lifecycle States
The server manages these states:
idle- Not launchedlaunching- Starting upready- App running, ready for toolserror- Launch failedclosed- App was closed
Tools automatically launch the app if needed (lazy initialization).
Programmatic Usage
Install as a dependency:
npm install electron-ui-mcpThen use in your code:
import { createServer, resolveConfig } from 'electron-ui-mcp';
const config = resolveConfig({
dev: '.vite/build/main.js',
isolated: true,
});
const server = createServer(config);Security Considerations
Main Process Code Execution
The main_evaluate tool executes arbitrary JavaScript in the Electron main process. This is intentionally powerful for automation but should only be used in trusted environments. The main process has full Node.js and system access.
Environment Variable Passthrough
By default, all environment variables from the host process are passed to the launched Electron app. This can unintentionally expose secrets if the app logs or exposes environment variables. Prefer a sanitized environment or set specific variables via the config. Isolation is enabled by default; use --no-isolated only if you need real user data.
File Access
The electron_file_upload tool can read arbitrary local files. This is expected behavior for automation but worth noting when exposing this server to untrusted callers.
Requirements
- Node.js >= 18
- Electron >= 28 (peer dependency)
- Playwright >= 1.50
License
MIT
