Skip to content
SKILLS
MCP ServerPublisher identity verifiedNo findings from static checks

@spboucher/safari-mcpv1.0.0

MCP server that drives Safari on macOS through AppleScript: navigation, reading, forms, uploads, downloads with the page's session, screenshots. Works in its own window, with domain policy and sensitive-field guards.

  • downloadable
  • installable
  • executable
Version
1.0.0
Published
Nov 10, 2026
Licence
MIT
Archive
48 kB
Files
14
Transport
stdio
Tools
30

Install

Register the local server

claude mcp add --transport stdio --env SAFARI_MCP_ALLOW_DOMAINS=<value> --env SAFARI_MCP_BLOCK_DOMAINS=<value> --env SAFARI_MCP_FILE_ROOT=<value> --env SAFARI_MCP_SCOPE=<value> --env SAFARI_MCP_ALLOW_EVAL=<value> --env SAFARI_MCP_DIALOGS=<value> safari-mcp -- node server.mjs
.mcp.json (project scope)
{
  "mcpServers": {
    "safari-mcp": {
      "command": "node",
      "args": [
        "server.mjs"
      ],
      "env": {
        "SAFARI_MCP_ALLOW_DOMAINS": "${SAFARI_MCP_ALLOW_DOMAINS}",
        "SAFARI_MCP_BLOCK_DOMAINS": "${SAFARI_MCP_BLOCK_DOMAINS}",
        "SAFARI_MCP_FILE_ROOT": "${SAFARI_MCP_FILE_ROOT}",
        "SAFARI_MCP_SCOPE": "${SAFARI_MCP_SCOPE}",
        "SAFARI_MCP_ALLOW_EVAL": "${SAFARI_MCP_ALLOW_EVAL}",
        "SAFARI_MCP_DIALOGS": "${SAFARI_MCP_DIALOGS}"
      }
    }
  }
}

Environment variables — set locally, never sent to the registry

VariableRequiredPurpose
SAFARI_MCP_ALLOW_DOMAINSoptionalComma-separated sites the server may visit (with their subdomains). Empty: any http(s) site.
SAFARI_MCP_BLOCK_DOMAINSoptionalComma-separated sites the server must never visit. Wins over the allow list.
SAFARI_MCP_FILE_ROOToptionalOnly directory used for uploads, downloads and screenshots (default: working directory).
SAFARI_MCP_SCOPEoptionalSet to "all" to let the server see and act on tabs the user opened. Default: its own window only.
SAFARI_MCP_ALLOW_EVALoptionalSet to 1 to enable the evaluate_js tool.
SAFARI_MCP_DIALOGSoptional"accept" (default) or "dismiss": how page confirm() dialogs are answered.
More steps
  1. 1Set the required environment variables locally

    SAFARI_MCP_ALLOW_DOMAINS, SAFARI_MCP_BLOCK_DOMAINS, SAFARI_MCP_FILE_ROOT, SAFARI_MCP_SCOPE, SAFARI_MCP_ALLOW_EVAL, SAFARI_MCP_DIALOGS — configured on your machine only; never sent to the registry.

  2. 2Optional: download the listing's source archive for review

    skills download @spboucher/safari-mcp@1.0.0
  • Declared permissions: shell, network, browser, filesystem:read, filesystem:write.
  • This server runs locally on your machine with your user's privileges. Review the source before running it; the registry does not execute or host it.

Installing only copies or configures. Nothing is executed for you. The Skills CLI verifies the checksum before writing files.

Documentation

safari-mcp

An MCP server that lets an agent use Safari on your Mac through AppleScript: open pages, read them, click, fill forms, attach files, download files with the page's own sign-in, take screenshots.

Why Safari rather than a headless browser: it is the browser you are already signed in to. The agent can read a page behind your university proxy or download a report from an internal tool without ever seeing a password. That is also why this server is built defensively.

What it will and will not do

  • Its own window. The server opens a dedicated Safari window and works only there. Tabs you already had open are invisible to it — it cannot list, read, switch or close them — unless you start it with SAFARI_MCP_SCOPE=all.
  • Domain policy. SAFARI_MCP_ALLOW_DOMAINS restricts it to named sites; SAFARI_MCP_BLOCK_DOMAINS excludes sites and wins over the allow list. The tab's current address is re-checked before every tool call, because pages redirect.
  • Secrets. It never reads cookies, browser storage or saved passwords. Password, card and one-time-code fields are redacted in every output, and typing into them is refused unless the call carries confirm_sensitive: true.
  • No arbitrary script by default. evaluate_js is off unless you set SAFARI_MCP_ALLOW_EVAL=1.
  • Files stay in one directory. Uploads are read from, and downloads and screenshots written to, SAFARI_MCP_FILE_ROOT only. Nothing is overwritten.
  • Untrusted content. Tool results carry a notice that page text is data, not instructions. This reduces the risk of prompt injection; it does not remove it. Use the allow list for anything unattended.

