MCP (Model Context Protocol) server for testing Electron applications using Playwright. Enables AI models like Claude to interact with and test your Electron apps.
# Run directly with npx
npx electron-test-mcp
# Or install globally
npm install -g electron-test-mcp
electron-test-mcp- Two Connection Modes
- CDP Mode: Connect to a running Electron app via Chrome DevTools Protocol
- Launch Mode: Launch a fresh Electron app instance for testing
- Full Playwright API: screenshot, click, fill, type, hover, press, wait, evaluate, and more
- Accessibility Snapshots: Get the accessibility tree for element discovery
- Main Process Access: Execute code in Electron's main process (launch mode only)
User <--> AI Model (Claude) <--> MCP Protocol <--> electron-test-mcp <--> Electron App
- User: "Click the login button and fill in the email field"
- AI Model: Determines which MCP tools to use
- MCP Protocol: Standardized communication
- electron-test-mcp: Executes Playwright commands on the Electron app
- Electron App: Actions are performed in the actual application
Add to your MCP configuration file:
{
"mcpServers": {
"electron-test": {
"command": "npx",
"args": ["electron-test-mcp"]
}
}
}{
"mcp": {
"electron-test": {
"type": "local",
"command": ["npx", "electron-test-mcp"],
"enabled": true
}
}
}Connect to an already running Electron app with remote debugging enabled:
# Start your Electron app with debugging port
electron your-app --remote-debugging-port=9222
# Or with electron-vite
electron-vite dev -- --remote-debugging-port=9222Then use the connect tool:
connect({ port: 9222 })
Advantages:
- Works with your existing dev workflow
- App state preserved between tests
- Hot reload still works
Launch a fresh Electron app instance:
launch({ appPath: "./out/main/index.js" })
# With headless mode for CI
launch({ appPath: "./out/main/index.js", headless: true })
Advantages:
- Clean state for each test
- Access to main process via
evaluateMain - Can pass custom environment variables
- Supports headless mode for CI/automation
Pass headless: true to run without a visible window:
launch({ appPath: "./out/main/index.js", headless: true })
Start your Electron app with headless flags before connecting:
# Option 1: Electron headless flag (Electron 28+)
electron your-app --headless=new --remote-debugging-port=9222
# Option 2: xvfb (Linux) - virtual framebuffer
xvfb-run electron your-app --remote-debugging-port=9222
# Option 3: xvfb with specific display (CI environments)
Xvfb :99 -screen 0 1920x1080x24 &
DISPLAY=:99 electron your-app --remote-debugging-port=9222Then connect normally:
connect({ port: 9222 })
| Tool | Description |
|---|---|
connect |
Connect to running app via CDP |
disconnect |
Disconnect from CDP (app keeps running) |
launch |
Launch new Electron app instance |
close |
Close launched app |
| Tool | Description |
|---|---|
click |
Click an element |
fill |
Fill text into input (clears first) |
type |
Type text character by character |
hover |
Hover over an element |
press |
Press keyboard key |
drag |
Drag and drop |
selectOption |
Select from dropdown |
| Tool | Description |
|---|---|
screenshot |
Take screenshot (returns base64 image) |
snapshot |
Get accessibility tree |
getText |
Get element text content |
getAttribute |
Get element attribute |
isVisible |
Check if element is visible |
count |
Count matching elements |
| Tool | Description |
|---|---|
wait |
Wait for element state |
evaluate |
Run JS in renderer process |
evaluateMain |
Run code in main process (launch mode only) |
Supports all Playwright selectors:
# CSS selectors
[data-testid="submit-btn"]
.my-class
#my-id
# Text selectors
text=Submit
text="Exact Match"
# Role selectors
role=button[name="Submit"]
# Combining
.form >> text=Submit
1. connect({ port: 9222 })
2. snapshot() // See the page structure
3. click('[data-testid="login-btn"]')
4. fill('[data-testid="email"]', 'test@example.com')
5. fill('[data-testid="password"]', 'password123')
6. click('text=Sign In')
7. wait({ selector: '[data-testid="dashboard"]' })
8. screenshot()
// Get app version
evaluateMain({
script: "({ app }) => app.getVersion()",
});
// Show dialog
evaluateMain({
script: "({ dialog }) => dialog.showMessageBox({ message: 'Hello!' })",
});You can ask Claude or other AI assistants to test your Electron app:
Connect to my Electron app running on port 9222 and:
1. Take a screenshot of the current state
2. Click the "Settings" button in the sidebar
3. Change the theme to dark mode
4. Verify the theme changed by checking the background color
- Add
data-testidattributes to important elements - Enable remote debugging in development:
--remote-debugging-port=9222 - Use semantic HTML for better accessibility snapshots
- Keep selectors stable - prefer
data-testidover classes
# Clone repository
git clone https://github.com/lazy-dinosaur/electron-test-mcp.git
cd electron-test-mcp
# Install dependencies
npm install
# Build
npm run build
# Run locally
node dist/index.jsContributions are welcome! Please feel free to submit a Pull Request.
Distributed under the MIT License. See LICENSE file for more information.
If you find this project useful, please consider giving it a ⭐️ on GitHub!