TL;DR: Use your real Safari with all your logins, cookies, and sessions. No headless browsers, no Chrome, no Puppeteer. Just pure AppleScript + JavaScript running natively on macOS — 60% less CPU/heat on Apple Silicon.
🤔 Why not just use Playwright or Chrome DevTools MCP?
| Problem | Safari MCP Solution |
|---|
| Chrome DevTools MCP heats up your Mac | Native WebKit — ~60% less CPU |
| Playwright launches a new browser without your logins | Uses your real Safari with all sessions |
| Puppeteer requires Chrome + debug port | Zero dependencies — just AppleScript |
| Headless browsers can't access your authenticated sessions | Gmail, GitHub, Slack — already logged in |
| Browser automation steals window focus | Safari stays in background, never interrupts |
Highlights
- 80 tools — navigation, clicks, forms, screenshots, network, storage, accessibility, and more
- Zero heat — native WebKit on Apple Silicon, ~60% less CPU than Chrome
- Your real browser — keeps all logins, cookies, sessions (Gmail, GitHub, Ahrefs, etc.)
- Background operation — Safari stays in the background, no window stealing
- No dependencies — no Puppeteer, no Playwright, no WebDriver, no Chrome
- Persistent process — reuses a single osascript process (~5ms per command vs ~80ms)
- Framework-compatible — React, Vue, Angular, Svelte form filling via native setters
Quick Start
Prerequisites
- macOS (any version with Safari)
- Node.js 18+
- Safari → Settings → Advanced → Show features for web developers ✓
- Safari → Develop → Allow JavaScript from Apple Events ✓
Install
git clone https://github.com/achiya-automation/safari-mcp.git
cd safari-mcp
npm install
Configure
Add to your MCP client config:
Claude Code (~/.mcp.json)
{
"mcpServers": {
"safari": {
"command": "node",
"args": ["/path/to/safari-mcp/index.js"]
}
}
}
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"safari": {
"command": "node",
"args": ["/path/to/safari-mcp/index.js"]
}
}
}
Cursor (.cursor/mcp.json)
{
"mcpServers": {
"safari": {
"command": "node",
"args": ["/path/to/safari-mcp/index.js"]
}
}
}
Windsurf / VS Code + Continue
{
"mcpServers": {
"safari": {
"command": "node",
"args": ["/path/to/safari-mcp/index.js"]
}
}
}
Tools (80)
Navigation (4)
| Tool | Description |
|---|
safari_navigate | Navigate to URL (auto HTTPS, wait for load) |
safari_go_back | Go back in history |
safari_go_forward | Go forward in history |
safari_reload | Reload page (optional hard reload) |
Page Reading (3)
| Tool | Description |
|---|
safari_read_page | Get title, URL, and text content |
safari_get_source | Get full HTML source |
safari_navigate_and_read | Navigate + read in one call |
Click & Interaction (5)
| Tool | Description |
|---|
safari_click | Click by CSS selector, visible text, or coordinates |
safari_double_click | Double-click (select word, etc.) |
safari_right_click | Right-click (context menu) |
safari_hover | Hover over element |
safari_click_and_wait | Click + wait for navigation |
Form Input (7)
| Tool | Description |
|---|
safari_fill | Fill input (React/Vue/Angular compatible) |
safari_clear_field | Clear input field |
safari_select_option | Select dropdown option |
safari_fill_form | Batch fill multiple fields |
safari_fill_and_submit | Fill form + submit in one call |
safari_type_text | Type real keystrokes (JS-based, no System Events) |
safari_press_key | Press key with modifiers |
Screenshots & PDF (3)
| Tool | Description |
|---|
safari_screenshot | Screenshot as PNG (viewport or full page) |
safari_screenshot_element | Screenshot a specific element |
safari_save_pdf | Export page as PDF |
Scroll (3)
| Tool | Description |
|---|
safari_scroll | Scroll up/down by pixels |
safari_scroll_to | Scroll to exact position |
safari_scroll_to_element | Smooth scroll to element |
Tab Management (4)
| Tool | Description |
|---|
safari_list_tabs | List all tabs (index, title, URL) |
safari_new_tab | Open new tab (background, no focus steal) |
safari_close_tab | Close tab |
safari_switch_tab | Switch to tab by index |
Wait (2)
| Tool | Description |
|---|
safari_wait_for | Wait for element, text, or URL change |
safari_wait | Wait for specified milliseconds |
JavaScript (1)
| Tool | Description |
|---|
safari_evaluate | Execute arbitrary JavaScript, return result |
Element Inspection (4)
| Tool | Description |
|---|
safari_get_element | Element details (tag, rect, attrs, visibility) |
safari_query_all | Find all matching elements |
safari_get_computed_style | Computed CSS styles |
safari_detect_forms | Auto-detect all forms with field selectors |
Accessibility (1)
| Tool | Description |
|---|
safari_accessibility_snapshot | Full a11y tree: roles, ARIA, focusable elements |
Drag & Drop (1)
| Tool | Description |
|---|
safari_drag | Drag between elements or coordinates |
File Operations (2)
| Tool | Description |
|---|
safari_upload_file | Upload file via JS DataTransfer (no file dialog!) |
safari_paste_image | Paste image into editor (no clipboard touch!) |
Dialog & Window (2)
| Tool | Description |
|---|
safari_handle_dialog | Handle alert/confirm/prompt |
safari_resize | Resize browser window |
Device Emulation (2)
| Tool | Description |
|---|
safari_emulate | Emulate device (iPhone, iPad, Pixel, Galaxy) |
safari_reset_emulation | Reset to desktop |
Cookies & Storage (10)
| Tool | Description |
|---|
safari_get_cookies | Get all cookies |
safari_set_cookie | Set cookie with all options |
safari_delete_cookies | Delete one or all cookies |
safari_local_storage | Read localStorage |
safari_set_local_storage | Write localStorage |
safari_delete_local_storage | Delete/clear localStorage |
safari_session_storage | Read sessionStorage |
safari_set_session_storage | Write sessionStorage |
safari_delete_session_storage | Delete/clear sessionStorage |
safari_export_storage | Export all storage as JSON (backup/restore sessions) |
safari_import_storage | Import storage state from JSON |
Clipboard (2)
| Tool | Description |
|---|
safari_clipboard_read | Read clipboard text |
safari_clipboard_write | Write text to clipboard |
Network (6)
| Tool | Description |
|---|
safari_network | Quick network requests via Performance API |
safari_start_network_capture | Start detailed capture (fetch + XHR) |
safari_network_details | Get captured requests with headers/timing |
safari_clear_network | Clear captured requests |
safari_mock_route | Mock network responses (intercept fetch/XHR) |
safari_clear_mocks | Remove all network mocks |
Console (4)
| Tool | Description |
|---|
safari_start_console | Start capturing console messages |
safari_get_console | Get all captured messages |
safari_clear_console | Clear captured messages |
safari_console_filter | Filter by level (log/warn/error) |
Performance (2)
| Tool | Description |
|---|
safari_performance_metrics | Navigation timing, Web Vitals, memory |
safari_throttle_network | Simulate slow-3g/fast-3g/4g/offline |
Data Extraction (4)
| Tool | Description |
|---|
safari_extract_tables | Tables as structured JSON |
safari_extract_meta | All meta: OG, Twitter, JSON-LD, canonical |
safari_extract_images | Images with dimensions and loading info |
safari_extract_links | Links with rel, external/nofollow detection |
Advanced (5)
| Tool | Description |
|---|
safari_override_geolocation | Override browser geolocation |
safari_list_indexed_dbs | List IndexedDB databases |
safari_get_indexed_db | Read IndexedDB records |
safari_css_coverage | Find unused CSS rules |
safari_analyze_page | Full page analysis in one call |
Automation (1)
| Tool | Description |
|---|
safari_run_script | Run multiple actions in a single call (batch) |
Safari MCP vs Alternatives
| Feature | Safari MCP | Chrome DevTools MCP | Playwright MCP |
|---|
| CPU/Heat | 🟢 Minimal | 🔴 High | 🟡 Medium |
| Your logins | ✅ Yes | ✅ Yes | ❌ No |
| macOS native | ✅ WebKit | ❌ Chromium | ❌ Chromium/WebKit |
| Dependencies | None | Chrome + debug port | Playwright runtime |
| Tools | 80 | ~30 | ~25 |
| File upload | JS (no dialog) | CDP | Playwright API |
| Image paste | JS (no clipboard) | CDP | Playwright API |
| Focus steal | ❌ Background | ❌ Background | ❌ Headless |
| Network mocking | ✅ | ❌ | ✅ |
| Lighthouse | ❌ | ✅ | ❌ |
| Performance trace | ❌ | ✅ | ❌ |
Tip: Use Safari MCP for daily browsing tasks (95% of work) and Chrome DevTools MCP only for Lighthouse/Performance audits.
Architecture
Claude/Cursor/AI Agent
↓ MCP Protocol (stdio)
Safari MCP Server (Node.js)
↓ Persistent osascript process (~5ms/cmd)
AppleScript → Safari
↓ do JavaScript in tab N
Page DOM (your real browser)
Key design decisions:
- Persistent osascript process — one long-running process instead of spawning per command (16x faster)
- Tab-indexed operations — all JS runs on a specific tab by index, never steals visual focus
- JS-first approach — typing, clicking, file upload all use JavaScript events (no System Events keyboard conflicts)
- No
activate — Safari is never brought to foreground
macOS Permissions
Safari MCP needs these one-time permissions:
| Permission | Where | Why |
|---|
| JavaScript from Apple Events | Safari → Develop menu | Required for do JavaScript |
| Screen Recording | System Settings → Privacy | Required for safari_screenshot |
| Accessibility | System Settings → Privacy | Required for safari_save_pdf only |
Troubleshooting
| Issue | Fix |
|---|
| "AppleScript error" | Enable "Allow JavaScript from Apple Events" in Safari → Develop |
| Screenshots empty | Grant Screen Recording permission to Terminal/VS Code |
| Tab not found | Call safari_list_tabs to refresh tab indices |
| Hebrew keyboard issues | All typing uses JS events — immune to keyboard layout |
| HTTPS blocked | safari_navigate auto-tries HTTPS first, falls back to HTTP |
| Safari steals focus | Ensure you're on latest version — newTab restores your active tab |
Works With
Safari MCP works with any MCP-compatible client:
Contributing
PRs welcome! The codebase is two files:
safari.js — Safari automation layer (AppleScript + JavaScript)
index.js — MCP server with tool definitions
Star History
If Safari MCP saved you from Chrome overhead, consider giving it a ⭐

License
MIT — use it however you want.