Public leaderboard

Public assessment

achiya-automation/safari-mcp (safari-mcp)

safari-mcp · v2.15.11 · scanned

What changed in the harness

Selection accuracy 93→89, token cost up 9%, unconfirmed writes 0%→0%.

Category breakdown

Where the score comes from.

Earned points across the four signals Gradable measures. Safety and Legibility are scored out of 30; Economics and Discoverability are scored out of 20.

01Safety

0.0 / 30

0.0 out of 30
02Legibility

18.2 / 30

18.2 out of 30
03Economics

12.0 / 20

12.0 out of 20
04Discoverability

12.4 / 20

12.4 out of 20

Highest-impact fix

Estimated gain +30 points

Add explicit identity and permission preflight tools

Expose machine-readable principal/tenant confirmation and a non-mutating permission check so agents can verify both before destructive actions.

Description evidence

Defects and rewrites.

66 defects found across the exposed tool descriptions. Suggested rewrites make purpose, inputs, boundaries, and returns easier for an agent to understand.

Tool Defect types Suggested rewrite
safari_navigate
name_restates_behavior no_return_description
Load the specified url in the active Safari tab and wait until the page has fully loaded before returning, so subsequent snapshot/read calls see the rendered page. Returns the outcome (success/failure) of the navigation.
safari_go_back
no_return_description
Move the active Safari tab one step backward in browser history, equivalent to pressing the Back button. Returns whether the navigation succeeded.
safari_go_forward
no_return_description
Move the active Safari tab one step forward in browser history, equivalent to pressing the Forward button (only meaningful after going back). Returns whether the navigation succeeded.
safari_reload
no_return_description
Re-fetch the current page in the active Safari tab; pass hard: true to bypass the cache and force a full reload. Returns whether the reload succeeded.
safari_get_source
no_return_description
Return the raw HTML source of the current page as a string, optionally truncated to maxLength characters (default 200000). Use to inspect markup or extract data that text-based reading misses.
safari_click
no_return_description
Perform a click on an element in the current page, locating it by ref (take a fresh safari_snapshot first, since refs expire after each snapshot), CSS selector, visible text, or x/y coordinates. Dispatches a full PointerEvent+MouseEvent sequence with a React Fiber fallback so it works on React/Airtable/virtual-DOM apps, and never moves the real mouse. Returns the outcome of the click.
safari_double_click
no_return_description
Double-click an element in the current page, located by CSS selector or x/y coordinates (e.g. to select a word). Returns the outcome of the double-click.
safari_right_click
no_return_description
Right-click an element in the current page, located by CSS selector or x/y coordinates, to open its context menu. Returns the outcome of the right-click.
safari_native_hover
no_return_description
Move the real macOS cursor over an element (by ref, CSS selector, text, or x/y) to trigger native :hover and mouseenter handlers that JS-dispatched events can't reach, such as Discord sidebar or portal-rendered tooltips. Dwells for dwellMs (clamped 0-5000) to let tooltips render, then restores the original cursor position unless restoreMouse is false; requires the Safari window to be visible. After hovering, read the tooltip with safari_wait_for or safari_evaluate. Returns the outcome of the hover.
safari_native_type
no_return_description
Insert text into any editor in the active Safari page by pasting it through the real OS clipboard (CGEvent Cmd+V targeted at the Safari window), so ProseMirror/Slate/Draft.js update their internal model natively. Unlike safari_fill it never manipulates the DOM directly, saves and restores the clipboard, and doesn't steal focus. Use for Discord, Slack, and editors where safari_fill looks right but content isn't 'really there' at submit time. Returns the outcome of the insertion.
safari_fill
no_return_description
Set the value of an input, textarea, select, or contenteditable, replacing any existing content, matching by selector or a fresh-snapshot ref (refs expire after each new snapshot). Handles React controlled inputs, ProseMirror, Draft.js, and Google Closure editors automatically; use safari_replace_editor for code editors and safari_type_text for character-by-character fields. Returns the outcome of the fill.
safari_clear_field
no_return_description
Clear the text of the input identified by selector in the current page. Returns the outcome of the clear action.
safari_select_option
no_return_description
Select the given value (option value or visible label) in a native <select> dropdown by setting .value and dispatching a change event. Pass ref (from safari_snapshot) when the select is inside an iframe or shadow DOM, since a plain selector only reaches the top document; for custom/React dropdowns use safari_click on the trigger then the option instead. Returns the selection outcome.
safari_fill_form
no_return_description
Fill multiple form fields in one call by passing fields as an array of {selector, value} pairs, applying each value to the matching element. Returns the outcome of the batch fill.
safari_press_key
no_return_description
Send a keyboard keypress (enter, tab, escape, space, arrow keys, or a single character) to the current page, optionally with cmd/shift/alt/ctrl modifiers. Returns the outcome of the keypress.
safari_type_text
no_return_description
Type text character-by-character into the current page's focus or an element matched by ref/selector, firing realistic key events so autocomplete and per-keystroke handlers trigger — best for search boxes, chat inputs, and incrementally-reacting fields. Use safari_fill for rich text editors and safari_replace_editor for code editors; refs expire after each new snapshot. Returns the outcome of the typing.
safari_replace_editor
no_return_description
Replaces ALL content in a code editor (Monaco, CodeMirror, Ace, ProseMirror) using its native API. Use ONLY for code editors, e.g. Airtable automations, GitHub gists, CodePen, n8n code nodes. NOT for rich text editors like Medium/LinkedIn (use safari_fill for those). Detects ProseMirror/Draft.js/CodeMirror/Monaco/Ace and returns a confirmation once the new text is written.
safari_screenshot
no_return_description
Takes a visual screenshot of the current viewport (or the full page if fullPage is true) and returns it as a base64 JPEG image. EXPENSIVE: prefer safari_snapshot for most tasks and use this only to verify visual layout, styling, images, or colors that snapshot cannot show.
safari_scroll
no_return_description
Scrolls the page up or down by the given number of pixels (direction defaults to down, amount defaults to 500 px) and returns the resulting scroll position.
safari_scroll_to
no_return_description
Scrolls the page to the given x/y pixel position (both default to 0) and returns the resulting scroll position.
safari_list_tabs
name_restates_behavior no_return_description
Returns the list of all open Safari tabs with their titles and URLs, including the indices used by safari_switch_tab. Call this first to identify which tab to switch to or act on.
safari_reload_extension
no_return_description
Hot-reloads the Safari MCP Bridge extension so it reloads its own code from disk without a manual Safari Preferences > Extensions toggle. Use after editing extension/background.js or extension/content.js in the safari-mcp repo. The extension briefly disconnects and auto-reconnects within about 2 seconds, after which the tool returns a confirmation. NOTE: requires an installed extension supporting the reload_extension command (added in v2.9.1+); older extensions need a one-time manual reload to pick up this feature.
safari_new_tab
no_return_description
Opens a new Safari tab, navigating to the given URL or opening a blank tab when left empty, and returns a confirmation once the tab is open.
safari_close_tab
no_return_description
Closes the currently active Safari tab and returns a confirmation once it is closed.
safari_switch_tab
no_return_description
Switches Safari to the tab at the given index (starting from 1; use safari_list_tabs to see indices) and returns a confirmation. All subsequent commands (click, fill, evaluate, screenshot, scroll) target this tab; call switch_tab again to re-anchor if commands run on the wrong tab.
safari_wait_for
no_return_description
Waits up to the timeout (default 10000 ms) for the given CSS selector or text to appear on the page and returns once it is found. Use before interacting with dynamically loaded content.
safari_wait_for_new_tab
no_return_description
Waits up to the timeout (default 10000 ms) for a new tab to appear, e.g. after an OAuth login click opens a popup, and automatically switches to it. If urlContains is set, only tabs whose URL contains that string match. Returns once the new tab is found.
safari_evaluate
no_return_description
Executes the given JavaScript in the current page and returns the result of the last expression. Automatically falls back to AppleScript when CSP blocks execution (e.g. Google Search Console, LinkedIn). For reading data prefer safari_read_page or safari_snapshot; for interactions prefer safari_click/fill with refs.
safari_eval_file
no_return_description
Executes JavaScript read from the .js file at the given absolute path (avoids passing huge scripts inline or manual copy) and returns the result. Same engine as safari_evaluate: extension-first (no focus steal) with AppleScript fallback. Use to upload binary via a generated .js containing base64.
safari_get_element
no_return_description
Returns detailed information about the element matching the CSS selector: tag, text, bounding rect, attributes, and visibility.
safari_hover
no_return_description
Moves the pointer over an element targeted by ref (from safari_snapshot), CSS selector, or x/y coordinates to trigger hover effects (e.g. tooltips, dropdowns), and returns a confirmation once the hover is applied.
safari_handle_dialog
no_return_description
Registers a handler for the next alert/confirm/prompt dialog: accepts or dismisses it (default accept) and optionally enters text for prompt dialogs. Returns a confirmation that the handler is set; call it before triggering the dialog.
safari_resize
name_restates_behavior no_return_description
Resizes the Safari window to the given pixel width and height, for example to establish a known viewport before screenshots or layout checks, and returns a confirmation once the resize is applied.
safari_drag
no_return_description
Drags an element from a source (CSS selector or source x/y) to a target (CSS selector or target x/y) to simulate a drag-and-drop gesture, and returns a confirmation once the drag completes.
safari_paste_image
no_return_description
Pastes the image at the given file path (PNG, JPG, WebP) into the currently focused element via JS DataTransfer with no clipboard use and no focus steal. Works on Medium, dev.to, HackerNoon, TOI, etc., and returns a confirmation once pasted.
safari_emulate
no_return_description
Emulates a mobile device by resizing the window and setting the user agent. Use a preset device (iphone-14, iphone-14-pro-max, ipad, ipad-pro, pixel-7, galaxy-s24) or custom width/height/userAgent/scale, and returns a confirmation once emulation is applied.
safari_reset_emulation
no_return_description
Resets device emulation back to desktop mode by clearing the mobile window size and user agent set by safari_emulate, and returns a confirmation once reset.
safari_get_cookies
no_return_description
Returns the cookies currently set for the current page, including their names and values, so you can inspect session or auth state.
safari_local_storage
no_return_description
Get localStorage data for the current page. Returns the stored value for the given key, or all localStorage key-value pairs when no key is specified.
safari_run_script
no_return_description
Batch multiple Safari actions in ONE call. Steps: [{action, args}]. Actions match other safari_* tool names without prefix (e.g. 'navigate', 'click', 'fill', 'evaluate', 'readPage'). Returns the result of each step in order.
safari_start_console
no_return_description
Start capturing console messages (log, warn, error, info). Call once per page. Returns nothing; use safari_get_console to retrieve the captured messages.
safari_get_console
name_restates_behavior no_return_description
Retrieve console messages captured since safari_start_console was called. Returns the collected log, warn, error, and info messages with their type and text.
safari_clear_console
no_return_description
Clear all captured console messages. Returns nothing; new messages continue to be captured if safari_start_console is still active.
safari_save_pdf
name_restates_behavior no_return_description
Save the current page as a PDF file at the given absolute path. Uses screencapture + PDF rendering (no Safari UI interaction needed). Returns the path where the PDF was saved.
safari_accessibility_snapshot
no_return_description
Get the accessibility tree of the page (roles, ARIA labels, focusable elements, form states). Essential for a11y auditing. Returns the tree, scoped to the optional CSS selector and limited to maxDepth levels.
safari_set_cookie
no_return_description
Set a cookie on the current page with the given name, value, and optional attributes (domain, path, expires, secure, sameSite). Returns nothing on success.
safari_delete_cookies
no_return_description
Delete a specific cookie by name on the current page, or delete all cookies when 'all' is true. Returns nothing.
safari_session_storage
no_return_description
Get sessionStorage data for the current page. Returns the value for the given key, or all sessionStorage key-value pairs when no key is specified.
safari_set_session_storage
name_restates_behavior no_return_description
Write the given value to the specified key in the current page's sessionStorage. Returns nothing on success.
safari_set_local_storage
name_restates_behavior no_return_description
Write the given value to the specified key in the current page's localStorage. Returns nothing on success.
safari_delete_local_storage
name_restates_behavior no_return_description
Delete a single key from the current page's localStorage, or clear all localStorage when key is omitted. Returns nothing.
safari_delete_session_storage
name_restates_behavior no_return_description
Delete a single key from the current page's sessionStorage, or clear all sessionStorage when key is omitted. Returns nothing.
safari_export_storage
no_return_description
Export all storage state (cookies + localStorage + sessionStorage) as JSON. Returns a JSON string representing the full storage state, useful for saving and restoring login sessions.
safari_import_storage
name_restates_behavior no_return_description
Restore cookies, localStorage, and sessionStorage on the current page from a JSON string exported by safari_export_storage. Returns nothing on success.
safari_clipboard_read
no_return_description
Read the current system clipboard content. Returns the text currently on the clipboard.
safari_clipboard_write
no_return_description
Write the given text to the system clipboard, replacing any current content. Returns nothing on success.
safari_clear_mocks
no_return_description
Remove all network route mocks created by safari_mock_route and restore real network behavior. Returns nothing.
safari_wait
no_return_description
Wait for a fixed time in milliseconds. Use only when you need a brief pause between actions. PREFER safari_wait_for (waits for element/text to appear) — it's smarter and doesn't waste time. Returns nothing after the wait completes.
safari_start_network_capture
no_return_description
Start capturing detailed network requests (fetch + XHR) with headers, status, timing. Call once per page. Intercepts fetch/XHR — captures requests AFTER this call only. Returns nothing; use safari_network_details to retrieve results. For quick overview of already-loaded resources, use safari_network instead.
safari_network_details
no_return_description
Get captured network requests with full details (must call safari_start_network_capture first). Returns a list of captured requests, optionally filtered by URL substring and limited to 'limit' entries (default: 50).
safari_clear_network
no_return_description
Clear all captured network requests. Returns nothing; recording continues unless capture is stopped.
safari_throttle_network
no_return_description
Simulate slow network conditions to test performance under poor connectivity: apply a preset profile (slow-3g, fast-3g, 4g, offline) or custom latency and download speed, or call with no args to reset to normal. Returns a confirmation of the applied settings (or that the network was reset).
safari_override_geolocation
no_return_description
Override the browser's geolocation API so navigator.geolocation calls from the page return custom coordinates using the required latitude and longitude, with optional accuracy in meters (default 100). Returns a confirmation that the override is active.
safari_scroll_to_element
no_return_description
Scroll the page to bring a target into view, by CSS selector or by visible text; for virtual-DOM pages (e.g., Airtable) use text and it scrolls down until the text appears in the DOM. Returns whether the target was found and scrolled into view within the timeout.
safari_click_and_wait
no_return_description
Click an element (by CSS selector or visible text) and wait for the result — either a page load or the appearance of a waitFor selector — in one call instead of separate click + wait steps. Returns the outcome of the click and wait within the timeout.
safari_fill_and_submit
no_return_description
Fill the given fields and submit the form in one operation, auto-detecting the submit button when submitSelector is omitted. Returns the result of the submission (e.g., resulting page state or confirmation).

