Electro Puppeteer
FreeNot checkedMCP and HTTP API to navigate and fetch through isolated puppeteer contexts locally
About
MCP and HTTP API to navigate and fetch through isolated puppeteer contexts locally
README
A powerful Electron application that provides both HTTP REST API and Model Context Protocol (MCP) interfaces for managing browser automation sessions using Puppeteer. Enables programmatic control of browser windows with full Chrome DevTools Protocol access.
Overview
This project combines:
- Electron - Provides native browser window management
- Puppeteer - Enables Chrome DevTools Protocol automation
- Express - RESTful HTTP API server
- MCP - Model Context Protocol for AI agent integration
Features
- 🌐 Multi-Session Management - Create and manage multiple isolated browser sessions with unique IDs
- 🔌 Dual Interface - Access via HTTP REST API or MCP protocol
- 🚀 Real Browser Automation - Full Puppeteer capabilities with actual Chrome rendering
- 📊 System Monitoring - Built-in status endpoint for health checks
- 🎯 Session Isolation - Each session maintains independent state and context
Installation
# Install dependencies
npm install
# Build the project
npm run build
# Start the server
npm start
API Documentation
HTTP REST API
All HTTP endpoints are available at http://localhost:3000
Create Session
Creates a new browser session with an optional initial URL.
Endpoint: POST /sessions
Request Body:
{
"initialUrl": "https://example.com" // optional
}
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000"
}
Example:
curl -X POST http://localhost:3000/sessions \
-H "Content-Type: application/json" \
-d '{"initialUrl": "https://example.com"}'
Navigate Session
Navigates an existing session to a new URL.
Endpoint: POST /sessions/:id/navigate
Request Body:
{
"url": "https://example.com/?q=search"
}
Response: 200 OK
{
"success": true,
"message": "Navigated to https://example.com/?q=search",
"currentUrl": "https://example.com/?q=search"
}
Error Response: 404 Not Found
{
"success": false,
"message": "Session not found"
}
Example:
curl -X POST http://localhost:3000/sessions/{SESSION_ID}/navigate \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
Delete Session
Closes and removes a browser session.
Endpoint: DELETE /sessions/:id
Response: 200 OK
{
"success": true,
"message": "Browser session closed successfully"
}
Error Response: 404 Not Found
{
"success": false,
"message": "Session not found"
}
Example:
curl -X DELETE http://localhost:3000/sessions/{SESSION_ID}
Capture Screenshot
Captures a PNG screenshot of the current page in a session.
Endpoint: GET /sessions/:id/screenshot
Response: 200 OK
- Content-Type:
image/png - Body: Binary PNG image data
Error Response: 404 Not Found
{
"success": false,
"message": "Session not found"
}
Example:
curl -X GET http://localhost:3000/sessions/{SESSION_ID}/screenshot \
--output screenshot.png
Fetch (Renderer Network Request)
Performs a network request from the renderer process and returns a Response-like payload.
Endpoint: POST /sessions/:id/fetch
Request Body:
{
"url": "https://example.com/api",
"method": "POST",
"headers": {"content-type": "application/json"},
"body": "eyJmb28iOiJiYXIifQ==",
"bodyEncoding": "base64"
}
Any standard Request fields may be provided: method, headers, body (as UTF-8 string or base64 with bodyEncoding), redirect, credentials, cache, mode, referrer, referrerPolicy, integrity, keepalive.
Response: 200 OK
{
"ok": true,
"status": 200,
"statusText": "OK",
"url": "https://example.com/api",
"redirected": false,
"type": "basic",
"headers": {"content-type": "application/json"},
"bodyBase64": "eyJmb28iOiJiYXIifQ=="
}
Decode bodyBase64 to get the raw bytes of the response body.
Health Status
Returns server health metrics and session information.
Endpoint: GET /status
Response: 200 OK
{
"uptime": 42,
"memoryUsage": {
"rss": 123456789,
"heapTotal": 98765432,
"heapUsed": 87654321,
"external": 1234567
},
"browser": {
"isOpen": true
},
"sessions": {
"active": 2
},
"timestamp": "2025-10-25T10:44:15.000Z"
}
Example:
curl http://localhost:3000/status
Quit Daemon
Gracefully shuts down the daemon by closing all browser windows, stopping the HTTP server, and exiting the Electron app with status code 0.
Endpoint: POST /quit
Response: 200 OK
{
"success": true,
"message": "Shutting down daemon"
}
Example:
curl -X POST http://localhost:3000/quit
Note: This endpoint is useful for programmatic shutdown, especially in test environments. The daemon will close all active sessions, stop the HTTP server, and exit cleanly.
MCP Protocol
The MCP endpoint is available at http://localhost:3000/mcp and follows the JSON-RPC 2.0 specification with Server-Sent Events (SSE) responses.
Available Tools
open_browser
Opens a new browser session with an optional initial URL.
Input Schema:
{
initialUrl?: string // Optional URL to load initially
}
Output:
{
"success": true,
"message": "Browser session opened successfully",
"id": "550e8400-e29b-41d4-a716-446655440000"
}
Example Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "open_browser",
"arguments": {
"initialUrl": "https://example.com"
}
}
}
close_browser
Closes an existing browser session.
Input Schema:
{
id: string // Session ID to close
}
Output:
{
"success": true,
"message": "Browser session closed successfully"
}
Example Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "close_browser",
"arguments": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
}
navigate_to_url
Navigates a browser session to a specific URL.
Input Schema:
{
id: string, // Session ID
url: string // URL to navigate to
}
Output:
{
"success": true,
"message": "Navigated to https://example.com",
"currentUrl": "https://example.com"
}
Example Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "navigate_to_url",
"arguments": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com/?q=1"
}
}
}
take_screenshot
Captures a PNG screenshot of the current page in a session.
Input Schema:
{
id: string // Session ID
}
Output:
{
"success": true,
"message": "Screenshot captured successfully",
"mimeType": "image/png",
"dataBase64": "iVBORw0KGgoAAAANSUhEUgAA..."
}
Example Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "take_screenshot",
"arguments": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
}
The response includes the screenshot as a base64-encoded PNG string in both the content array (as text) and in the structuredContent object with additional metadata.
fetch_page_content
Status: Not Implemented
Returns an error indicating the feature is not yet implemented.
Output:
{
"success": false,
"message": "Not implemented"
}
Project Structure
electro-puppeteer-mcp/
├── index.ts # Main application file
│ ├── Session Management # Map-based session storage with UUID keys
│ ├── HTTP Routes # Express REST API endpoints
│ ├── MCP Server # Model Context Protocol implementation
│ └── Electron Setup # App initialization and lifecycle
├── tests/
│ ├── http.test.ts # Integration tests for HTTP API
│ └── mcp.test.ts # Integration tests for MCP protocol
├── agents/ # Agent planning and artifacts
│ └── routes.plan.md # Refactoring plan documentation
├── dist/ # Compiled TypeScript output
├── package.json # Project dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── biome.json # Biome linter/formatter configuration
Key Components
Session Management
- Sessions stored in
Map<string, { window: BrowserWindow, page: puppeteer.Page }> - UUID-based session identifiers using
crypto.randomUUID() - Lazy browser initialization on first session creation
- Graceful window cleanup with
window.close()
Browser Operations
Core functionality shared between HTTP and MCP interfaces:
open(initialUrl?)- Create new sessionclose(id)- Remove sessionnavigate(id, url)- Load URL in sessionscreenshot(id)- Capture PNG screenshotfetch(id)- (Not implemented) Extract page content
Server Architecture
- Puppeteer-in-Electron (PIE) initialized before app ready
- Express server starts after Electron ready
- Window-all-closed handler prevents app quit (server mode)
- Port 3000 for both HTTP and MCP endpoints
Useful Commands
Development
# Build TypeScript to JavaScript
npm run build
# Start the Electron application
npm start
# Stop the application
npm stop
# Run in development (build + start)
npm run build && npm start
Testing
# Run all integration tests
npm test
# Tests use real Electron/Puppeteer - no mocking
# Both test suites run sequentially with actual server instances
Code Quality
# Check linting and formatting
npm run lint
# Auto-format code
npm run format
# Biome handles both linting and formatting
Process Management
# Kill any stuck Electron processes
pkill -f 'electron dist/index.js'
# Check if server is running
curl http://localhost:3000/status
Session Lifecycle Example
HTTP API Flow
# 1. Start server
npm start
# 2. Create a new session
SESSION_ID=$(curl -s -X POST http://localhost:3000/sessions \
-H "Content-Type: application/json" \
-d '{"initialUrl": "https://example.com"}' \
| jq -r '.id')
echo "Created session: $SESSION_ID"
# 3. Navigate to a different page
curl -X POST http://localhost:3000/sessions/$SESSION_ID/navigate \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/?q=search"}'
# 4. Capture a screenshot
curl -X GET http://localhost:3000/sessions/$SESSION_ID/screenshot \
--output screenshot.png
# 5. Check server status
curl http://localhost:3000/status | jq
# 6. Close the session
curl -X DELETE http://localhost:3000/sessions/$SESSION_ID
# 7. Verify session is closed
curl http://localhost:3000/status | jq '.sessions.active'
MCP Protocol Flow
# 1. List available tools
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}'
# 2. Open browser with MCP
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "open_browser",
"arguments": {"initialUrl": "https://example.com"}
}
}'
Technical Notes
Electron + Puppeteer Integration
- PIE (Puppeteer-in-Electron) must call
pie.initialize(app)beforeapp.whenReady() - Browser windows are real Electron
BrowserWindowinstances - Puppeteer pages connected via Chrome DevTools Protocol
- Full access to page evaluation, network interception, and automation
WSL2 Considerations
DBUS errors in WSL2 are expected and don't affect functionality:
ERROR:dbus/bus.cc:408] Failed to connect to the bus
These errors are cosmetic - Electron runs fine without DBUS in WSL2.
Test Architecture
- Real Integration Tests - No mocking, actual Electron processes
- Sequential Execution - Tests run one at a time to avoid port conflicts
- Server Lifecycle - Each test suite starts/stops the server
- Timing-Safe - 2-second startup delay ensures server is ready
Configuration
Port Configuration
Default port is 3000. To change, modify index.ts:
const port = 3000
Browser Options
Customize Electron BrowserWindow options in browserOperations.open():
const window = new BrowserWindow({
width: 1280,
height: 720,
// Add more options here
})
Troubleshooting
Server won't start
# Check if port 3000 is in use
lsof -i :3000
# Kill any existing processes
npm stop
Tests failing
# Ensure no server is running
npm stop
# Clean build and retry
rm -rf dist/
npm run build
npm test
Memory Issues
Monitor session count and close unused sessions:
curl http://localhost:3000/status | jq '.sessions.active'
Contributing
- Follow TypeScript strict mode guidelines
- Use Biome for code formatting (
npm run format) - Ensure all tests pass (
npm test) - No mocking in tests - use real integration tests
- Update README for new features or API changes
License
See LICENSE file for details.
Related Technologies
- Electron - Cross-platform desktop applications
- Puppeteer - Headless Chrome automation
- Puppeteer-in-Electron - PIE integration
- Express - Web framework for Node.js
- Model Context Protocol - MCP specification
- Biome - Fast linter and formatter
- Vitest - Fast unit test framework
Installing Electro Puppeteer
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/3p3r/electro-puppeteer-mcpFAQ
Is Electro Puppeteer MCP free?
Yes, Electro Puppeteer MCP is free — one-click install via Unyly at no cost.
Does Electro Puppeteer need an API key?
No, Electro Puppeteer runs without API keys or environment variables.
Is Electro Puppeteer hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Electro Puppeteer in Claude Desktop, Claude Code or Cursor?
Open Electro Puppeteer on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
Playwright
Browser automation, scraping, screenshots
by MicrosoftPuppeteer
Browser automation and web scraping.
by modelcontextprotocolopentabs-dev/opentabs
Plugin-based MCP server + Chrome extension that gives AI agents access to web applications through the user's authenticated browser session. 100+ plugins with a
by opentabs-devrobhunter/agentdeals
1,500+ developer infrastructure deals, free tiers, and startup programs across 54 categories. Search deals, compare vendors, plan stacks, and track pricing chan
by robhunterCompare Electro Puppeteer with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All browse MCPs
