MCP server for Browserious — browser-as-a-service for AI agents
Project description
Browserious - Browser API Wrapper
Self-hosted, API-controlled browser-as-a-service for automation, testing, and web scraping.
Overview
Browserious provides a REST API + WebSocket interface to control Chromium browsers running in Docker containers. Each browser session runs in an isolated container with:
- Persistent Profiles - Maintain cookies, localStorage, and session state
- Proxy Support - Configure HTTP/HTTPS/SOCKS5 proxies per session
- Extensions - Load custom Chrome extensions
- Request Interception - Block, redirect, or mock network requests
- Remote Viewing - Watch browser sessions via VNC
- CDP Access - Direct Chrome DevTools Protocol control
Primary Use Cases:
- Browser automation and E2E testing
- Web scraping and data extraction
- Remote browser service
Quick Start
Prerequisites
- Docker and Docker Compose
- Python 3.11+ (for development)
Installation
# Clone repository
git clone https://github.com/muzhig/browserious.git
cd browserious
# Generate API key
export API_KEYS=$(openssl rand -base64 32)
# Start service
docker-compose up -d
# Verify
curl -H "X-API-Key: $API_KEYS" http://localhost:8100/sessions
Create Your First Session
# Create browser session
SESSION_ID=$(curl -X POST http://localhost:8100/sessions \
-H "X-API-Key: $API_KEYS" \
-H "Content-Type: application/json" \
-d '{"timeout": 600}' \
| jq -r '.session_id')
# Navigate to a page
curl -X POST http://localhost:8100/sessions/$SESSION_ID/pages/page-0/goto \
-H "X-API-Key: $API_KEYS" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
# Take screenshot
curl -H "X-API-Key: $API_KEYS" \
http://localhost:8100/sessions/$SESSION_ID/pages/page-0/screenshot \
> screenshot.png
# Watch in browser (VNC)
# Open the web_vnc_url from the session response, e.g.:
# http://localhost:8100/vnc.html?session=$SESSION_ID
# Cleanup
curl -X DELETE http://localhost:8100/sessions/$SESSION_ID \
-H "X-API-Key: $API_KEYS"
Architecture
┌─────────────────────────────────────────────────────────┐
│ API Container (browserious-api) │
│ ┌───────────────────────────────────────────────────┐ │
│ │ FastAPI Application :8100 │ │
│ │ - REST API + WebSocket │ │
│ │ - VNC WebSocket proxy /sessions/{id}/vnc │ │
│ │ - Web VNC viewer /vnc.html?session={id} │ │
│ │ - Docker API (creates/manages browser nodes) │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ Docker Network: browserious
▼
┌─────────────────────────────────────────────────────────┐
│ Browser Node Containers (one per session) │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ session-abc123 │ │ session-xyz789 │ ... │
│ │ │ │ │ │
│ │ Xvfb :99 │ │ Xvfb :99 │ │
│ │ x11vnc :5900 │ │ x11vnc :5900 │ │
│ │ Chromium │ │ Chromium │ │
│ │ CDP :9222 │ │ CDP :9222 │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ (No port conflicts - each node uses same internal │
│ ports, addressed by container hostname/IP) │
└─────────────────────────────────────────────────────────┘
Features
✅ Session Management
- Create isolated browser sessions
- Configure proxy, viewport, user agent
- Persistent profiles with cookie/storage management
- Automatic timeout and cleanup
✅ Page Operations
- Navigate, click, type, fill forms
- Multiple selector strategies (CSS, XPath, Playwright, JS)
- Wait for elements (visibility, loading states)
- Execute JavaScript in page context
- Screenshots (full page or viewport)
- HTML content extraction
✅ Request Interception
- Block requests (ads, trackers, images)
- Redirect URLs (mock APIs, override media)
- Override responses (status, headers, body)
- Inspect and capture requests
✅ Extensions
- Upload custom Chrome extensions
- Load extensions per session
- Support for .zip and .crx formats
✅ Remote Access
- VNC server with web client (noVNC)
- Per-session password protection
- Real-time browser viewing
✅ CDP WebSocket
- Direct Chrome DevTools Protocol access
- Compatible with Puppeteer/Playwright
- Full browser control for advanced use cases
Documentation
| Document | Description |
|---|---|
| PRD | Product Requirements Document - features, use cases, MVP scope |
| ADR | Architecture Decision Records - key technical decisions and rationale |
| API | Complete API Reference - endpoints, examples, error codes |
| EXAMPLES | Code examples - form interaction, content extraction, visual debugging |
| SECURITY | Security Analysis - threat model, hardening, best practices |
| Project Brief | Original project specification |
MCP Server for Claude Code
Browserious includes an MCP (Model Context Protocol) server for integration with Claude Code and other AI assistants.
Setup
Install:
pip install browserious
# or run without installing:
uvx browserious
Add to your Claude Code, Cursor, or Claude Desktop config:
{
"mcpServers": {
"browserious": {
"command": "uvx",
"args": ["browserious"],
"env": {
"BROWSERIOUS_API_URL": "https://api.browserious.com",
"BROWSERIOUS_API_KEY": "<your-api-token>"
}
}
}
}
The MCP server runs locally on your machine. It uses the API for session lifecycle (create/delete) and connects directly to browser containers for all operations — no proxy overhead.
Available Tools
The MCP server exposes 20 tools:
| Tool | Description |
|---|---|
create_session |
Create browser session, returns session_id and URLs |
delete_session |
Close and cleanup session |
list_sessions |
List all active sessions |
create_page |
Open new tab, optionally navigate to URL |
page_goto |
Navigate to URL |
page_click |
Click element (CSS, XPath, text, role, JS selectors) |
page_type |
Type text with keyboard events |
page_fill |
Fill input instantly |
page_eval |
Execute JavaScript, return result |
page_wait_for_selector |
Wait for element state |
page_content |
Get full HTML |
page_screenshot |
Capture page, save to file, return path |
display_screenshot |
Capture X11 display with cursor |
play_input |
Hardware-level mouse/keyboard via X11 |
get_cursor_position |
Get current cursor screen coordinates |
Screenshot Handling
Screenshots are saved to files and the path is returned, allowing multimodal AI to view them:
# MCP tool returns: {"file_path": "/tmp/screenshot_abc123.png", "size_bytes": 45678}
# AI can then read the image file directly
Coordinate System
For play_input, convert viewport coordinates to screen coordinates:
screen_x = viewport_x + screenX
screen_y = viewport_y + screenY + chromeHeight
Get these values from window_info in the session response or via page_eval:
({
screenX: window.screenX,
screenY: window.screenY,
chromeHeight: window.outerHeight - window.innerHeight
})
API Examples
Web Scraping with Proxy
import requests
API_KEY = "your-api-key"
BASE_URL = "http://localhost:8100"
headers = {"X-API-Key": API_KEY}
# Create session with proxy
session = requests.post(
f"{BASE_URL}/sessions",
headers=headers,
json={
"profile_id": "scraper-001",
"proxy": {"server": "http://proxy.example.com:8080"},
"timeout": 3600
}
).json()
session_id = session["session_id"]
# Block images to speed up scraping
requests.post(
f"{BASE_URL}/sessions/{session_id}/routes",
headers=headers,
json={
"pattern": "**/*.{png,jpg,jpeg,gif}",
"action": {"type": "block"}
}
)
# Navigate and extract data
requests.post(
f"{BASE_URL}/sessions/{session_id}/pages/page-0/goto",
headers=headers,
json={"url": "https://example.com"}
)
data = requests.post(
f"{BASE_URL}/sessions/{session_id}/pages/page-0/eval",
headers=headers,
json={"script": "return document.querySelectorAll('.item').length"}
).json()
print(f"Found {data['result']} items")
# Cleanup
requests.delete(f"{BASE_URL}/sessions/{session_id}", headers=headers)
E2E Testing with Mocked API
# Create test session
session = requests.post(
f"{BASE_URL}/sessions",
headers=headers,
json={"profile_id": "test-user"}
).json()
session_id = session["session_id"]
# Mock API response
requests.post(
f"{BASE_URL}/sessions/{session_id}/routes",
headers=headers,
json={
"pattern": "**/api/user",
"action": {
"type": "override",
"status": 200,
"body": '{"id": 123, "name": "Test User"}'
}
}
)
# Run test
requests.post(
f"{BASE_URL}/sessions/{session_id}/pages/page-0/goto",
headers=headers,
json={"url": "https://app.example.com"}
)
# Interact with page
requests.post(
f"{BASE_URL}/sessions/{session_id}/pages/page-0/click",
headers=headers,
json={"selector": {"strategy": "css", "value": "#login-button"}}
)
# Capture screenshot on failure
screenshot = requests.get(
f"{BASE_URL}/sessions/{session_id}/pages/page-0/screenshot",
headers=headers,
params={"full_page": True}
).content
with open("test-failure.png", "wb") as f:
f.write(screenshot)
Using Puppeteer via CDP
const puppeteer = require('puppeteer-core');
// Connect to existing session via CDP
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://localhost:8100/sessions/{session_id}/cdp'
});
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log('Page title:', title);
await page.screenshot({path: 'screenshot.png'});
Configuration
Environment Variables
| Variable | Default | Description |
|---|---|---|
API_KEYS |
- | Comma-separated API keys (required) |
PROFILES_DIR |
/data/profiles |
Profile storage directory |
EXTENSIONS_DIR |
/data/extensions |
Extensions storage directory |
MAX_SESSIONS |
10 | Maximum concurrent sessions |
DEFAULT_TIMEOUT |
3600 | Default session timeout (seconds) |
RESOLUTION |
1920x1080x24 |
Virtual display resolution |
Docker Compose
services:
api:
build: .
container_name: browserious-api
ports:
- "8100:8100" # API + VNC viewer
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./profiles:/data/profiles
- ./extensions:/data/extensions
environment:
- API_KEYS=${API_KEYS}
- API_HOST=localhost
- API_PORT=8100
- PROFILES_DIR=/data/profiles
- EXTENSIONS_DIR=/data/extensions
- HOST_PROFILES_DIR=${HOST_PROFILES_DIR}
- HOST_EXTENSIONS_DIR=${HOST_EXTENSIONS_DIR}
- DOCKER_NETWORK=browserious
- DOCKER_IMAGE=browserious-node:latest
- MAX_SESSIONS=10
- DEFAULT_TIMEOUT=3600
networks:
- browserious
restart: unless-stopped
networks:
browserious:
name: browserious
driver: bridge
Note: The API container requires access to Docker socket to spawn browser node containers. Set HOST_PROFILES_DIR and HOST_EXTENSIONS_DIR to the absolute paths on your host machine for volume mounts to work correctly in browser nodes.
Development
Setup
# Clone repository
git clone https://github.com/muzhig/browserious.git
cd browserious
# Install dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt
# Install Playwright browsers
playwright install chromium
# Run tests
pytest
# Run locally (without Docker)
export API_KEYS=test-key
export DISPLAY=:99
Xvfb :99 -screen 0 1920x1080x24 &
python -m uvicorn src.main:app --reload
Rebuilding After Code Changes
Different parts of the codebase require different rebuild steps:
| Changed | Rebuild Command | Notes |
|---|---|---|
src/*.py |
docker-compose build api |
Python API code |
node/api/*.go |
docker build -t browserious-node:latest ./node |
Go node API (input simulation) |
node/Dockerfile |
docker build -t browserious-node:latest ./node |
Node container config |
node/entrypoint.sh |
docker build -t browserious-node:latest ./node |
Node startup script |
Dockerfile |
docker-compose build api |
API container config |
docker-compose.yml |
docker-compose up -d |
Just restart, no rebuild |
Quick reference:
# After changing Python code (src/)
docker-compose build api && docker-compose up -d
# After changing Go code (node/api/)
docker build -t browserious-node:latest ./node
# After changing both
docker build -t browserious-node:latest ./node && docker-compose build api && docker-compose up -d
# Full rebuild from scratch
docker build -t browserious-node:latest ./node && docker-compose build --no-cache && docker-compose up -d
Note: Existing browser sessions use the node image that was current when they were created. New sessions will use the updated image.
Project Structure
browserious/
├── docs/ # Documentation
│ ├── PRD.md
│ ├── ADR.md
│ ├── API.md
│ └── SECURITY.md
├── src/ # Source code
│ ├── main.py
│ ├── browser_manager.py
│ ├── page_operations.py
│ ├── route_manager.py
│ └── ...
├── tests/ # Test suite
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── README.md
Deployment
Production Checklist
- Generate strong API keys (
openssl rand -base64 32) - Enable HTTPS (nginx/Caddy reverse proxy)
- Configure firewall (restrict API/VNC to trusted IPs)
- Set resource limits (CPU, memory)
- Enable profile encryption (LUKS or application-level)
- Set up monitoring and alerting
- Configure backups
- Review Security Documentation
Horizontal Scaling
Run multiple instances with external load balancer:
# Instance 1
docker-compose up -d
# Instance 2 (different ports)
docker-compose -f docker-compose.instance2.yml up -d
# Load balancer (nginx)
upstream browserapi {
server instance1:8000;
server instance2:8000;
}
See ADR-002 for scaling strategy.
Security
Browserious provides multiple security layers:
- API key authentication
- Docker container isolation
- Chromium sandbox
- Per-session VNC passwords
- Resource limits
Important: This service exposes significant attack surface. Review SECURITY.md before production deployment.
Quick Security Wins
- HTTPS Only: Use TLS for API (nginx reverse proxy)
- Network Isolation: Firewall rules to restrict access
- Strong API Keys: Generate with
openssl rand -base64 32 - Resource Limits: Prevent DoS via docker-compose limits
- Profile Encryption: Encrypt
/data/profilesvolume
Troubleshooting
Common Issues
Session creation fails
- Check Docker is running:
docker ps - Check logs:
docker-compose logs - Verify shm_size:
docker inspect | grep ShmSize
VNC not showing browser
- Ensure you're using the web VNC URL:
http://localhost:8100/vnc.html?session={session_id} - Check that the session exists:
curl http://localhost:8100/sessions/{session_id} - Verify the browser node container is running:
docker ps | grep session-
Browser crashes
- Increase shm_size in docker-compose.yml (recommended: 2g)
- Check memory limits
- Review container logs
Profile corruption
- Avoid concurrent access to same profile_id
- Use unique profile IDs:
user-{id}-{session-num} - See ADR-003
Roadmap
MVP (Current)
- Session management
- Page operations (all selector strategies)
- Request interception
- Profile management
- Extension support
- VNC access
- CDP WebSocket
Post-MVP
- Metrics and monitoring (
/metrics,/health) - Session event webhooks
- Redis-based session registry (multi-instance)
- Session recording (Playwright trace)
- Firefox support
- Mobile device emulation
Contributing
Contributions welcome! Please:
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing-feature) - Make changes following code style guidelines
- Run tests:
pytest tests/ -v - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open Pull Request
Quick Setup for Contributors
git clone https://github.com/muzhig/browserious.git
cd browserious
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt
playwright install chromium
pytest tests/ -v
See CONTRIBUTING.md for detailed guidelines.
Acknowledgments
- Playwright - Browser automation framework
- FastAPI - Modern Python web framework
- noVNC - HTML5 VNC client
- x11vnc - VNC server
Support
- Issues: GitHub Issues
- Documentation: docs/
- Security: Report vulnerabilities to security@example.com
Built for automation, testing, and scraping workflows.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file browserious-0.1.3.tar.gz.
File metadata
- Download URL: browserious-0.1.3.tar.gz
- Upload date:
- Size: 280.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7fdc2d1e5a04f58f44944e5eb9f359bad2dde2a510e66d560a7bc5e99b9418b
|
|
| MD5 |
8383ab2e22ce33707d3f7743b05e8529
|
|
| BLAKE2b-256 |
d3da06ea7d564d5f31414c4d05a7922b0e7241f28a0edf21b66842fc78f43c6d
|
Provenance
The following attestation bundles were made for browserious-0.1.3.tar.gz:
Publisher:
ci.yml on muzhig/browserious
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
browserious-0.1.3.tar.gz -
Subject digest:
f7fdc2d1e5a04f58f44944e5eb9f359bad2dde2a510e66d560a7bc5e99b9418b - Sigstore transparency entry: 1232952722
- Sigstore integration time:
-
Permalink:
muzhig/browserious@14beb0b21fbed4c0dab8a93b134df079b22795d9 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/muzhig
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@14beb0b21fbed4c0dab8a93b134df079b22795d9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file browserious-0.1.3-py3-none-any.whl.
File metadata
- Download URL: browserious-0.1.3-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1316edb41b2eacf5384a9616bde9a4bb99d70198107c6492afb7f1ca5642471
|
|
| MD5 |
bfbee9012a93693fae184b90e130a9db
|
|
| BLAKE2b-256 |
9d3877b49abbcffe56714fd0bfe84f0b72854cf910f8773054a177f83da1c1c5
|
Provenance
The following attestation bundles were made for browserious-0.1.3-py3-none-any.whl:
Publisher:
ci.yml on muzhig/browserious
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
browserious-0.1.3-py3-none-any.whl -
Subject digest:
f1316edb41b2eacf5384a9616bde9a4bb99d70198107c6492afb7f1ca5642471 - Sigstore transparency entry: 1232952766
- Sigstore integration time:
-
Permalink:
muzhig/browserious@14beb0b21fbed4c0dab8a93b134df079b22795d9 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/muzhig
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@14beb0b21fbed4c0dab8a93b134df079b22795d9 -
Trigger Event:
release
-
Statement type: