# Safari Mcp

> Native MCP server to drive Safari on macOS — navigate, click, type, run JS, screenshots, computer-use, file upload, and console/network capture. Zero runtime deps.

- **Type:** MCP server
- **Install:** `agentstack add mcp-erwinzhang7-safari-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [erwinzhang7](https://agentstack.voostack.com/s/erwinzhang7)
- **Installs:** 0
- **Category:** [Web & Browser](https://agentstack.voostack.com/c/web-and-browser)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [erwinzhang7](https://github.com/erwinzhang7)
- **Source:** https://github.com/erwinzhang7/safari-mcp

## Install

```sh
agentstack add mcp-erwinzhang7-safari-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Safari MCP

A native [Model Context Protocol](https://modelcontextprotocol.io) server that lets an MCP
client (e.g. Claude Code) drive Safari on macOS — navigate, read, click, type, run JS, take
screenshots, do screenshot-driven mouse/keyboard control, upload files, and capture
console/network traffic. The Safari equivalent of a "browser in your agent," built native with
**zero runtime dependencies**.

Two complementary halves:

- **Native driver** (`driver/`) — a single Swift binary that speaks MCP over stdio and drives
  Safari via AppleScript (`do JavaScript`), CoreGraphics (`screencapture`, CGEvent), and
  `NSPasteboard`. Hand-rolled JSON-RPC and WebSocket — no SDK, no `ws`, no Node.
- **Safari extension** (`extension/`) — a vanilla-JS MV3 extension whose only job is to capture
  the current site's **console + network** and stream it to the driver over a loopback
  WebSocket. Its popup is a small status panel (bridge health, capture state, event counts, and
  per-site permission management). No API key, no embedded chat.

```
MCP client ──stdio(MCP)──▶ safari-mcp (Swift) ──AppleScript/CGEvent──▶ Safari ──▶ pages
                                  ▲
                                  │ ws://127.0.0.1:8787 (console/network telemetry)
                                  │
                       Safari extension (MV3) ──▶ status + permission popup
```

## Why this shape

Safari's extension model is hostile to silent automation (per-site prompts, sandboxing,
unsigned-extension resets). So the **heavy lifting is native** (AppleScript + CoreGraphics),
which needs only one-time macOS permission grants — and the **extension stays tiny**, doing the
one thing native automation can't easily do: capture console/network from inside the page. See
`RESEARCH.md` for the verified platform constraints and `PLAN.md` for the design.

## Requirements

- macOS with Safari, and Xcode (for building/installing the extension).
- A Swift toolchain (`swift`), Python 3, and Node (for the test runners only).
- A code-signing identity. A stable identity (Apple Development or Developer ID) is strongly
  recommended so macOS permission grants persist across rebuilds.

## Build & install

**Quick start** (build the driver and register it globally in one command):

```sh
# Optional but recommended: a stable signing identity so macOS permission grants persist.
export SMCP_SIGN_IDENTITY="Apple Development: you@example.com"
make install          # builds + signs the driver, registers it as a global MCP server
make build-extension  # generates the Xcode project; then build/run it once (step 2 below)
```

Then restart your MCP client and finish the Safari steps below. The two halves in detail:

### 1. Driver

```sh
# Signs with $SMCP_SIGN_IDENTITY (defaults to ad-hoc "-"). Set it to a stable identity so the
# macOS Automation grant sticks across rebuilds, e.g. SMCP_SIGN_IDENTITY="Apple Development: you@example.com".
./scripts/build-driver.sh release
# Register it (the script prints the exact binary path; `make install` does this for you):
claude mcp add safari --scope user -- "$(cd driver && swift build -c release --show-bin-path)/safari-mcp"
```

One-time macOS grants (per the signing identity):
- Approve the **Automation** prompt for Safari the first time a tool runs
  (System Settings ▸ Privacy & Security ▸ Automation).
- Safari ▸ Settings ▸ Advanced ▸ **Show features for web developers**, then
  Develop ▸ **Allow JavaScript from Apple Events**.
- For `safari_screenshot`: **Screen Recording** permission (prompted on first use).
- For `safari_computer` with `real: true`: **Accessibility** permission (prompted on first use).

### 2. Extension

```sh
./scripts/build-extension.sh             # converts extension/ → an Xcode project under app/
open app/SafariMCP/SafariMCP.xcodeproj
```