It cannot stop an agent from doing something unwise that you allowed. submit_form and click act with your identity on the sites you let it visit.

Requirements

  • macOS with Safari, Node.js 20 or newer.
  • Safari → Settings → Advanced → "Show features for web developers", then Settings → Developer → Allow JavaScript from Apple Events.
  • On first use macOS asks whether the app running the server (your terminal, Claude Code, …) may control Safari: allow it (System Settings → Privacy & Security → Automation).
  • For screenshot only: Screen Recording permission for that same app.

Install

shell
skills download @spboucher/safari-mcp --extract ./safari-mcp   # or download the archive and verify its SHA-256
cd safari-mcp
npm ci
npm test        # offline tests; does not touch Safari
shell
# Claude Code — restricted to two sites, files under ~/Downloads/agent
claude mcp add --transport stdio \
  --env SAFARI_MCP_ALLOW_DOMAINS=example.org,intranet.example.com \
  --env SAFARI_MCP_FILE_ROOT=$HOME/Downloads/agent \
  safari -- node /abs/path/safari-mcp/server.mjs
toml
# Codex: ~/.codex/config.toml
[mcp_servers.safari]
command = "node"
args = ["/abs/path/safari-mcp/server.mjs"]
[mcp_servers.safari.env]
SAFARI_MCP_ALLOW_DOMAINS = "example.org"
json
// Cursor: .cursor/mcp.json
{ "mcpServers": { "safari": { "type": "stdio", "command": "node", "args": ["/abs/path/safari-mcp/server.mjs"], "env": { "SAFARI_MCP_ALLOW_DOMAINS": "example.org" } } } }
VariableEffectDefault
SAFARI_MCP_ALLOW_DOMAINSOnly these sites (and subdomains)any http(s) site
SAFARI_MCP_BLOCK_DOMAINSNever these sitesnone
SAFARI_MCP_FILE_ROOTDirectory for uploads, downloads, screenshotsworking directory
SAFARI_MCP_SCOPE=allAlso see and act on tabs you openedown window only
SAFARI_MCP_ALLOW_EVAL=1Enable evaluate_jsoff
SAFARI_MCP_ALLOW_FILE_URLS=1Allow file:// pagesoff
SAFARI_MCP_DIALOGS=dismissAnswer page confirm() with "cancel"accept

Tools

GroupTools
Sessionsafari_status, open_url, navigate (goto / back / forward / reload), list_tabs, select_tab, close_tab, resize_window
Readpage_info, snapshot, read_text, read_html, query_elements, list_links, extract_tables, list_forms
Actclick, hover, fill, fill_form, select_option, set_checked, press_key, submit_form, scroll, wait_for
Files and dataupload_file, download, fetch_text, screenshot
Opt-inevaluate_js

The usual loop is open_url → snapshot → act on a ref → wait_for / snapshot. Elements can also be addressed by visible text, field label or CSS selector; when several match, the error lists the candidates. Searches go through open shadow roots and same-origin iframes.

How it stays reliable

  • Page readiness. Safari reports a tab's destination address as soon as a navigation starts, while the old document still answers scripts. The server waits until the document's own address has caught up and it is fully loaded, so it never acts on the page being left.
  • Framework inputs. Fields are set through the native value setter with input and change events, which React- and Vue-style pages observe.
  • No injection. Scripts are fixed; every value travels as an argument to osascript, never pasted into AppleScript or JavaScript source. No shell is ever invoked.
  • Dialogs. alert, confirm and prompt are intercepted and reported, so a page cannot freeze the session.
  • Downloads and uploads move bytes through the page in chunks: fetch with the page's cookies for downloads, a constructed File for uploads — no system file dialog.

Verified

test/safari.test.mjs drives the real Safari through the MCP protocol on a local fixture site: navigation, redirects, history, tabs, late content, shadow DOM, iframes, ambiguous targets, dialogs, a framework-style form, the sensitive-field guard and redaction, file upload (bytes checked by hash), a cookie-protected download (checked by hash), same-origin enforcement, screenshots, the domain policy applied to a page that moves, stale refs — and finally that the user's own windows are exactly as they were. test/realweb.test.mjs repeats a read-only flow on example.com and Wikipedia.

