Last month I noticed something: every time I used Chrome DevTools MCP or Playwright MCP with Claude, my MacBook Pro fans would spin up. Activity Monitor showed Chrome eating 40-60% CPU just sitting there with a debug port open.
I use Safari as my daily browser. All my logins are there — Gmail, GitHub, Ahrefs, AWS console. Why am I launching a second browser just so an AI agent can click buttons?
So I built Safari MCP — a native MCP server that controls Safari directly via AppleScript. No Chrome. No Puppeteer. No headless anything.
The Architecture (It's Embarrassingly Simple)
AI Agent (Claude, Cursor, etc.)
↓ MCP Protocol (stdio)
Safari MCP Server (Node.js)
↓ Persistent osascript process
AppleScript → Safari
↓ do JavaScript in tab N
Your real browser DOM
The entire server is essentially two files:
-
index.js— MCP tool definitions -
safari.js— AppleScript + JavaScript bridge
The key trick: instead of spawning a new osascript process for every command (~80ms each), I keep a single persistent process running. Commands go in via stdin, results come back via stdout. Result: ~5ms per command instead of 80ms.
80 Tools — Here's What You Actually Get
Not just navigate and click. Safari MCP has 80 tools across 20 categories:
The basics: navigate, click, fill forms, screenshots, scroll, tabs
The good stuff:
-
safari_fill— works with React/Vue/Angular (uses native property setters, not just DOMvalue) -
safari_upload_file— uploads via JS DataTransfer, no file dialog popup -
safari_mock_route— intercept and mock fetch/XHR responses -
safari_accessibility_snapshot— full a11y tree with ARIA roles -
safari_extract_tables— tables as structured JSON -
safari_emulate— device emulation (iPhone, iPad, Pixel, etc.) -
safari_run_script— batch multiple actions in a single call
The sneaky stuff:
-
safari_start_network_capture+safari_network_details— capture all fetch/XHR with headers and timing -
safari_export_storage/safari_import_storage— backup and restore entire browser sessions -
safari_css_coverage— find unused CSS rules -
safari_analyze_page— full page analysis in one call
The React Form Problem (And How I Solved It)
If you've ever tried to automate React forms, you know this doesn't work:
element.value = "hello";
React doesn't see it. The state doesn't update. The submit button stays disabled.
Safari MCP uses the native input setter approach:
const nativeSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype, 'value'
).set;
nativeSetter.call(element, value);
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
This works with React, Vue, Angular, Svelte — anything that uses synthetic event listeners.
Real Numbers: Safari MCP vs Chrome DevTools MCP
I measured this on an M2 MacBook Pro running both servers simultaneously:
| Metric | Safari MCP | Chrome DevTools MCP |
|---|---|---|
| CPU (idle) | ~0.1% | ~8-15% |
| CPU (active) | ~2-5% | ~25-40% |
| Memory | ~30MB (Node process only) | ~200-400MB (Chrome + Node) |
| Command latency | ~5ms | ~15-30ms |
| Startup time | <1s | 3-5s (Chrome launch) |
| Dependencies | 0 | Chrome browser |
The CPU difference is dramatic on laptops. Safari MCP basically doesn't show up in Activity Monitor.
The Tradeoffs (I'm Being Honest)
Safari MCP is not a replacement for everything:
What Safari MCP can't do:
- No Lighthouse audits (Chrome-only)
- No Performance traces / CPU profiling
- No cross-platform (macOS only, obviously)
- No headless mode (Safari is always "real")
- No CDP (Chrome DevTools Protocol) — we use AppleScript
My actual workflow:
- Safari MCP for 95% of browser tasks (navigation, scraping, form filling, testing)
- Chrome DevTools MCP for the 5% that needs Lighthouse or Performance traces
Quick Start
git clone https://github.com/achiya-automation/safari-mcp.git
cd safari-mcp
npm install
Enable in Safari:
- Safari → Settings → Advanced → Show features for web developers ✓
- Safari → Develop → Allow JavaScript from Apple Events ✓
Add to your MCP config (Claude Code, Cursor, etc.):
{
"mcpServers": {
"safari": {
"command": "node",
"args": ["/path/to/safari-mcp/index.js"]
}
}
}
That's it. No Chrome to install, no debug ports to configure, no Playwright browsers to download.
Why I Open-Sourced It
I built this for myself — I run an automation business and needed reliable browser control without the Chrome tax. But I figured if my MacBook was overheating, other Mac developers must be having the same problem.
If you're on a Mac and tired of Chrome eating your battery for AI browser automation, give it a try:
github.com/achiya-automation/safari-mcp
Star it if it saves your fans from spinning up. ⭐
Built with AppleScript, JavaScript, and frustration with Chrome's CPU usage.
Top comments (0)