@spboucher/echo-mcp-server
Dependency-free local MCP server over stdio with a single echo tool, for testing client configuration.
- Latest version
- v1.0.1
- Licence
- MIT
- Updated
- 4 h ago
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.
Installing only copies or configures. Nothing is executed for you. The Skills CLI verifies the checksum before writing files.
Open a page, read it, screenshot it, close it (Claude Code)
The server opens its own Safari window, reads the title and links, saves a screenshot and closes what it opened. Real session, Claude Code 2.1.322 with Fable 5.2, with version 1.0.0 installed from this registry; inputs are test fixtures.
With the safari MCP tools: open https://example.com in a new Safari window of your own, read the page title and the main heading, list the links on the page, save a screenshot as example.png in the current folder, then close the window you opened. Report in at most 8 lines.Open a page, read it, screenshot it, close it (Codex)
The server opens its own Safari window, reads the title and links, saves a screenshot and closes what it opened. Real session, Codex CLI 0.167.1 with GPT-6.1-Sol, with version 1.0.0 installed from this registry; inputs are test fixtures.
With the safari MCP tools: open https://example.com in a new Safari window of your own, read the page title and the main heading, list the links on the page, save a screenshot as example.png in the current folder, then close the window you opened. Report in at most 8 lines.Screenshots supplied by the publisher. The registry serves them from the release archive and does not verify what they show.
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.
SAFARI_MCP_SCOPE=all.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.confirm_sensitive: true.evaluate_js is off unless you set SAFARI_MCP_ALLOW_EVAL=1.SAFARI_MCP_FILE_ROOT only. Nothing is overwritten.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.
screenshot only: Screen Recording permission for that same app.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
# 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
# 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"
// Cursor: .cursor/mcp.json
{ "mcpServers": { "safari": { "type": "stdio", "command": "node", "args": ["/abs/path/safari-mcp/server.mjs"], "env": { "SAFARI_MCP_ALLOW_DOMAINS": "example.org" } } } }
| Variable | Effect | Default |
|---|---|---|
SAFARI_MCP_ALLOW_DOMAINS | Only these sites (and subdomains) | any http(s) site |
SAFARI_MCP_BLOCK_DOMAINS | Never these sites | none |
SAFARI_MCP_FILE_ROOT | Directory for uploads, downloads, screenshots | working directory |
SAFARI_MCP_SCOPE=all | Also see and act on tabs you opened | own window only |
SAFARI_MCP_ALLOW_EVAL=1 | Enable evaluate_js | off |
SAFARI_MCP_ALLOW_FILE_URLS=1 | Allow file:// pages | off |
SAFARI_MCP_DIALOGS=dismiss | Answer page confirm() with "cancel" | accept |
| Group | Tools |
|---|---|
| Session | safari_status, open_url, navigate (goto / back / forward / reload), list_tabs, select_tab, close_tab, resize_window |
| Read | page_info, snapshot, read_text, read_html, query_elements, list_links, extract_tables, list_forms |
| Act | click, hover, fill, fill_form, select_option, set_checked, press_key, submit_form, scroll, wait_for |
| Files and data | upload_file, download, fetch_text, screenshot |
| Opt-in | evaluate_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.
input and change
events, which React- and Vue-style pages observe.osascript, never
pasted into AppleScript or JavaScript source. No shell is ever invoked.alert, confirm and prompt are intercepted and reported, so a page cannot
freeze the session.File for uploads — no system file dialog.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.
select_tab is called with bring_to_front.| Tool | What it does |
|---|---|
| safari_status | Check that Safari can be driven and show the active policy |
| open_url | Open a URL in the session window and wait for it |
| navigate | Load a URL, go back or forward, reload |
| list_tabs | Tabs of the session window |
| select_tab | Switch tab |
| close_tab | Close a session tab or the session window |
| resize_window | Resize the session window |
| page_info | URL, title, load state, dialogs, cross-origin frames |
| snapshot | Interactive elements with refs, names, values and state |
| read_text | Visible text of the page or an element |
| read_html | HTML of the page or an element |
| query_elements | Elements matching a CSS selector |
| list_links | Links with their text |
| extract_tables | Tables as headers and rows |
| list_forms | Forms and their fields |
| click | Click an element and report any navigation |
| hover | Hover an element |
| fill | Fill a field (sensitive fields need confirmation) |
| fill_form | Fill several fields in one call |
| select_option | Choose an option of a select |
| set_checked | Check or uncheck |
| press_key | Send a key; Enter submits the form |
| submit_form | Submit a form |
| scroll | Scroll the page or to an element |
| wait_for | Wait for a selector, text, URL or load |
| upload_file | Attach a local file to a file input |
| download | Download a URL with the page's session |
| fetch_text | GET text or JSON with the page's session |
| screenshot | Capture the session window to a PNG, with a preview |
| evaluate_js | Run JavaScript in the page (off unless the operator enables it) |
| Variable | Required | Purpose |
|---|---|---|
| SAFARI_MCP_ALLOW_DOMAINS | optional | Comma-separated sites the server may visit (with their subdomains). Empty: any http(s) site. |
| SAFARI_MCP_BLOCK_DOMAINS | optional | Comma-separated sites the server must never visit. Wins over the allow list. |
| SAFARI_MCP_FILE_ROOT | optional | Only directory used for uploads, downloads and screenshots (default: working directory). |
| SAFARI_MCP_SCOPE | optional | Set to "all" to let the server see and act on tabs the user opened. Default: its own window only. |
| SAFARI_MCP_ALLOW_EVAL | optional | Set to 1 to enable the evaluate_js tool. |
| SAFARI_MCP_DIALOGS | optional | "accept" (default) or "dismiss": how page confirm() dialogs are answered. |
Select a file to preview it. Files are shown as plain text and never executed.
lib/osa.mjslib/page.jslib/safari.mjstest/offline.test.mjstest/offline.test.mjstest/safari.test.mjsStatic checks are advisory. They never certify that a package is safe. Compatibility entries are publisher claims unless marked verified.
| Version | Published | Size | SHA-256 | State |
|---|---|---|---|---|
| 1.0.1latest | Nov 10, 2026 | 284 kB | fe0511bd5b92… | published |
| 1.0.0 | Nov 10, 2026 | 48 kB | 8d46c4d16d55… | published |
Adds screenshots of real Claude Code and Codex sessions (examples/). No code change.
Dependency-free local MCP server over stdio with a single echo tool, for testing client configuration.
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.
Offline MCP server keeping a hash-chained, append-only ledger for preregistered research: hypotheses, protocol freeze and amendments, decisions, deviations, gates, runs, spending, results.