Selection evidence

Confusable tool pairs.

11 pairs where similar names or overlapping descriptions may send an agent toward the wrong tool.

Tool A Tool B Confidence Why they collide
safari_snapshot safari_accessibility_snapshot high Both return the page's accessibility tree with near-identical phrasing ('snapshot' vs 'accessibility snapshot'). Tasks like 'get the page structure/state' or 'give me the accessibility snapshot' can select either; only the descriptions (interactive refs vs a11y auditing) differentiate them.
safari_scroll safari_scroll_to medium Both are 'scroll' tools; 'scroll down the page' maps to safari_scroll (direction/amount) while 'scroll to a specific spot' maps to safari_scroll_to (x/y). Tasks like 'scroll to the bottom of the page' fit both, so the agent can pick the one whose schema does not match.
safari_scroll_to safari_scroll_to_element medium Near-identical names. A task like 'scroll to the element / comments section' should use safari_scroll_to_element (selector/text), but an agent may pick safari_scroll_to, which only accepts x/y coordinates and can't target the element.
safari_native_hover safari_hover medium Both perform 'hover over an element' and both mention tooltips; they differ only in the event mechanism (JS-dispatched vs OS-level CGEvent). A task like 'hover over X to reveal the tooltip' matches both, and picking the wrong mechanism may fail to trigger native :hover handlers.
safari_wait_for safari_wait medium Both start with 'wait'. safari_wait is a fixed ms pause while safari_wait_for waits for an element/text; a task like 'wait until the page loads' or 'wait for the content to appear' can be mapped to either, especially since wait_for's description steers users away from wait.
safari_fill safari_fill_form medium 'Fill out this form' maps to both: safari_fill sets a single value, safari_fill_form takes an array of fields. A multi-field task can cause the agent to pick safari_fill with mismatched parameters, or vice versa.
safari_fill safari_fill_and_submit medium Both are 'fill' tools; a task like 'fill in the login form and submit/log in' could make the agent pick safari_fill (dropping the submission) or safari_fill_and_submit, since the descriptions overlap on filling form fields.
safari_network safari_network_details medium Both retrieve network request information. A task like 'give me the details of the network requests' could select safari_network_details, which requires a prior safari_start_network_capture (fails otherwise), or safari_network, the quick no-setup overview; the name/description do not make the prerequisite obvious.
safari_local_storage safari_session_storage medium Identical schema and near-identical descriptions ('Get ... storage data for the current page'), differing only in localStorage vs sessionStorage. A task like 'get the stored storage values for this page' is genuinely ambiguous between them.
safari_set_session_storage safari_set_local_storage medium Both are 'Set a value in ... storage' with identical key/value parameters; a task like 'save this value under this key in storage' without explicitly naming local vs session has no distinguishing signal, so either tool looks correct.
safari_click_and_read safari_click_and_wait medium Both combine 'click' with a follow-up and share the same tokens. A task like 'click the element and wait for the result page to load/update' is ambiguous: click_and_read returns the updated page content, while click_and_wait waits for a selector; the agent may pick the one that omits the other half of the task.

Compare the field

One score is useful.
The evidence makes it actionable.

Back to the leaderboard