
Cli Anything Safari
- 366 installs
- 46.6k repo stars
- Updated August 3, 2026
- hkuds/cli-anything
cli-anything-safari is a Python Click CLI skill that wraps the safari-mcp MCP server to expose all 84 Safari automation tools for developers who need native WebKit browser control on macOS.
About
cli-anything-safari is a macOS-only Safari browser automation skill from the hkuds/cli-anything family. It wraps the Node.js safari-mcp MCP server in a Python Click CLI so coding agents and shell scripts can drive real Safari sessions that keep native logins and WebKit rendering. Every Click command is generated automatically from safari-mcp's bundled resources/tools.json schema, exposing all 84 MCP tools with 1:1 parity and schema-accurate arguments to prevent manual drift. Developers reach for cli-anything-safari when Chromium drivers miss WebKit-specific behavior, Safari-only auth cookies, or macOS browser workflows during agent-driven testing, page inspection, and automation.
- Safari automation through cli-anything
- WebKit-specific compatibility testing
- macOS-native browser agent control
- Supports frontend verification flows
- Complements Chromium automation skills
Cli Anything Safari by the numbers
- 366 all-time installs (skills.sh)
- +15 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #684 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hkuds/cli-anything --skill cli-anything-safariAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 366 |
|---|---|
| repo stars | ★ 46.6k |
| Last updated | August 3, 2026 |
| Repository | hkuds/cli-anything ↗ |
How do agents automate real Safari on macOS?
Enable agents to control Safari for WebKit-specific testing, automation, page inspection, and macOS browser workflows that differ from Chromium-based drivers.
Who is it for?
macOS developers and agent authors who must test or automate WebKit-specific behavior in real Safari instead of Chromium-based headless browsers.
Skip if: Developers on Linux or Windows, teams standardized on Playwright or Puppeteer for Chromium-only CI, or projects that do not require native Safari sessions.
When should I use this skill?
A coding agent needs to control Safari on macOS for WebKit testing, authenticated page inspection, or automation that Chromium drivers cannot reproduce.
What you get
Schema-generated Click CLI commands, live Safari browser sessions, page inspection output, and WebKit automation traces from 84 safari-mcp tools.
- Auto-generated Click CLI commands
- Live Safari automation sessions
- WebKit page inspection output
By the numbers
- Exposes all 84 safari-mcp MCP tools as Click CLI commands
- Generates commands from bundled resources/tools.json tool schema
- Wraps the Node.js safari-mcp server in a Python Click CLI
Files
cli-anything-safari
A command-line interface for Safari browser automation on macOS. Wraps the `safari-mcp` Node.js MCP server in a Python Click CLI.
Feature parity is guaranteed. Every Click command is generated automatically from safari-mcp's tool schema (bundled as resources/tools.json). All 84 tools are reachable with the exact argument names and types the MCP server expects.
When to use this CLI
Each CLI invocation spawns a fresh subprocess, so there is per-call overhead. If your agent speaks MCP natively (Claude Code, Cursor, Cline, etc.), using safari-mcp directly over MCP stdio will be faster.
Use this CLI when:
- Your agent framework does not speak MCP (Codex CLI, GitHub Copilot
CLI, custom scripts, older agent frameworks).
- You need to script browser automation from bash —
cli-anything-safari --json tool snapshot | jq '...'.
- You run in CI/CD and want cron-able, subprocess-friendly output.
- You're debugging interactively from Terminal.
Installation
Prerequisites
1. macOS — Safari MCP is macOS-only. 2. Safari — already installed on macOS. 3. Node.js 18+ — brew install node or from https://nodejs.org/ 4. Python 3.10+ 5. Enable Apple Events for Safari: Safari → Develop → Allow JavaScript from Apple Events
Install the CLI
cd safari/agent-harness
pip install -e .The first tool call will download the safari-mcp npm package (one-time, a few MB).
Command Structure
The CLI has 5 top-level commands:
| Command | Purpose |
|---|---|
tool | Call any of safari-mcp's 84 tools (dynamic, schema-driven) |
tools | Inspect the bundled tool registry (list, describe, count) |
raw | Escape hatch — call a tool by full name with raw JSON args |
session | In-memory session state (last URL, current tab) |
repl | Interactive REPL (default when no subcommand given) |
Usage Examples
Discover the tool surface
# Count of tools (sanity check — must match safari-mcp's registered tools)
cli-anything-safari tools count
# → 84
# List every tool
cli-anything-safari tools list
cli-anything-safari tools list --filter click # filter by substring
# Full schema for one tool (JSON or human format)
cli-anything-safari tools describe safari_scroll
cli-anything-safari --json tools describe safari_clickCall a tool (schema-driven)
# Navigate
cli-anything-safari tool navigate --url https://example.com
# Take a snapshot (preferred over screenshot — structured text with ref IDs)
cli-anything-safari --json tool snapshot
# Click by ref (refs come from snapshot; they expire on the next snapshot!)
cli-anything-safari tool click --ref 0_5
# Click by selector or visible text
cli-anything-safari tool click --selector "#submit"
cli-anything-safari tool click --text "Log in"
# Fill a field
cli-anything-safari tool fill --selector "#email" --value "user@example.com"
# Scroll by direction/amount (NOT x/y — note the schema!)
cli-anything-safari tool scroll --direction down --amount 500
# Drag one element onto another
cli-anything-safari tool drag \
--source-selector ".card" \
--target-selector ".trash"
# Screenshot — returns base64 JPEG in stdout. Decode with:
cli-anything-safari --json tool screenshot --full-page \
| python3 -c "import sys,json,base64; \
d=json.load(sys.stdin); \
open('/tmp/shot.jpg','wb').write(base64.b64decode(d['data']))"
# Save as PDF (this one writes to disk directly)
cli-anything-safari tool save-pdf --path /tmp/page.pdf
# Evaluate JavaScript (note: parameter is --script, not --code)
cli-anything-safari tool evaluate --script "document.title"Navigate and read in one round-trip
cli-anything-safari --json tool navigate-and-read --url https://example.comForm fill (bulk)
safari_fill_form takes an array of {selector, value} objects. Pass it as a JSON string:
cli-anything-safari tool fill-form --fields '[
{"selector": "#email", "value": "user@example.com"},
{"selector": "#password", "value": "hunter2"}
]'Run cli-anything-safari tools describe safari_fill_form to see the exact schema, including any new fields safari-mcp adds upstream.
Network monitoring
cli-anything-safari tool start-network-capture
cli-anything-safari tool navigate --url https://example.com
cli-anything-safari --json tool network
cli-anything-safari tool performance-metricsStorage
cli-anything-safari tool get-cookies
cli-anything-safari tool set-cookie --name session --value abc123 --domain example.com
cli-anything-safari tool local-storage --key theme
# export-storage returns JSON to stdout — no --path arg. Pipe to a file:
cli-anything-safari --json tool export-storage > /tmp/storage.jsonRaw JSON escape hatch
When you need to pass a complex nested object or want to drive the CLI from a pre-built JSON blob:
cli-anything-safari raw safari_evaluate \
--json-args '{"code":"[...document.querySelectorAll(\"a\")].map(a => a.href)"}'Interactive REPL
cli-anything-safariThe REPL banner prints the absolute path to this SKILL.md so agents can self-discover capabilities.
JSON Output
All commands support --json as a global flag:
cli-anything-safari --json tool snapshot
cli-anything-safari --json tool list-tabs
cli-anything-safari --json tools listState Management
The CLI maintains a small amount of in-memory state for REPL display only:
- `last_url` — last URL the CLI navigated to (updated after every
successful tool navigate, tool navigate-and-read, or tool new-tab)
- `current_tab_index` — last known active tab index
There is no persistent session, no undo/redo, no document model. Every CLI invocation starts with fresh state. Safari MCP itself is stateless per-call: each tool command spawns a fresh npx safari-mcp subprocess, performs the action, and exits. This is a deliberate design choice; see HARNESS.md and TEST.md for the reasoning behind the deviation from the standard undo/redo pattern.
Output Formats
All commands support dual output modes:
- Human-readable (default): indented key-value text for
dict
results, bullet lists for arrays, plain text otherwise
- Machine-readable (
--jsonflag): structured JSON for agent
consumption
# Human output
cli-anything-safari tool snapshot
# JSON output for agents
cli-anything-safari --json tool snapshot
cli-anything-safari --json tools list
cli-anything-safari --json tools describe safari_clickFor AI Agents
When using this CLI programmatically:
1. Always use `--json` flag for parseable output. 2. Check return codes — 0 for success, non-zero for errors (URL validation failures, MCP call failures, invalid JSON args). 3. Parse stderr for error messages; use stdout for data. 4. File-handling tools have inconsistent path arg names — always check tools describe <name> first:
tool save-pdf --path /tmp/x.pdftool upload-file --selector ... --file-path /tmp/x.txt(note:--file-path, not--path)tool export-storage— no path arg; pipe JSON output to a filetool import-storage --path /tmp/x.jsontool screenshot/screenshot-element— return base64 in
the JSON response, no path arg (decode it yourself) 5. Snapshot before click — refs from tool snapshot expire on the next snapshot. Always snapshot → find ref → click in close succession. 6. Discover tools via `tools list` — the bundled registry is the source of truth for what's available. Do not hard-code tool names that may change upstream. 7. Use `tools describe <name>` to learn the exact schema (required args, enum choices, JSON-typed args) before constructing a call. Never assume parameter names from the description — for example, safari_evaluate takes --script (not --code) even though the description says "JavaScript code to execute".
Agent-Specific Guidance
Finding the right tool
Use the introspection commands. The CLI is guaranteed to reflect the MCP server 1:1:
# Find all click-related tools
cli-anything-safari tools list --filter click
# Get the full schema (including every argument with type, description,
# required/optional, enum choices, defaults)
cli-anything-safari --json tools describe safari_clickTool selection strategy
1. `tool snapshot` over tool screenshot — structured text with ref IDs is orders of magnitude cheaper and carries the refs needed for clicks. 2. `tool click --ref` over tool click --selector — refs are stable within a single snapshot, selectors may be brittle. 3. `tool navigate-and-read` over navigate + read-page — saves one round-trip. 4. `tool click-and-read` over click + read-page — saves one round-trip. 5. `tool native-click` only when regular click fails with 405/403 (WAF blocks, G2, Cloudflare) — it physically moves the cursor.
Refs Expire
Refs from tool snapshot expire when you take a new snapshot:
- First snapshot: refs
0_1,0_2,0_3... - Second snapshot: refs
1_1,1_2,1_3...
Always snapshot → click in close succession. If in doubt, snapshot again.
Tab Ownership Safety
Safari MCP tracks tab ownership per session. Tools that modify a tab (navigate, click, fill) are blocked on tabs the session did not open. To operate on a specific page, always start with tool new-tab --url ....
Error Handling
Common errors:
npx not found→ install Node.js 18+safari-mcp package not found on npm registry→ check networkNot macOS→ harness is macOS-onlyAppleScript denied→ enable "Allow JavaScript from Apple Events" in Safari → DevelopBlocked URL scheme: file→ URL validation rejected the input (by design)
URL Validation
The CLI validates URLs before passing them to safari_navigate, safari_navigate_and_read, and safari_new_tab. Blocked schemes: file, javascript, data, vbscript, about, chrome, safari, webkit, x-apple, and other browser-internal schemes. The raw command also enforces this for navigation tools.
Multi-Session Warning
Safari MCP enforces a single active session by killing stale Node.js processes older than 10 seconds. If you run two CLI instances at once, one will kill the other's backend. There is currently no daemon mode — for latency-sensitive workflows, drive the CLI from a long-lived Python script that imports `cli_anything.safari.utils.safari_backend.call()` directly to avoid re-spawning the subprocess on every invocation.
Links
Security Considerations
URL Validation
All navigation tools (tool navigate, tool navigate-and-read, tool new-tab, and raw safari_navigate*) pass the url argument through utils/security.py which blocks dangerous schemes and optionally blocks private networks (set CLI_ANYTHING_SAFARI_BLOCK_PRIVATE=1).
Tab Isolation
Safari MCP enforces per-session tab ownership upstream — tools cannot operate on tabs the session did not open.
Profile Isolation
Set SAFARI_PROFILE env var to use a separate Safari profile for automation:
export SAFARI_PROFILE="Automation"
cli-anything-safari tool navigate --url https://example.comThis keeps cookies/logins/history separate from the user's main browsing.
JavaScript Execution
tool evaluate and tool run-script run arbitrary JavaScript in the page context. Treat untrusted input with the same care as any dynamic code execution path.
Clipboard
tool clipboard-read and tool clipboard-write touch the system clipboard. Be careful when running inside a user's active session — overwriting the clipboard mid-task is disruptive.
Regenerating the tool registry
If you upgrade safari-mcp, regenerate the bundled schema:
python scripts/extract_tools.py \
"$(npm root -g)/safari-mcp/index.js" \
cli_anything/safari/resources/tools.jsonThe parity test (test_parity.py) pins the expected tool count; update it when the upstream tool list changes.
More Information
- Full documentation:
cli_anything/safari/README.mdin the package - Test coverage:
cli_anything/safari/tests/TEST.mdin the package - Architecture analysis:
safari/agent-harness/SAFARI.md - Methodology:
cli-anything-plugin/HARNESS.md - MCP backend pattern:
cli-anything-plugin/guides/mcp-backend.md
Version
1.0.0 — targets safari-mcp 2.7.8 (84 tools). Bundled tool registry is regenerated via scripts/extract_tools.py when safari-mcp upgrades.
Related skills
How it compares
Choose cli-anything-safari when WebKit fidelity, native Safari sessions, or macOS-only auth state matter more than cross-platform Chromium automation in CI.
FAQ
How many Safari tools does cli-anything-safari expose?
cli-anything-safari exposes all 84 tools from the safari-mcp MCP server. Each tool maps to an auto-generated Python Click command with schema-accurate arguments sourced from resources/tools.json.
Does cli-anything-safari work outside macOS?
cli-anything-safari requires macOS because it drives the native Safari application through safari-mcp. Linux and Windows hosts cannot run this skill without a macOS environment.
How does cli-anything-safari stay in sync with safari-mcp?
cli-anything-safari generates Click commands automatically from safari-mcp's bundled tool schema in resources/tools.json. That pipeline keeps all 84 commands aligned without hand-written wrappers.