⚡ Electron Debug MCP
Debug Electron apps from Cursor & Claude with real DevTools superpowers.
Model Context Protocol server · Chrome DevTools Protocol · start / attach / screenshot / console / DOM / UI automation / tracing
🌟 Overview
Electron Debug MCP is a local MCP server that gives AI coding agents eyes, hands, and Chrome DevTools inside your Electron app.
Instead of guessing from source alone, the agent can:
It speaks MCP over stdio (Cursor / Claude Desktop friendly), bridges to Chrome DevTools Protocol, buffers console + network on monitored page targets, and keeps stdout clean (all server logs go to stderr).
👤 Who it’s for
- 🧑💻 Cursor / Claude users pair-programming on Electron desktop apps
- 🐛 Maintainers tired of “white screen / silent exception” bugs agents can’t see
- 🧰 Tooling authors who need a stdio MCP ↔ CDP bridge for Electron/Chromium
💬 Example things you can ask the agent
“Start D:/apps/my-app on port 9222 and tell me if the renderer threw on boot.”
“Find my running Electron app, attach by PID, screenshot #sidebar, and dump localStorage.”
“Type into #email, press Enter, wait for Welcome, then list console errors.”
“Start a CDP trace, click through settings, stop tracing, and save the JSON.”
“Diagnose why this Electron window is blank.”
📊 At a glance
✅ Status
- 🟢 Ready for local agent-driven Electron debugging
- 🟢 E2E smoke: start → UI/automation → storage/cookies → tracing → find/attach-by-pid → stop
- 🟢 Windows binary repair:
scripts/fix-electron.cmd when npm blocks postinstall
- 🟢 v1.5.0 — element screenshots, cookies/storage, tracing, attach-by-pid
- 🟢 Built on TypeScript 7 (native Go compiler) — ~10x faster builds
📖 Table of contents
✨ Why this exists
Electron bugs are often invisible to coding agents:
🚀 Feature tour
⚡ 60-second quick start
git clone https://github.com/amafjarkasi/electron-mcp-server.git
cd electron-mcp-server
npm install
npm run ensure-electron
npm run build
npm test
🪟 Windows binary missing?
If npm warns about allowScripts / Electron postinstall:
.\scripts\fix-electron.cmd
That reinstalls Electron, extracts electron.exe with system tar, then runs tests.
🖥️ Cursor & Claude Desktop setup
Cursor
npm run build
- Open Cursor → MCP settings
- Add (use your absolute path):
Windows
{
"mcpServers": {
"electron-debug": {
"command": "node",
"args": ["C:/Users/you/code/electron-mcp-server/build/index.js"]
}
}
}
macOS / Linux
{
"mcpServers": {
"electron-debug": {
"command": "node",
"args": ["/Users/you/code/electron-mcp-server/build/index.js"],
"env": {
"ELECTRON_MCP_NO_SANDBOX": "1"
}
}
}
}
- Restart Cursor
- Confirm tools:
start_app, attach, find_apps, screenshot, get_console_messages, click, start_tracing, …
📄 Template: examples/cursor-mcp.json
Claude Desktop
Same mcpServers block in claude_desktop_config.json, pointing at build/index.js. Edit the file at:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Windows:
%APPDATA%\Claude\claude_desktop_config.json
- Linux:
~/.config/Claude/claude_desktop_config.json
📄 Template: examples/claude-desktop-config.json
⚠️ Don’t run node build/index.js in a normal terminal for daily use — it waits on stdio for an MCP client. Let Cursor/Claude spawn it.
🧩 How it works
┌──────────────────────────┐
│ Cursor / Claude / MCP │
│ client (agent) │
└────────────┬─────────────┘
│ stdio JSON-RPC
▼
┌──────────────────────────┐
│ Electron Debug MCP │
│ 🛠️ tools (36) │
│ 📡 resources │
│ 💬 prompts │
│ 📣 logging / list-changed│
└────────────┬─────────────┘
│ spawn / attach / PID resolve
│ CDP WebSocket
▼
┌──────────────────────────┐
│ Electron application │
│ --remote-debugging-port │
│ Runtime·Page·Network·… │
│ optional --inspect (main)│
└──────────────────────────┘
After start_app / attach / attach_by_pid, page targets get Runtime / Log / Network / Page enabled so console + network events keep buffering between tool calls.
Finding a running app
find_apps — OS process scan (Electron PIDs + --remote-debugging-port from argv)
discover_apps — HTTP probe of local CDP ports (/json/version, /json/list)
attach / attach_by_pid — open a managed session (detach-only on stop_app)
All APIs below are MCP tools. Schemas match the live Zod definitions in src/index.ts.
🚀 Lifecycle
start_app
Launch Electron with remote debugging.
Auto flags: --remote-debugging-port, --enable-logging, --disable-gpu, and --no-sandbox when ELECTRON_MCP_NO_SANDBOX=1 / CI=true / no DISPLAY.
Returns: id, pid, debugPort, targets, attached: false, …
attach
stop_app on attached sessions detaches only (does not kill the external app).
attach_by_pid
Attach by OS process id. Resolves --remote-debugging-port from the process command line (Linux/macOS/ps, Windows PowerShell). Falls back to listening sockets owned by the PID on Linux when needed.
Tip: Prefer the main process PID from find_apps (helpers with --type=renderer / gpu-process are filtered unless they expose a debug port).
find_apps
List running Electron-like processes.
Returns: { apps: [{ pid, command, debugPort?, inspectPort?, likelyElectron }], count }
Use this when you launched the app yourself and don’t remember the port.
discover_apps
HTTP-probes each port for Chromium/Electron DevTools (/json/version + /json/list).
stop_app — { processId }
list_apps — no params
diagnose — optional { processId } (omit = all sessions)
diagnose reports port reachability, target role counts, recent console errors, and monitoring state.
🔍 Inspection
screenshot / save_screenshot
screenshot returns MCP image content (+ JSON meta including clip when used).
save_screenshot writes bytes to disk and returns { path, bytes, mimeType, clip? }.
get_dom — { processId, selector?, targetId? }
query_selector — { processId, selector, targetId?, limit?=20 }
evaluate
evaluate_main
Evaluate in the Electron main/node CDP target.
Requires a node-like target — start with inspectMain: true, or pass an explicit targetId from list_targets.
get_cookies
set_cookie
Note: Chromium often rejects cookies on file:// pages — use an http(s) URL or pass an explicit url/domain.
get_storage / set_storage
get_console_messages — { processId, tail?, level? }
get_network_log — { processId, tail? }
get_logs — { processId, tail? }
list_targets — { processId? }
page_info — { processId, targetId? } → url / title / readyState / userAgent
Console capture includes console.*, CDP Log entries, and Runtime.exceptionThrown.
🖱️ Interaction & control
navigate — { processId, url, targetId?, waitUntilLoad?=true, timeoutMs?=15000 }
wait_for
Provide at least one condition:
type_text — { processId, text, selector?, clear?, pressEnter?, targetId? }
press_key
set_console_live — { enabled }
Errors/asserts always emit MCP logs. When enabled, log/info/warn/debug also stream live.
reload — { processId, targetId?, ignoreCache?=false }
pause / resume — { processId, targetId? }
clear_buffers — { processId, console?=true, network?=true, logs?=false }
🧰 Power / tracing
start_tracing
Only one active trace per process session.
stop_tracing
Returns: { path, eventCount, elapsedMs, targetId, … }
Open the file in Chrome’s chrome://tracing (or Perfetto UI).
cdp_command — { processId, method:"Domain.method", targetId?, params? }
Escape hatch for any DevTools method not wrapped above.
📡 Resources (read-only)
💬 Prompts
📚 Usage examples
1️⃣ Start app → read title
// tool: start_app
{
"appPath": "D:/apps/my-electron-app",
"debugPort": 9222,
"extraArgs": ["--no-sandbox"]
}
// tool: evaluate
{
"processId": "electron-1710000000000",
"expression": "document.title"
}
2️⃣ Attach to a running app (port)
electron . --remote-debugging-port=9222
// tool: attach
{ "debugPort": 9222, "name": "my-app" }
3️⃣ Find by PID → attach
// tool: find_apps
{}
// tool: attach_by_pid
{ "pid": 43210, "name": "my-app" }
4️⃣ Catch console errors (+ live stream)
// tool: set_console_live
{ "enabled": true }
// tool: get_console_messages
{
"processId": "electron-1710000000000",
"level": "error",
"tail": 50
}
Also: resource electron://console/{processId}
5️⃣ Screenshot — full page, file, or element
// tool: screenshot
{ "processId": "electron-…", "format": "png" }
// tool: save_screenshot
{
"processId": "electron-…",
"path": "D:/tmp/app.png",
"format": "png"
}
// tool: save_screenshot (element clip)
{
"processId": "electron-…",
"path": "D:/tmp/sidebar.png",
"selector": "#sidebar"
}
6️⃣ UI automation flow
// wait_for
{ "processId": "electron-…", "selector": "#email", "timeoutMs": 8000 }
// type_text
{
"processId": "electron-…",
"selector": "#email",
"text": "[email protected]",
"clear": true
}
// press_key
{ "processId": "electron-…", "key": "Enter" }
// click
{ "processId": "electron-…", "selector": "button[type=submit]" }
// wait_for (richer conditions)
{
"processId": "electron-…",
"text": "Welcome",
"timeoutMs": 8000,
"screenshotOnTimeout": true
}
// wait_for enabled / count / hidden
{ "processId": "electron-…", "enabled": "#submit" }
{
"processId": "electron-…",
"countSelector": ".row",
"minCount": 3
}
{ "processId": "electron-…", "hidden": ".spinner" }
7️⃣ Cookies & storage
// set_storage
{
"processId": "electron-…",
"kind": "localStorage",
"clear": true,
"entries": { "theme": "dark", "onboardingDone": "1" }
}
// get_storage
{ "processId": "electron-…", "kind": "localStorage" }
// set_cookie
{
"processId": "electron-…",
"name": "session",
"value": "abc",
"url": "https://app.local/"
}
// get_cookies
{ "processId": "electron-…", "urls": ["https://app.local/"] }
8️⃣ Main-process evaluate
// start_app with inspectMain
{
"appPath": "D:/apps/my-electron-app",
"debugPort": 9222,
"inspectMain": true
}
// evaluate_main
{
"processId": "electron-…",
"expression": "process.versions.electron"
}
// start_tracing
{ "processId": "electron-…" }
…reproduce the slow interaction (click / navigate / wait_for)…
// stop_tracing
{
"processId": "electron-…",
"path": "D:/tmp/app-trace.json"
}
Open app-trace.json in chrome://tracing.
🔟 Diagnose a sick session
// tool: diagnose
{ "processId": "electron-1710000000000" }
1️⃣1️⃣ Navigate + page info
// navigate
{
"processId": "electron-…",
"url": "file:///path/to/renderer/settings.html",
"waitUntilLoad": true
}
// page_info
{ "processId": "electron-…" }
1️⃣2️⃣ Raw CDP escape hatch
// cdp_command
{
"processId": "electron-…",
"method": "Page.captureScreenshot",
"params": { "format": "png", "fromSurface": true }
}
1️⃣3️⃣ Recommended agent loop
find_apps / discover_apps / start_app / attach / attach_by_pid
→ diagnose
→ set_console_live(true) # optional
→ get_console_messages(level="error")
→ screenshot / save_screenshot(selector?)
→ wait_for (if UI)
→ click / type_text / press_key / evaluate / get_dom
→ get_storage / get_cookies # if state matters
→ start_tracing … stop_tracing # if perf
→ stop_app
🔐 Configuration
Environment variables
Path allowlist example
$env:ELECTRON_MCP_ALLOWED_ROOTS="D:\apps;D:\GH"
📜 npm scripts
Windows helpers: scripts/fix-electron.cmd · scripts/fix-electron.ps1
🧪 Testing
npm test
Smoke path (v1.5):
initialize → tool/prompt/resource lists → start_app → evaluate → console/network/DOM → page_info / type_text / click / wait_for / press_key → save_screenshot (+ selector clip) → storage / cookies → start/stop_tracing → find_apps / attach_by_pid → screenshot → diagnose → attach → discover → stop
CI: .github/workflows/ci.yml (Ubuntu + Xvfb).
🗂️ Project layout
electron-mcp-server/
├── assets/logo.svg · logo.png
├── examples/cursor-mcp.json · claude-desktop-config.json
├── fixtures/minimal-electron-app/
├── scripts/ensure-electron.mjs · fix-electron.cmd · fix-electron.ps1
├── src/index.ts · process-manager.ts · events.ts · log.ts
├── src/types/chrome-remote-interface.d.ts
├── test/mcp-smoke.mjs · unit-helpers.test.mjs
├── .github/workflows/ci.yml
└── README.md · LICENSE · package.json · tsconfig.json
🛡️ Security
- Can launch local binaries, evaluate JS in app contexts, read page content, cookies, and storage — treat as a powerful local debugger.
- Use
ELECTRON_MCP_ALLOWED_ROOTS on shared machines.
save_screenshot / stop_tracing reject writes to sensitive locations (~/.ssh, /etc, /proc, /usr, C:\Windows, C:\Program Files, …). Set ELECTRON_MCP_OUTPUT_ROOTS to further restrict output to specific directories.
- Don’t expose stdio over an open network without auth.
- Only
attach / attach_by_pid to apps you trust (remote debugging is powerful).
- In-memory console/network buffers and exported traces may contain secrets from the app under test.
🧯 Troubleshooting
🤝 Contributing
- Fork + branch
npm test
- PR with tool/behavior notes
- Keep stdout MCP-clean (log to stderr only)
📄 License
ISC © Electron Debug MCP contributors

Built for agents that need eyes — and hands — inside Electron.