DEV Community

Cover image for I Built an MCP Server for Safari Because Chrome Was Melting My MacBook
אחיה כהן
אחיה כהן

Posted on

I Built an MCP Server for Safari Because Chrome Was Melting My MacBook

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
Enter fullscreen mode Exit fullscreen mode

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 DOM value)
  • 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";
Enter fullscreen mode Exit fullscreen mode

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 }));
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Enable in Safari:

  1. Safari → Settings → Advanced → Show features for web developers
  2. 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"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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)