In Xcode: set your signing **Team** on both targets (a free Apple ID works), then **Product ▸
Run** to install. In Safari: Develop ▸ **Allow Unsigned Extensions** (resets each launch unless
the extension is signed by a real Developer ID), Settings ▸ Extensions ▸ enable **Safari MCP**,
then grant a site capture via the toolbar popup. `extension/` is the source of truth; `app/` is a
regenerated build artifact (gitignored) — re-run `build-extension.sh` after editing `extension/`.

> Driver changes require a fresh MCP-client session to load (the server set is fixed at session
> start). Extension changes hot-reload in Safari, but reinstalling the app can disable the
> extension — re-enable it in Settings ▸ Extensions if so.

## Per-site permissions

Read-only tools (list tabs, read page text/DOM, screenshots, console/network) work anywhere.
Anything that **acts on a page or runs JS** (click, type, set value, scroll, `run_js`, navigate,
reload, computer-use input, storage writes, file upload) is **gated per origin**:

- The first time the agent acts on an unauthorized site, the driver pops a native **Allow / Deny**
  dialog. Allow adds the origin to a persistent allowlist; the agent can never self-authorize.
- Grant/revoke any time from the extension popup. Capture is folded into the same auth: a site
  must be allowed before console/network stream.

## MCP tools

| Tool | What it does |
|---|---|
| `safari_list_tabs` | List all tabs across windows (with stable `tabId`s) |
| `safari_navigate` | Open a URL in a tab (waits for load) |
| `safari_new_tab` / `safari_close_tab` / `safari_activate_tab` | Tab management (new tabs open in the background) |
| `safari_reload` / `safari_back` / `safari_forward` | History navigation |
| `safari_resize_window` | Resize a window (responsive testing) |
| `safari_get_page_text` | Visible page text (innerText) |
| `safari_read_page` | Snapshot interactive elements with stable `ref`s |
| `safari_find` | Find elements by CSS selector or visible text |
| `safari_inspect` | Computed styles, bounding box, attributes, `outerHTML` |
| `safari_click` / `safari_type` / `safari_set_value` | Interact with elements by `ref` / `selector` / `text` |
| `safari_scroll` | Scroll by direction/amount, or a `ref`/`selector` into view |
| `safari_wait_for` | Wait for a selector / text / network-idle (with timeout) |
| `safari_run_js` | Run arbitrary JS, return its result (escape hatch) |
| `safari_screenshot` | PNG of a Safari window — works on background/occluded windows |
| `safari_computer` | Screenshot-driven mouse/keyboard control with an on-page cursor overlay |
| `safari_upload` | Upload a local file into a file input / drop zone (no native picker) |
| `safari_clipboard` | Read/write the macOS clipboard (copy/paste workflows) |
| `safari_storage` | Read/write localStorage, sessionStorage, cookies |
| `safari_read_console` / `safari_read_network` | Captured console / network, filterable (needs the extension) |
| `safari_bridge_status` | Is the extension connected? how much is buffered? |
| `safari_permissions` | List or revoke per-site action permissions |

Notes:
- Most tools take an optional `tabId` (from `safari_list_tabs`); omit for the active tab. Tabs in
  non-front and occluded windows are addressed reliably and driven in the background.
- `safari_computer` defaults to **DOM-synthesized** input dispatched inside the target tab — it
  works in the background, needs no Accessibility grant, and draws a cursor/click overlay. Set
  `real: true` for true OS-level CGEvent input (needs the window frontmost + Accessibility) for
  sites that reject synthetic events.
- `safari_read_network` captures request/response headers and (for JSON/text responses) bodies up
  to 16KB; sensitive headers are redacted unless `includeSecrets: true`.

## Tests

```sh
make test          # runs both self-tests (neither needs Safari)
```

- `protocol_selftest.py` — MCP protocol layer (initialize, tools/list, tools/call, errors).
- `bridge_selftest.mjs` — the console/network bridge, with a Node WS client standing in for the
  extension.

## Repo layout

```
driver/        Swift package — the native MCP driver
extension/     MV3 Safari extension source (the single source of truth)
scripts/       build-driver.sh, build-extension.sh, patch-xcodeproj.py, make-icons.py
app/           generated Xcode project (gitignored build artifact)
PLAN.md        architecture;  RESEARCH.md  verified platform findings
```

## License

Apache License 2.0 — see [LICENSE](LICENSE).

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [erwinzhang7](https://github.com/erwinzhang7)
- **Source:** [erwinzhang7/safari-mcp](https://github.com/erwinzhang7/safari-mcp)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-erwinzhang7-safari-mcp
- Seller: https://agentstack.voostack.com/s/erwinzhang7
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
