Install
$ agentstack add mcp-achiya-automation-safari-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
🦁 Safari MCP
The browser for your coding agent.
Your real Safari, logged in — no Chrome, no heat, no headless.
[](https://www.npmjs.com/package/safari-mcp) [](https://www.npmjs.com/package/safari-mcp) [](https://opensource.org/licenses/MIT) [](https://www.apple.com/macos/)
[](https://glama.ai/mcp/servers/@achiya-automation/safari-mcp) [](https://registry.modelcontextprotocol.io/v0/servers?search=achiya-automation) [](https://smithery.ai/server/@achiya-automation/safari-mcp) [](https://mcpscoreboard.com/server/05977769-8762-4e89-aff3-a0c5776843bb/)
96 tools · No Chrome/Puppeteer/Playwright needed · ~5ms per command · 60% less CPU than Chrome
[Quick Start](#quick-start) · [All 96 Tools](#tools-96) · [Examples](examples/) · [Why Safari MCP?](#safari-mcp-vs-alternatives) · [Architecture](#architecture) · [Changelog](CHANGELOG.md)
❌ Without Safari MCP
Your AI agent needs to browse. So it either:
- Spins up Chromium via Playwright — with no logins, no cookies, no sessions
- Uses Chrome DevTools MCP — and melts your fan running a second browser
- Relies on headless scrapers — blocked by Cloudflare, reCAPTCHA, and bot detection
✅ With Safari MCP
Your AI drives the Safari you're already logged into — Gmail, GitHub, Ahrefs, Slack, banking.
Native WebKit. ~60% less CPU. Background operation. 96 tools. One npx command. macOS only.
> 📰 Featured on freeCodeCamp: How to Connect Your AI Coding Agent to a Browser on macOS · HackerNoon: Reverse-Engineering React, Shadow DOM, and CSP
Highlights
- 96 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 browser 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 (one command)
npx safari-mcp
That's it — no global install needed. Or install permanently:
npm install -g safari-mcp
Configure your MCP client
All clients run Safari MCP the same way — npx safari-mcp. Pick your editor:
Claude Code
claude mcp add safari -- npx safari-mcp
Or edit ~/.mcp.json:
{
"mcpServers": {
"safari": {
"command": "npx",
"args": ["safari-mcp"]
}
}
}
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"safari": {
"command": "npx",
"args": ["safari-mcp"]
}
}
}
Restart Claude Desktop after saving.
Cursor
One-click: [Install in Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=safari-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22safari-mcp%22%5D%7D)
Or edit .cursor/mcp.json in your project:
{
"mcpServers": {
"safari": {
"command": "npx",
"args": ["safari-mcp"]
}
}
}
VS Code / VS Code Insiders
One-click: [Install in VS Code](vscode:mcp/install?%7B%22safari-mcp%22%3A%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22safari-mcp%22%5D%7D%7D)
Or edit .vscode/mcp.json:
{
"servers": {
"safari": {
"type": "stdio",
"command": "npx",
"args": ["safari-mcp"]
}
}
}
Windsurf
Edit .windsurf/mcp.json in your project (or ~/.codeium/windsurf/mcp_config.json globally):
{
"mcpServers": {
"safari": {
"command": "npx",
"args": ["safari-mcp"]
}
}
}
Cline
Open Cline in VS Code → click the MCP icon → Edit MCP Settings → add:
{
"mcpServers": {
"safari": {
"command": "npx",
"args": ["safari-mcp"]
}
}
}
Continue
Edit ~/.continue/config.yaml (or .continue/config.yaml in workspace):
mcpServers:
- name: safari
command: npx
args:
- safari-mcp
Goose
Edit ~/.config/goose/config.yaml:
extensions:
safari:
name: safari
type: stdio
cmd: npx
args:
- safari-mcp
enabled: true
LM Studio
Open LM Studio → Settings → MCP Servers → Add Server:
- Name:
safari - Command:
npx - Args:
safari-mcp
Zed
Open Zed → Settings → search for "Context Servers" and add:
{
"context_servers": {
"safari": {
"command": {
"path": "npx",
"args": ["safari-mcp"]
}
}
}
}
Alternative: Homebrew
brew install achiya-automation/tap/safari-mcp
Alternative: from source
git clone https://github.com/achiya-automation/safari-mcp.git
cd safari-mcp && npm install
Usage Workflow
The recommended pattern for AI agents using Safari MCP:
1. safari_snapshot → Get page state (accessibility tree)
2. safari_click/fill/... → Interact with elements by ref
3. safari_snapshot → Verify the result
Element targeting — tools accept multiple targeting strategies:
| Strategy | Example | Best for | |----------|---------|----------| | CSS selector | #login-btn, .submit | Unique elements | | Visible text | "Sign In", "Submit" | Buttons, links | | Coordinates | x: 100, y: 200 | Canvas, custom widgets | | Ref from snapshot | ref: "e42" | Any element from accessibility tree |
> Tip: Start with safari_snapshot to get element refs, then use refs for precise targeting. This is faster and more reliable than CSS selectors.
Tools (96)
Click to expand the full tool list — organized by category
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 (6)
| 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 | | safari_click_and_read | Click then return the updated page — saves a round-trip (React Router + full loads) |
Form Input (11)
| 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 | | safari_react_select_set | Set a react-select v5 value via React fiber — bypasses the menu UI | | safari_react_select_list_options | List a react-select v5 dropdown's options without opening it | | safari_replace_editor | Replace all content in a code editor (Monaco, CodeMirror, Ace, ProseMirror) | | safari_verify_state | Verify an editor's framework-level state matches expected — catch stale DOM before Submit |
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 (5)
| 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 | | safari_wait_for_new_tab | Wait for a new tab (e.g. OAuth popup) and auto-switch to it |
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 (2)
| Tool | Description | |------|-------------| | safari_accessibility_snapshot | Full a11y tree: roles, ARIA, focusable elements | | safari_snapshot | Accessibility tree with ref IDs for every interactive element — preferred way to see page state |
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 (11)
| 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 (7)
| 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 | | safari_doctor | Diagnose the macOS permission + daemon chain (Apple Events, Accessibility, Screen Recording, codesign) with per-failure fixes | | safari_reload_extension | Hot-reload the Safari MCP Bridge extension without a manual toggle |
Automation (1)
| Tool | Description | |------|-------------| | safari_run_script | Run multiple actions in a single call (batch) |
Native Input — CGEvent (4)
| Tool | Description | |------|-------------| | safari_native_click | OS-level mouse click (CGEvent, isTrusted: true) — bypasses WAF/bot detection when safari_click is blocked (405/403) | | safari_native_hover | OS-level cursor hover — triggers real :hover/mouseenter for tooltips and obfuscated UIs | | safari_native_type | Insert text via the real paste pipeline — ProseMirror/Slate/Draft.js process it natively so Submit sends real data | | safari_native_keyboard | OS-level keypress + modifiers to Safari, no focus steal — reaches React trust-gated handlers (Discord/Slack send) |
iOS & WebKit Validation (4)
| Tool | Description | |------|-------------| | safari_inspect_viewport | Validate the ` tag for iOS Safari (device-width, zoom/WCAG, viewport-fit) | | safarisafeareainsets | Read live safe-area-inset values + viewport-fit / env() usage (notch / Dynamic Island) | | safaricheckpwa | Audit iOS "Add to Home Screen" / PWA readiness (apple-touch-icon, manifest, theme-color, splash) | | safariwebkit_compat | Check page CSS against this Safari via CSS.supports() — unsupported props, missing -webkit-` prefixes, known quirks |
Security
Safari MCP runs locally on your Mac with minimal attack surface:
| Aspect | Detail | |--------|--------| | Network | No remote connections — all communication is local (stdio + localhost) | | Permissions | macOS system permissions required (Screen Recording for screenshots) | | Data | No telemetry, no analytics, no data sent anywhere | | Extension | Communicates only with localhost:9224, validated by Safari | | Code | Fully open source (MIT) — audit every line |
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 | | Browser dependencies | None | Chrome + debug port | Playwright runtime | | Tools | 96 | ~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.
Why Safari MC
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: achiya-automation
- Source: achiya-automation/safari-mcp
- License: MIT
- Homepage: https://achiya-automation.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.