chromium-arm64
This ARM64-optimized Chromium automation server via Chrome DevTools Protocol offers:
Core Browser Control: Navigate, take screenshots (full-page or viewport), click, fill fields, hover, select dropdowns, execute JavaScript, and extract HTML/text.
Monitoring & Logging: Retrieve console logs/errors, network logs/errors, and clear all logs.
Element Inspection: Get details (tag, ID, class, text, value, selector) of the focused element.
Audits: Run accessibility, performance, SEO, best practices, Next.js, combined audits, and debugger mode.
Session Management: Set, get, and import/export cookies; persistent user profiles.
Mobile Device Emulation: Presets for iPhone, Pixel, Samsung, iPad; customizable viewport, user agent, device scale factor, touch, landscape, and reset to desktop.
Screencast Recording: Start/stop recording, export to MP4, GIF, or WebM, and check status.
Cross-Platform & Performance: Optimized for Linux ARM64 (Raspberry Pi), macOS Apple Silicon; direct WebSocket for lower memory and fast startup.
Integration: Claude Code CLI (MCP), Python API, and direct CLI access.
Customization: Environment variables for window size, screenshot height, user data dir, headful/headless, disk cache, custom Chromium path, and launch arguments.
Process Management: Cleanly shut down the Chromium browser instance.
Built on Node.js runtime to provide browser automation capabilities through a standardized interface.
Provides an alternative to Puppeteer that works on ARM64 architecture, fixing compatibility issues with Puppeteer's x86_64 binaries.
Provides Python wrappers and APIs for browser automation, enabling Python scripts to control the browser environment.
Optimized for Raspberry Pi's ARM64 architecture, providing a budget-friendly hardware platform for AI development.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@chromium-arm64 take a screenshot of the homepage and save it as 'homepage.png'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Chromium ARM64 Server
π Two Implementation Approaches Available
π¦ Version Comparison
Feature | Direct CDP (v1.4.0) β RECOMMENDED | Puppeteer-based (v1.2.0) |
Dependencies | Only | Puppeteer + MCP SDK (163 packages) |
Memory Usage | Lower (native chromium) | Higher (Node.js wrapper overhead) |
Startup Time | Faster (direct WebSocket) | Slower (puppeteer initialization) |
Browser Control | Native Chrome DevTools Protocol | Puppeteer abstraction layer |
ARM64 Optimization | Full native ARM64 | Depends on Puppeteer ARM64 support |
Debugging | Raw CDP messages visible | Abstracted by Puppeteer |
Maintenance | Chrome protocol changes only | Puppeteer + Chrome protocol changes |
Performance | Best (direct communication) | Good (wrapped communication) |
π― When to Use Which Version
Use Direct CDP (v1.4.0) if:
β You want maximum performance and minimum dependencies
β You need native ARM64 optimization
β You want direct Chrome DevTools Protocol control
β You're building production automation systems
β You want the latest features and fastest updates
Use Puppeteer-based (v1.2.0) if:
β You're migrating from existing Puppeteer code
β You prefer the Puppeteer API abstraction
β You need specific Puppeteer features not yet implemented in direct CDP
β You want to minimize changes to existing workflows
π Switching Between Versions
# Switch to Direct CDP (recommended)
git checkout direct-chromium
npm install # Only 89 packages
# Switch back to Puppeteer version
git checkout main
npm install # 163 packagesRelated MCP server: Glance
π Documentation & Specialized Guides
This repository includes multiple documentation approaches for different audiences:
π― For Developers & DevOps Engineers
π TECHNICAL README - Comprehensive technical documentation including:
Architecture diagrams and API reference
Performance benchmarks and optimization guides
CI/CD integration examples and E2E testing workflows
Advanced debugging and customization options
π For Makers & Entrepreneurs
π RASPBERRY PI README - Budget-focused guide featuring:
Complete $480 AI development setup
No-code SaaS development workflows
Real-world startup use cases and ROI analysis
Global accessibility and maker movement focus
β‘ Quick Links
Developers: Jump to Technical Documentation β
Makers: Jump to Raspberry Pi Guide β
Everyone: Continue reading for universal setup and usage
β¨ Core Features
π€ Native ARM64 Browser Automation
Direct Chrome DevTools Protocol implementation
27 comprehensive MCP tools for complete browser control
Optimized for Raspberry Pi and Apple Silicon architectures
No dependency on broken x86_64 Puppeteer binaries
β‘ High Performance Architecture
Only 2 dependencies (ws + MCP SDK) vs 163 packages in Puppeteer
Lower memory usage and faster startup times
Direct WebSocket communication with Chrome
Comprehensive logging and audit capabilities
π οΈ Enterprise-Ready Development
Full debugging suite with console/network monitoring
Accessibility, SEO, and performance audits built-in
CI/CD integration examples and E2E testing workflows
Cross-platform compatibility (Linux ARM64, macOS Apple Silicon)
π° Affordable Innovation Platform
Complete AI development setup for under $500
Same capabilities as $50K+ enterprise workstations
Global accessibility for makers and startups worldwide
No recurring cloud costs - own your infrastructure
π Universal Quick Start
Prerequisites
# Install system dependencies
sudo apt update
sudo apt install chromium-browser nodejs npm python3
# Verify Chromium works
chromium-browser --versionInstallation
git clone https://github.com/nfodor/mcp-chromium-arm64
cd mcp-chromium-arm64
npm install
chmod +x *.py *.shQuick Test (One-Liner)
# Verify it works immediately after install:
python3 -c "import sys; sys.path.append('.'); import arm64_browser; print('[OK] ARM64 Browser Works!' if 'error' not in arm64_browser.navigate('https://example.com').lower() else '[FAIL] Failed')"Expected Result: [OK] ARM64 Browser Works!
Test & Demo
# Quick demo with immediate visible results (30 seconds)
python3 instant_demo.py
# Or comprehensive demo showing all capabilities (2-3 minutes)
./run_demo.shTest the Setup
# Test MCP server directly
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node index.js
# Test Python wrapper
python3 simple_browser.pyπ οΈ Developer Guide & Debugging
π§ Available MCP Tools (29 total)
Core Browser Control
navigate- Navigate to URLs with full page loadingscreenshot- Capture PNG screenshots (full page or viewport)click- Click elements by CSS selector with precise positioningfill- Fill input fields with text or valueshover- Hover over elements for dropdown/tooltip interactionsselect- Select dropdown options by valueevaluate- Execute JavaScript and return resultsget_content- Extract page HTML or plain text content
Advanced Functionality
get_console_logs- Retrieve browser console outputget_console_errors- Get console error messages onlyget_network_logs- Monitor all network requests/responsesget_network_errors- Track failed network requests (4xx/5xx)wipe_logs- Clear all stored logs from memoryget_selected_element- Get info about currently focused element
Session & Authentication
set_cookies- Import cookies (e.g. exported after logging in elsewhere) to authenticate without scripting the login formget_cookies- Export the current session's cookies as JSON (round-trips withset_cookies)
Mobile Device Emulation
emulate_device- Emulate mobile devices with 17 presets or custom viewport/UA/DPR/touch, with landscape supportiPhones:
iphone-16,iphone-16-pro,iphone-16-pro-max,iphone-16e,iphone-15,iphone-15-pro-max,iphone-sePixels:
pixel-9,pixel-9-pro,pixel-9-pro-xl,pixel-9-pro-foldSamsung:
galaxy-s24,galaxy-s24-ultra,galaxy-z-fold-5Tablets:
ipad-air-m2,ipad-pro-13,galaxy-tab-s9
reset_emulation- Reset device emulation back to desktop mode
Screencast Recording
start_screencast- Start recording browser activity via CDP screencast (configurable format, quality, resolution, frame skip)stop_screencast- Stop recording and encode to MP4, GIF, or WebM via ffmpeg (auto-detects FPS from frame timestamps)screencast_status- Check recording status, frame count, and elapsed duration
Audit & Analysis Tools
run_accessibility_audit- Check alt text, labels, headings, contrastrun_performance_audit- Measure load times, memory usage, resourcesrun_seo_audit- Validate title, meta description, H1 tags, canonicalrun_best_practices_audit- Check HTTPS, deprecated HTML, viewportrun_nextjs_audit- Next.js specific optimization checksrun_debugger_mode- Comprehensive debugging informationrun_audit_mode- Run all audits together with summaryclose_browser- Clean shutdown of chromium process
π Authenticated Review (login-required sites)
To review pages behind a login (e.g. x.com) you don't have to script the login form, captcha, or 2FA. Log in once in your normal browser, export the cookies, inject them, then navigate.
Log in to the site in your regular browser.
Export the cookies with Cookie-Editor (Chrome / Firefox / Edge / Safari / Opera): open it on the logged-in tab β Export β JSON. An extension export is required for
httpOnlycookies (e.g. x.com'sauth_token), whichdocument.cookiecannot read.Inject and review via the MCP:
# 1) import the exported cookies (replace the [...] with the Cookie-Editor JSON array)
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"set_cookies","arguments":{"url":"https://x.com","cookies":[]}}}' | node index.js
# 2) navigate to the page you want β now authenticated
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"navigate","arguments":{"url":"https://x.com/home"}}}' | node index.jsThe session stays authenticated for the life of the browser process. Use get_cookies to export it back out for reuse.
Alternative β raw Cookie header. Instead of the JSON array you can paste a raw Cookie: header string via cookieHeader (requires url, since a header carries no domain):
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"set_cookies","arguments":{"url":"https://x.com","cookieHeader":"auth_token=abc123; ct0=def456"}}}' | node index.jsPersist across restarts. By default the profile is ephemeral, so the session is lost when the browser process exits. Set CHROMIUM_USER_DATA_DIR to a writable path and cookies/logins survive restarts β log in (or inject cookies) once and reuse:
export CHROMIUM_USER_DATA_DIR="$HOME/.mcp-chromium-arm64/profile"Format:
set_cookiesaccepts the Cookie-Editor / EditThisCookie JSON export directly β it normalizessameSite(no_restrictionβNone), acceptsexpirationDate, and honors session cookies. Pass a top-levelurlfor any cookie that omits a domain, or usecookieHeaderfor a raw header string.cookies[]andcookieHeadercan be combined.Security: cookies are session secrets and pass through as tool arguments, so they appear in logs/transcripts. Treat an exported
auth_tokenlike a password β log out / rotate when done. A persistentCHROMIUM_USER_DATA_DIRstores the live session on disk, so protect that directory too.
π Debugging & Development
Direct MCP Testing
# Test individual tools directly
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"navigate","arguments":{"url":"https://example.com"}}}' | node index.js
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"evaluate","arguments":{"script":"document.title"}}}' | node index.js
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"screenshot","arguments":{"name":"debug.png"}}}' | node index.jsScreencast Recording
# Start recording, interact with the page, then stop and encode
# 1. Start screencast
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"start_screencast","arguments":{"format":"jpeg","quality":80,"maxWidth":1280,"maxHeight":720}}}' | node index.js
# 2. Perform actions (navigate, click, fill, etc.)
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"navigate","arguments":{"url":"https://example.com"}}}' | node index.js
# 3. Check recording progress
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"screencast_status","arguments":{}}}' | node index.js
# 4. Stop and encode to MP4
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"stop_screencast","arguments":{"output":"mp4","name":"my-demo"}}}' | node index.js
# Output: /tmp/my-demo.mp4
# Encode as GIF instead (2-pass palette for quality)
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"stop_screencast","arguments":{"output":"gif","name":"bug-repro"}}}' | node index.js
# Output: /tmp/bug-repro.gif
# Or WebM (VP9)
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"stop_screencast","arguments":{"output":"webm"}}}' | node index.jsRequires:
ffmpeginstalled on the system. FPS is auto-detected from CDP frame timestamps. GIF output is capped at 15fps for reasonable file sizes.
Mobile Device Emulation
# Emulate iPhone 16 Pro
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"emulate_device","arguments":{"device":"iphone-16-pro"}}}' | node index.js
# Emulate in landscape mode
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"emulate_device","arguments":{"device":"ipad-pro-13","landscape":true}}}' | node index.js
# Custom viewport with DPR
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"emulate_device","arguments":{"width":390,"height":844,"deviceScaleFactor":3,"mobile":true}}}' | node index.js
# Reset back to desktop
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"reset_emulation","arguments":{}}}' | node index.jsNetwork & Console Monitoring
# Navigate to a page, then check console logs
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_console_logs","arguments":{}}}' | node index.js
# Get only errors
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_console_errors","arguments":{}}}' | node index.js
# Check network activity (all requests with status codes)
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_network_logs","arguments":{}}}' | node index.js
# Check for failed requests (4xx/5xx)
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_network_errors","arguments":{}}}' | node index.js
# Clear all logs when done
echo '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"wipe_logs","arguments":{}}}' | node index.jsAudits
# Run all audits at once (accessibility + performance + SEO + best practices + Next.js)
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"run_audit_mode","arguments":{}}}' | node index.js
# Or run individual audits
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"run_accessibility_audit","arguments":{}}}' | node index.js
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"run_performance_audit","arguments":{}}}' | node index.js
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"run_seo_audit","arguments":{}}}' | node index.js
# Get full debug info (URL, viewport, memory, timing)
echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"run_debugger_mode","arguments":{}}}' | node index.jsElement Inspection
# Get info about the currently focused element
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_selected_element","arguments":{}}}' | node index.js
# Returns: tagName, id, className, textContent, value, and a CSS selectorChrome DevTools Protocol Debugging
# Manual CDP connection test
node -e "
const { WebSocket } = require('ws');
const { spawn } = require('child_process');
const chrome = spawn('/usr/bin/chromium-browser', [
'--headless', '--remote-debugging-port=9227'
]);
setTimeout(() => {
fetch('http://localhost:9227/json')
.then(r => r.json())
.then(tabs => {
console.log('Available tabs:', tabs.length);
const ws = new WebSocket(tabs[0].webSocketDebuggerUrl);
ws.on('open', () => {
console.log('CDP WebSocket connected!');
ws.send(JSON.stringify({id: 1, method: 'Runtime.evaluate', params: {expression: '2+2'}}));
});
ws.on('message', (data) => {
console.log('CDP Response:', JSON.parse(data));
chrome.kill();
process.exit(0);
});
});
}, 2000);
"Performance Monitoring
# Monitor system resources during operation
htop &
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"navigate","arguments":{"url":"https://httpbin.org/delay/5"}}}' | time node index.js
# Check memory usage
ps aux | grep chromium
free -hNetwork Debugging
# Check if debugging port is accessible
curl -s http://localhost:9222/json | jq '.[] | {id, title, type}'
# Monitor WebSocket traffic (install websocat)
websocat ws://localhost:9222/devtools/page/[TAB_ID] --text -vπ Common Debugging Scenarios
1. WebSocket Connection Issues
# Symptoms: "CDP command timeout" errors
# Check if chrome debugging port is running
lsof -i :9222
# Test manual connection
node -e "
const { WebSocket } = require('ws');
const ws = new WebSocket('ws://localhost:9222/devtools/browser');
ws.on('open', () => console.log('β WebSocket OK'));
ws.on('error', (e) => console.log('β WebSocket Error:', e.message));
setTimeout(() => process.exit(0), 2000);
"2. Chrome Process Issues
# Symptoms: Browser won't start or hangs
# Kill any stuck processes
pkill -f chromium-browser
pkill -f remote-debugging-port
# Test chrome startup manually
timeout 10s /usr/bin/chromium-browser --headless --remote-debugging-port=9223 --no-sandbox
# Check chrome logs
journalctl --user -u chromium --since "1 hour ago"3. Element Selection Problems
# Debug CSS selectors interactively
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate","arguments":{"script":"document.querySelectorAll(\"button\").length"}}}' | node index.js
# Get element information
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate","arguments":{"script":"document.querySelector(\"#mybutton\") ? \"found\" : \"not found\""}}}' | node index.js4. Memory and Performance Issues
# Monitor memory during operation
watch -n 1 'ps aux | grep -E "(chromium|node)" | grep -v grep'
# Chrome memory debugging
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate","arguments":{"script":"JSON.stringify(performance.memory)"}}}' | node index.jsπ― Advanced Debugging Features
Enable Verbose Logging
# Set environment variables for detailed output
export DEBUG=puppeteer:*
export NODE_ENV=development
# Run with detailed Chrome logs
/usr/bin/chromium-browser --headless --enable-logging --log-level=0 --remote-debugging-port=9222CDP Message Tracing
# Create debug version with message logging
cp index.js debug-index.js
# Add to sendCDPCommand method:
# console.log('β CDP:', JSON.stringify(command));
# console.log('β CDP:', JSON.stringify(response));
node debug-index.jsIntegration with Browser DevTools
# Connect regular Chrome DevTools to the headless instance
# 1. Start the MCP server
# 2. Open regular Chrome/Chromium
# 3. Navigate to: chrome://inspect
# 4. Click "Configure..." and add localhost:9222
# 5. Click "inspect" on the page you want to debugπ Performance Benchmarks
Startup Time Comparison
# Direct CDP (v1.3.0)
time echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate","arguments":{"script":"Date.now()"}}}' | node index.js
# Puppeteer version (v1.2.0)
git checkout main
time echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate","arguments":{"script":"Date.now()"}}}' | node index.jsMemory Usage Monitoring
# Before operation
free -h && ps aux | grep -E "(chromium|node)" | grep -v grep
# During operation (run in another terminal)
watch -n 1 'echo "=== $(date) ===" && free -h && echo && ps aux | grep -E "(chromium|node)" | grep -v grep'π¨ Error Codes & Solutions
Error | Cause | Solution |
| WebSocket connection lost | Restart browser, check port availability |
| Chrome not fully started | Increase startup delay, check chrome process |
| CSS selector invalid | Verify selector with |
| Debugging port blocked | Check firewall, kill existing chrome processes |
| Page loading issues | Check network, increase timeout, try simpler page |
π§ Customization & Extension
Adding New MCP Tools
// In index.js, add to tools array:
{
name: 'my_custom_tool',
description: 'My custom functionality',
inputSchema: {
type: 'object',
properties: {
param: { type: 'string', description: 'Parameter description' }
},
required: ['param']
}
}
// Add to switch statement in CallToolRequestSchema handler:
case 'my_custom_tool':
return await this.myCustomTool(args.param);
// Implement the method:
async myCustomTool(param) {
await this.ensureChromium();
const result = await this.sendCDPCommand('Page.navigate', { url: param });
return { content: [{ type: 'text', text: `Custom result: ${result}` }] };
}Environment Variables
# Set browser window size (default: 1280,720)
export CHROMIUM_WINDOW_SIZE=1920,1080
# Cap full-page screenshot height in px (default: 32768)
export CHROMIUM_MAX_SCREENSHOT_HEIGHT=32768
# Persistent profile: keep cookies / logins across restarts (default: ephemeral when unset)
export CHROMIUM_USER_DATA_DIR="$HOME/.mcp-chromium-arm64/profile"
# Use a specific Chromium-family binary (Chrome, Edge, Brave, Opera, Vivaldi, Chromium).
# Overrides auto-detection; point it at any Chromium-based browser.
export CHROMIUM_PATH="/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
# Launch a visible (headful) window instead of headless β e.g. to log into a site
# by hand once into a persistent profile (default: headless when unset)
export CHROMIUM_HEADLESS=false
# Cap Chrome's on-disk HTTP cache in bytes (default: 104857600 = 100MB).
# Bounds profile/cache growth, especially with a persistent CHROMIUM_USER_DATA_DIR.
export CHROMIUM_DISK_CACHE_SIZE=104857600Disk hygiene: in the default (ephemeral) mode the server launches Chrome with its own temp profile dir and deletes it on close β and sweeps any leftovers from crashed/killed prior runs on startup β so it can't accumulate orphaned profile/cache directories. The disk cache is capped (CHROMIUM_DISK_CACHE_SIZE) in both ephemeral and persistent modes. A persistent CHROMIUM_USER_DATA_DIR is intentionally kept (that's the point of it), so it's the one path you manage yourself.
Browser support: auto-detects any Chromium-family browser β Chrome, Chromium, Microsoft Edge, Brave, Opera, Vivaldi (Firefox/Safari are not supported; the server speaks Chrome DevTools Protocol). Set CHROMIUM_PATH to force a specific binary.
Headful login (no cookie-export extension needed): set CHROMIUM_USER_DATA_DIR + CHROMIUM_HEADLESS=false, log into a site (X, LinkedIn, β¦) by hand once in the visible window, then drop CHROMIUM_HEADLESS β the persistent profile keeps you logged in for subsequent headless runs. This also beats headless bot-detection since you sign in as a normal user.
Chrome Launch Options
// Modify in startChromium() method:
const customArgs = [
'--headless',
'--no-sandbox',
'--disable-extensions',
'--disable-plugins',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--remote-debugging-port=9222',
'--window-size=1920,1080', // Custom viewport
'--user-agent=CustomUA/1.0', // Custom user agent
'--disable-web-security', // For CORS testing
'--allow-running-insecure-content' // For mixed content
];π Cross-Platform ARM64 Compatibility
Platform Support Matrix
Platform | Status | Chrome Path | Installation Method | Notes |
Linux ARM64 β | Fully Supported |
|
| Tested on Raspberry Pi OS |
macOS Apple Silicon β οΈ | Requires Modifications |
| Download from Google or | Need path and flag updates |
Windows ARM64 β | Untested |
| Download from Google | Would need Windows-specific changes |
macOS Apple Silicon Setup
Prerequisites
# Install Homebrew if not already installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install Node.js and Chromium
brew install node chromium --no-quarantineRequired Code Changes
Currently, the server is optimized for Linux ARM64. For macOS compatibility, modify index.js:
// Detect platform and set appropriate chrome path
function getChromePath() {
const platform = process.platform;
switch(platform) {
case 'linux':
return '/usr/bin/chromium-browser';
case 'darwin': // macOS
// Try multiple possible paths
const macPaths = [
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
'/Applications/Chromium.app/Contents/MacOS/Chromium',
'/opt/homebrew/bin/chromium'
];
for (const path of macPaths) {
if (require('fs').existsSync(path)) {
return path;
}
}
throw new Error('Chrome/Chromium not found on macOS');
case 'win32':
return 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe';
default:
throw new Error(`Unsupported platform: ${platform}`);
}
}
// Update startChromium method
async startChromium() {
const chromePath = getChromePath();
const platform = process.platform;
// Platform-specific arguments
const baseArgs = [
'--headless',
'--disable-extensions',
'--disable-plugins',
`--remote-debugging-port=${debuggingPort}`,
'--no-first-run',
'--disable-gpu',
'--window-size=1280,720'
];
// Add Linux-specific sandbox flags
if (platform === 'linux') {
baseArgs.push('--no-sandbox', '--disable-setuid-sandbox');
}
// Add macOS-specific flags if needed
if (platform === 'darwin') {
baseArgs.push('--disable-dev-shm-usage');
}
chromiumProcess = spawn(chromePath, baseArgs);
// ... rest of method
}macOS-Specific Issues & Solutions
1. "Chromium is damaged" Error
# Remove quarantine flag if downloading manually
sudo xattr -r -d com.apple.quarantine /Applications/Chromium.app
# Or install via Homebrew with no-quarantine flag
brew install chromium --no-quarantine2. Chrome vs Chromium Choice
# Option 1: Use Google Chrome (recommended)
# Download from: https://www.google.com/chrome/
# Path: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
# Option 2: Use Chromium via Homebrew
brew install chromium --no-quarantine
# Path: /opt/homebrew/bin/chromium3. Permission Issues
# Ensure Chrome has required permissions
# System Preferences > Security & Privacy > Privacy tab
# Grant Camera, Microphone access if needed for specific use casesTesting Cross-Platform Compatibility
Quick Platform Detection Test
node -e "
console.log('Platform:', process.platform);
console.log('Architecture:', process.arch);
const fs = require('fs');
const paths = {
linux: '/usr/bin/chromium-browser',
darwin: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
win32: 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe'
};
const chromePath = paths[process.platform];
console.log('Expected Chrome path:', chromePath);
console.log('Chrome exists:', fs.existsSync(chromePath));
"Cross-Platform MCP Test
# Test basic functionality across platforms
echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"evaluate\",\"arguments\":{\"script\":\"navigator.platform\"}}}' | node index.js
# Should return the current platformWindows ARM64 Considerations
While untested, Windows ARM64 support would need:
// Windows-specific chrome path detection
case 'win32':
const winPaths = [
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
process.env.LOCALAPPDATA + '\\Google\\Chrome\\Application\\chrome.exe'
];
// Similar path checking logic...Performance Differences
Platform | Startup Time | Memory Usage | Notes |
Linux ARM64 (Pi 4) | ~3-4s | ~150MB | Optimized, well-tested |
macOS Apple Silicon | ~2-3s | ~200MB | Faster CPU, more memory |
Windows ARM64 | Unknown | Unknown | Would depend on hardware |
Contribution Needed
We welcome contributions for full cross-platform support!
macOS testers: Test the proposed changes on Apple Silicon
Windows ARM64: Test on Surface Pro X or similar devices
Performance optimization: Platform-specific optimizations
Installation scripts: Automated setup for each platform
Claude CLI Integration
Prerequisites
# Install Claude Code CLI if you haven't already
npm install -g @anthropic-ai/claude-codeAdd to Claude CLI
# From the project directory after cloning
claude mcp add chromium-arm64 "$(pwd)/mcp-wrapper.sh" --scope userVerify Connection
claude mcp list
# Should show: chromium-arm64: /path/to/mcp-wrapper.sh - β Connectedβ οΈ Important: Restart Claude After Adding
You MUST start a new Claude session after adding the MCP server:
# Exit current session if in one
exit
# Start fresh session
claudeUsing in Claude CLI
Ask Claude to use the chromium-arm64 tools:
List available MCP servers and use chromium-arm64 to navigate to https://example.com
Take a screenshot using the chromium-arm64 tool
Use chromium-arm64 to click the button with selector #submit
Fill the email field using chromium-arm64 with test@example.com
Record a screencast of the login flow and save it as a GIF
Emulate an iPhone 16 Pro and take a screenshot of the homepage
Run a full audit on https://example.com using chromium-arm64Be explicit to avoid Playwright/Puppeteer:
"Use chromium-arm64 to navigate..."
"Using the chromium-arm64 tool, take a screenshot"
"Open a browser" (might try broken Playwright)
"Take a screenshot" (might try broken Puppeteer)
Success Example
When working correctly, you'll see:
You: Use chromium-arm64 to navigate to https://httpbin.org/json and show me what you see
Claude: I'll navigate to https://httpbin.org/json using the chromium-arm64 tool.
[Uses chromium-arm64.navigate tool]
The page displays a JSON object with a slideshow structure containing:
- Author: "Yours Truly"
- Date: "date of publication"
- Title: "Sample Slide Show"
...Usage Examples
Python API
import simple_browser
# Navigate to any website
result = simple_browser.browser_navigate("https://example.com")
print(result) # "Successfully navigated to https://example.com"
# Take a screenshot
screenshot = simple_browser.browser_screenshot("homepage.png")
print(screenshot) # "Screenshot saved to /tmp/homepage.png"
# Execute JavaScript
title = simple_browser.browser_evaluate("document.title")
print(title) # Website title
# Extract page content
content = simple_browser.browser_get_content("text")
print(content[:100]) # First 100 chars of page textMCP Tools (via Claude Code)
Once configured, use these tools directly in Claude Code:
navigate- Go to URLsscreenshot- Capture page imagesclick/fill/hover/select- Interact with page elementsevaluate- Execute JavaScriptget_content- Extract page HTML/textemulate_device/reset_emulation- Mobile device emulation with 17 presetsstart_screencast/stop_screencast- Record browser activity to MP4/GIF/WebMget_console_logs/get_network_logs- Monitor console and networkrun_audit_mode- Run all audits (a11y, performance, SEO, best practices)close_browser- Clean shutdown
π― Key Use Cases
π§ͺ For Testing & QA Teams
End-to-end SaaS testing with autonomous AI agents
Visual regression detection and cross-device compatibility
24/7 continuous validation on budget hardware
π For Startups & Makers
Complete $480 AI development setup (see Raspberry Pi Guide)
No-code SaaS development with AI-powered testing
Competitive analysis and market research automation
π οΈ For DevOps & Developers
CI/CD integration with comprehensive audit tools
Performance benchmarking and accessibility testing
Advanced debugging with console/network monitoring
π Full examples and detailed guides available in the specialized documentation.
ποΈ Architecture
graph TB
A[Claude Code] --> B[MCP Protocol]
B --> C[ARM64 Browser Server]
C --> D[System Chromium]
D --> E[Web Pages]
F[Python Tools] --> C
G[Direct CLI] --> Cπ§ Troubleshooting & Advanced Usage
For detailed troubleshooting guides, debugging tools, and advanced configuration:
π Quick References
Common Issues: See Technical Documentation β
Performance Tuning: See Technical Documentation β
Cross-Platform Setup: See Technical Documentation β
Complete Hardware Setup: See Raspberry Pi Guide β
Quick Fixes
# Test MCP server directly
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | node index.js
# Verify browser installation
chromium-browser --version
# Check Claude MCP integration
claude mcp listπ€ Contributing
We welcome contributions to democratize AI access for developers worldwide.
Areas for Contribution:
π± Mobile browser support (Android/iOS testing)
π§ Additional MCP tools and integrations
β‘ Performance optimizations for smaller devices
π Tutorial content and use-case examples
Development Setup:
git clone https://github.com/nfodor/mcp-chromium-arm64
cd mcp-chromium-arm64
npm install
# Ready to use - no development server needed!π License
MIT License - feel free to use in commercial projects!
π Acknowledgments
π€ Anthropic for Claude Code and MCP protocol
π Raspberry Pi Foundation for democratizing computing
π Chromium Project for ARM64 browser support
π₯ Open Source Community for making this possible
π Support & Community
π Issues: GitHub Issues
π¬ Discussions: GitHub Discussions
π§ Email: github@fodor.app
π Repository: github.com/nfodor/mcp-chromium-arm64
Available Tools
22 toolsclickC
Click an element on the page
Inputs: selector (required).
close_browserB
Close the browser instance
Inputs: no named parameters.
evaluateC
Execute JavaScript in the browser
Inputs: script (required).
fillC
Fill an input field
Inputs: selector (required), value (required).
get_console_errorsB
Get browser console errors
Inputs: no named parameters.
get_console_logsB
Get browser console logs
Inputs: no named parameters.
get_contentC
Get page content (HTML or text)
Inputs: type.
get_network_errorsB
Get network error logs
Inputs: no named parameters.
get_network_logsC
Get network activity logs
Inputs: no named parameters.
get_selected_elementB
Get information about the currently selected element
Inputs: no named parameters.
hoverC
Hover over an element on the page
Inputs: selector (required).
run_accessibility_auditB
Run an accessibility audit on the current page
Inputs: no named parameters.
run_audit_modeC
Run comprehensive audit mode for optimization
Inputs: no named parameters.
run_best_practices_auditC
Run a best practices audit on the current page
Inputs: no named parameters.
run_debugger_modeC
Run debugger mode to debug issues in the application
Inputs: no named parameters.
run_nextjs_auditB
Run a Next.js specific audit on the current page
Inputs: no named parameters.
run_performance_auditB
Run a performance audit on the current page
Inputs: no named parameters.
run_seo_auditB
Run an SEO audit on the current page
Inputs: no named parameters.
screenshotC
Take a screenshot of the current page
Inputs: name, fullPage.
selectC
Select an option from a dropdown
Inputs: selector (required), value (required).
wipe_logsB
Clear all stored logs from memory
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelogβ¦
TDQS
Scored across 22 tools
Most tools have distinct purposes, such as click, fill, navigate, and screenshot, with clear boundaries. However, some overlap exists between the various audit tools (e.g., run_accessibility_audit, run_best_practices_audit, run_performance_audit, run_seo_audit, run_nextjs_audit, run_audit_mode), which could cause confusion as their specific scopes might not be immediately clear from the names alone, though descriptions help differentiate them.
The tool names follow a highly consistent snake_case pattern with clear verb_noun structures, such as click, close_browser, evaluate, fill, get_console_errors, navigate, run_accessibility_audit, and screenshot. There are no deviations in naming conventions, making the set predictable and easy to understand.
With 22 tools, the count is borderline high for a browser automation and auditing server, as it might feel heavy and potentially overwhelming. While it covers many aspects, some tools could be consolidated (e.g., multiple audit tools), suggesting a slight over-scoping that could impact usability.
The tool set provides comprehensive coverage for browser automation and auditing, including navigation, interaction (click, fill, select), content retrieval (get_content, get_console_logs), debugging (run_debugger_mode, get_network_errors), audits (performance, SEO, accessibility), and maintenance (close_browser, wipe_logs). There are no obvious gaps, and agents can handle full workflows from setup to analysis.
Maintenance
Related MCP Connectors
Official Browserless MCP server: browser automation, scraping, screenshots and PDFs for AI agents.
MCP server for Mint β AI-powered QA that runs your app in a real browser on every PR.
Hosted Web Crawler MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Web scraping, browser automation, screenshots and AI data extraction for AI agents via MCP.
Related MCP Servers
- AlicenseCqualityDmaintenanceAn MCP server that gives Claude Code real browser control for web automation, testing, and screenshots.3263 npm157MIT
- AlicenseNot gradedqualityAmaintenanceAn MCP server that gives Claude Code a real browser, enabling it to navigate, click, type, screenshot, and inspect web pages during development. It also supports multi-step JSON test scenarios, assertions, session recording, and visual regression testing against web apps.106 npmMIT
- AlicenseNot gradedqualityAmaintenanceAn MCP server that gives Claude Code a real browser, enabling navigation, clicking, form filling, screenshots, and accessibility snapshots directly from the terminal. It also supports multi-step JSON test scenarios, assertions, session recording, and visual regression testing with network and console monitoring.106 npmMIT
- AlicenseNot gradedqualityBmaintenanceAn MCP server that gives Claude Code control of a real browser, letting it navigate pages, click and type, capture screenshots, read accessibility snapshots, and run multi-step test scenarios with assertions. It also supports session recording, visual regression comparison, and network/console monitoring with configurable security profiles.106 npmMIT