Limits

  • Tested on Safari 27.0 / macOS 27.0 only.
  • Cross-origin iframes cannot be read or driven: open their URL in a tab.
  • Events are synthetic: pages react, the browser does not (no shortcuts, no autofill), and some sites reject them.
  • A dialog raised before the server first touches a page still blocks until dismissed by hand.
  • Private windows, Reader, PDFs displayed in a tab and browser settings are not reachable.
  • Uploads up to 20 MB, downloads up to 50 MB.
  • The server takes no part in solving CAPTCHAs or bypassing bot checks.
  • While it runs, a Safari window is visible on your screen. It is not brought to the front unless select_tab is called with bring_to_front.

Tools

30 tools · declared by the publisher
ToolWhat it does
safari_statusCheck that Safari can be driven and show the active policy
open_urlOpen a URL in the session window and wait for it
navigateLoad a URL, go back or forward, reload
list_tabsTabs of the session window
select_tabSwitch tab
close_tabClose a session tab or the session window
resize_windowResize the session window
page_infoURL, title, load state, dialogs, cross-origin frames
snapshotInteractive elements with refs, names, values and state
read_textVisible text of the page or an element
read_htmlHTML of the page or an element
query_elementsElements matching a CSS selector
list_linksLinks with their text
extract_tablesTables as headers and rows
list_formsForms and their fields
clickClick an element and report any navigation
hoverHover an element
fillFill a field (sensitive fields need confirmation)
fill_formFill several fields in one call
select_optionChoose an option of a select
set_checkedCheck or uncheck
press_keySend a key; Enter submits the form
submit_formSubmit a form
scrollScroll the page or to an element
wait_forWait for a selector, text, URL or load
upload_fileAttach a local file to a file input
downloadDownload a URL with the page's session
fetch_textGET text or JSON with the page's session
screenshotCapture the session window to a PNG, with a preview
evaluate_jsRun JavaScript in the page (off unless the operator enables it)

Environment variables

VariableRequiredPurpose
SAFARI_MCP_ALLOW_DOMAINSoptionalComma-separated sites the server may visit (with their subdomains). Empty: any http(s) site.
SAFARI_MCP_BLOCK_DOMAINSoptionalComma-separated sites the server must never visit. Wins over the allow list.
SAFARI_MCP_FILE_ROOToptionalOnly directory used for uploads, downloads and screenshots (default: working directory).
SAFARI_MCP_SCOPEoptionalSet to "all" to let the server see and act on tabs the user opened. Default: its own window only.
SAFARI_MCP_ALLOW_EVALoptionalSet to 1 to enable the evaluate_js tool.
SAFARI_MCP_DIALOGSoptional"accept" (default) or "dismiss": how page confirm() dialogs are answered.

Files

14 files · 163 kB unpacked

Select a file to preview it. Files are shown as plain text and never executed.

Security & permissions

Declared permissions

  • shell
  • network
  • browser
  • filesystem:read
  • filesystem:write

Static checks

  • lowscript spawns other processeslib/osa.mjs
  • lowscript appears to make network requestslib/page.js
  • lowscript spawns other processeslib/safari.mjs
  • lowscript appears to make network requeststest/offline.test.mjs
  • lowscript spawns other processestest/offline.test.mjs
  • lowscript spawns other processestest/safari.test.mjs

Static checks are advisory. They never certify that a package is safe. Compatibility entries are publisher claims unless marked verified.

Compatibility

  • claude-code · macos · claimed
  • codex · macos · claimed
  • cursor · macos · claimed
  • generic-mcp · macos · claimed

Versions

1 release · immutable
VersionPublishedSizeSHA-256State
1.0.0latestNov 10, 202648 kB8d46c4d16d55…published

Publication history

  1. release.publish@spboucher/safari-mcp@1.0.0by Simon-Pierre Boucher
  2. artifact.create@spboucher/safari-mcpby Simon-Pierre Boucher
  • MCP ServerVerified publisher

    @spboucher/pangram-experiment-mcp

    MCP server for text-revision experiments that record the Pangram detector score as an observed outcome: frozen editorial plan, one submission per step, a real evaluation of every version, preservation checks, full history, chart and report.

    Latest version
    v1.0.0
    Licence
    MIT
    Updated
    1 h ago
  • MCP ServerVerified publisher

    @spboucher/manuscript-audit-mcp

    MCP server for deterministic, offline audits of LaTeX and Markdown manuscripts: citations, cross-references, numbers, statistics reporting, tables, claims, style, replication statements, referee-report scaffold, version comparison.

    Latest version
    v1.0.0
    Licence
    MIT
    Updated
    2 h ago
  • MCP ServerVerified publisher

    @spboucher/xlsx-audit-mcp

    MCP server that audits Excel workbooks without Excel: errors, hard-coded numbers, broken formula patterns, circular references, controls, stale values, comparison with a reference and a rubric-based grading aid. Read-only, dependency-free reader.

    Latest version
    v1.0.0
    Licence
    MIT
    Updated
    3 h ago

↑↓ to navigate · enter to open · esc to close