A Model Context Protocol (MCP) server that provides secure browser automation capabilities using Puppeteer. This server enables LLMs to interact with web pages, take screenshots, and execute JavaScript in a real browser environment with enterprise-grade security features.
🇪🇸 Versión en Español | 🇺🇸 English Version | 🤖 Agent Setup Guide
- Secure Web Navigation: Navigate only to whitelisted domains
- Screenshot Capture: Take screenshots with size limits and optimization
- Element Interaction: Click, fill forms, select options, and hover
- JavaScript Execution: Execute custom code in the browser context
- Console Monitoring: Capture and access browser console logs
- Flexible Configuration: Customizable Puppeteer launch options
- 🔒 Advanced Security: Rate limiting, timeouts, audit logging, and sandboxing
- 📊 Structured Logging: Complete audit trail of all operations
- 🐳 Secure Docker: Hardened container configuration
Being an MCP server, the primary way to use Puppeteer Server is through MCP client configuration:
{
"mcpServers": {
"puppeteer-server": {
"command": "npx",
"args": ["-y", "puppeteer-server"],
"env": {
"ALLOWED_ORIGINS": "https://example.com,https://*.trusted.org",
"PUPPETEER_LAUNCH_OPTIONS": "{ \"headless\": false, \"defaultViewport\": { \"width\": 1280, \"height\": 720 } }",
"ALLOW_DANGEROUS": "false"
}
}
}
}{
"mcpServers": {
"puppeteer-server-local": {
"command": "/opt/homebrew/bin/node",
"args": ["/absolute/path/to/puppeteer-server/dist/index.js"],
"env": {
"ALLOWED_ORIGINS": "https://github.com,https://*.github.io",
"MAX_SCREENSHOT_SIZE": "2097152",
"MAX_CONTENT_LENGTH": "1048576",
"TOOL_TIMEOUT": "30000",
"ALLOW_DANGEROUS": "false",
"PUPPETEER_LAUNCH_OPTIONS": "{ \"headless\": false, \"defaultViewport\": { \"width\": 1920, \"height\": 1080 } }"
}
}
}
}PUPPETEER_LAUNCH_OPTIONS: Launch options in JSON formatALLOWED_ORIGINS: Comma-separated list of allowed domainsALLOW_DANGEROUS: Allow dangerous arguments (true/false)MAX_SCREENSHOT_SIZE: Maximum screenshot size in bytesMAX_CONTENT_LENGTH: Maximum HTML content lengthTOOL_TIMEOUT: Timeout per tool operation in milliseconds
The server can run over HTTP using Server-Sent Events when MCP_TRANSPORT=http. Useful for n8n or other MCP clients that communicate over HTTP.
MCP_TRANSPORT: set tohttpto enable HTTP mode (defaults tostdio).PORT: listening port (default3333).MCP_BEARER: optional bearer token required inAuthorizationheader.ALLOWED_ORIGINS: comma-separated whitelist of allowedOriginheaders (*to allow any in development).MCP_BODY_LIMIT: max JSON body size accepted by/messages(default1mb).
pnpm build
MCP_TRANSPORT=http PORT=3333 node dist/index.jsVerify the SSE endpoint:
curl -I -H 'Accept: text/event-stream' http://localhost:3333/sseA basic health check is available at GET /health.
For STDIO mode (default):
pnpm build
npx @modelcontextprotocol/inspector --cli node dist/index.js --method tools/listFor local development and testing purposes:
# Use directly without installation
npx puppeteer-server# Clone and build the project
git clone https://github.com/tecnomanu/puppeteer-server.git
cd puppeteer-server
pnpm install
pnpm run buildpnpm run devBuild and run:
pnpm i
pnpm build
node dist/index.jsYou should see "Puppeteer MCP Server started successfully".
Test with MCP Inspector (UI):
npx @modelcontextprotocol/inspector node dist/index.jsOpens UI at http://localhost:6274; there you'll see tools/resources/prompts and can call them from the Tools tab. Usage examples and environment variable passing are in the inspector README. GitHub - modelcontextprotocol.io
Test with MCP Inspector (CLI):
npx @modelcontextprotocol/inspector --cli node dist/index.js --method tools/listYou should get the list of tools exposed by your server.
Navigate to a specific URL.
Parameters:
url(string, required): URL to navigate tolaunchOptions(object, optional): Puppeteer launch optionsallowDangerous(boolean, optional): Allow dangerous options
Take screenshots of pages or specific elements.
Parameters:
name(string, required): Name for the screenshotselector(string, optional): CSS selector for specific elementwidth(number, optional): Width in pixels (default: 800)height(number, optional): Height in pixels (default: 600)encoded(boolean, optional): Return as base64 data URI
Click on an element.
Parameters:
selector(string, required): CSS selector of the element
Fill input fields.
Parameters:
selector(string, required): CSS selector of the fieldvalue(string, required): Value to input
Select options in SELECT elements.
Parameters:
selector(string, required): CSS selector of the SELECT elementvalue(string, required): Value to select
Hover over an element.
Parameters:
selector(string, required): CSS selector of the element
Execute JavaScript in the browser console.
Parameters:
script(string, required): JavaScript code to execute
Wait for an element to appear.
Parameters:
selector(string, required): CSS selector of the elementtimeout(number, optional): Timeout in milliseconds (default: 30000)
Get the HTML content of the page.
Parameters:
selector(string, optional): Specific selector for partial content
Access to all browser console logs in text format.
Access to captured screenshots, identified by name.
This server implements multiple security layers to protect against attacks and malicious usage:
MANDATORY: Configure ALLOWED_ORIGINS to limit accessible domains:
# Production examples
export ALLOWED_ORIGINS="https://example.com,https://*.example.org,https://api.trusted-site.com"
# Development only (DO NOT use in production)
export ALLOWED_ORIGINS="*"- Maximum 30 requests per minute per tool
- Automatic protection against denial-of-service attacks
- Configurable via environment variables
export TOOL_TIMEOUT=30000 # 30s timeout per tool
export MAX_SCREENSHOT_SIZE=2097152 # 2MB max for screenshots
export MAX_CONTENT_LENGTH=1048576 # 1MB max for HTML contentArguments blocked by default (require ALLOW_DANGEROUS=true):
--no-sandbox,--disable-setuid-sandbox--single-process,--disable-web-security--ignore-certificate-errors--remote-debugging-port,--remote-debugging-address- Other security-reducing arguments
All logs are structured in JSON format for analysis:
{
"timestamp": "2024-01-01T12:00:00.000Z",
"level": "AUDIT",
"service": "puppeteer-server",
"toolName": "puppeteer_navigate",
"success": true,
"duration": 1250,
"resourceHash": "a1b2c3d4e5f6g7h8"
}Hardened Docker configuration included:
# Secure build
docker build -t puppeteer-server .
# Maximum security execution
docker run --cap-drop=ALL \
--security-opt=no-new-privileges:true \
--user 1001:1001 \
--read-only \
--tmpfs /tmp \
-e ALLOWED_ORIGINS="https://example.com" \
-e ALLOW_DANGEROUS=false \
puppeteer-server
# Or use docker-compose with security configuration
docker-compose -f docker-compose.security.yml up- NEVER use
ALLOWED_ORIGINS="*"in production - ALWAYS run in containers with non-privileged users
- AVOID
--no-sandboxarguments unless absolutely necessary - MONITOR audit logs regularly
- UPDATE dependencies regularly
The project includes a comprehensive test suite with 43 test cases:
- Unit Tests: Validation of security functions and individual tools
- Integration Tests: Complete MCP server verification
- Configuration Tests: Validation of configuration examples
# Run all tests
pnpm test
# Tests with code coverage
pnpm run test:coverage
# Development mode tests (watch)
pnpm run test:watchTests cover:
- ✅ Domain and origin validation
- ✅ Rate limiting and timeouts
- ✅ Hash generation and auditing
- ✅ Security configuration
- ✅ Individual MCP tools
- ✅ Error handling and exceptions
- ✅ Configuration example validation
The examples/ folder contains ready-to-use configurations:
| File | Description | Recommended Use |
|---|---|---|
mcp-config-example.json |
Basic configuration | Local development |
mcp-config-secure-example.json |
Secure configuration | Production |
docker-mcp-config.json |
With Docker hardening | Containers |
claude-desktop-config.json |
Optimized for Claude | Claude Desktop |
See examples/README.md for complete details on each configuration.
# Development with watch mode
pnpm run dev
# Linting and code formatting
pnpm run lint # Fix errors automatically
pnpm run lint:check # Only check errors
pnpm run format # Format code with Prettier
pnpm run format:check # Check formatting
# Testing
pnpm test # Run all tests
pnpm run test:watch # Tests in watch mode
pnpm run test:coverage # Tests with coverage report
# Build
pnpm run build- ESLint: Static analysis with security rules
- Prettier: Consistent code formatting
- Jest: Testing framework with coverage
- Husky: Pre-commit hooks for quality
- TypeScript: Static typing and compilation
Contributions are welcome! Please follow our process:
- Fork → create feature branch (
feat/your-feature) - Test → run
pnpm test& ensure all checks pass - Document → update docs and add examples if needed
- PR → open with context: why + screenshots/logs
📋 Please read our Contributing Guide and Code of Conduct before contributing.
All discussions happen on GitHub Issues.
- Verify Chrome/Chromium is installed
- Check execution permissions
- Review launch options
- Increase timeout value in
puppeteer_wait_for_selector - Verify the page loads correctly
- Check network connectivity
- Ensure the page is fully loaded
- Verify the CSS selector is correct
- Check viewport dimensions
- Spanish documentation: README_es.md
- Agent setup guide: README_FOR_AGENTS.md
- Project repository: https://github.com/tecnomanu/puppeteer-server
- MCP Protocol: https://modelcontextprotocol.io/
MIT – do whatever you want, just keep the copyright.
Happy coding! 💙
🇦🇷 Made with ❤️ in Argentina
