Safari MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| safari_navigateA | Navigate to a URL in Safari. Waits for page to fully load. |
| safari_go_backB | Go back in browser history |
| safari_go_forwardA | Go forward in browser history |
| safari_reloadC | Reload the current page |
| safari_read_pageA | Read page text content (title, URL, body text). Use for reading article text or page content. For interacting with elements, prefer safari_snapshot (gives ref IDs). Use selector to read specific element. Use maxLength to limit output. |
| safari_get_sourceC | Get HTML source of current page |
| safari_snapshotA | PREFERRED way to see page state. Returns accessibility tree with ref IDs for every interactive element. Use refs with click/fill/type instead of CSS selectors. Workflow: snapshot → see refs → click({ref:'0_5'}). PREFER THIS over safari_screenshot (cheaper, structured text vs heavy image) and over safari_read_page (includes interactive refs). Use safari_screenshot only when you need to see visual layout/styling. |
| safari_navigate_and_readA | Navigate to a URL and return the page content in one step — saves 1 full round-trip vs navigate+read_page. Use instead of safari_navigate + safari_read_page. |
| safari_clickA | Click element. Use ref (from snapshot), selector, text, or x/y. Works on React/Airtable/virtual DOM apps via full PointerEvent+MouseEvent sequence + React Fiber fallback. Pure JS — never touches user's mouse. When using ref, always take a FRESH safari_snapshot first — refs expire after each new snapshot. |
| safari_click_and_readA | Click an element then return the updated page — saves 1 full round-trip vs separate click+read_page. Handles both React Router navigation and full page loads. |
| safari_double_clickA | Double-click an element by CSS selector or x/y coordinates (e.g. to select a word in text) |
| safari_right_clickA | Right-click (context menu) an element by CSS selector or x/y coordinates |
| safari_native_clickA | OS-level mouse click via macOS CGEvent — produces isTrusted: true events that pass WAF/bot detection (G2, Cloudflare, etc.). Use when regular safari_click fails with 405/403 errors or form submissions are blocked. Trade-off: physically moves the mouse cursor and requires Safari window to be visible. Use ref (from snapshot), selector, text, or x/y. When using ref, always take a FRESH safari_snapshot first. |
| safari_native_hoverA | OS-level mouse hover via macOS CGEvent — moves the real cursor to an element to trigger native :hover / mouseenter handlers. Use for obfuscated UIs where JS-dispatched mouseenter isn't enough, like Discord server sidebars (tooltips only appear on real hover) or portal-rendered tooltips. After hover, call safari_wait_for or safari_evaluate to read the tooltip. Dwells for dwellMs to let tooltips render, then restores the original cursor position by default. Requires Safari window to be visible. |
| safari_native_keyboardA | OS-level keyboard event via macOS CGEvent — sends a real keypress (with optional modifiers) to the Safari window WITHOUT activating Safari or stealing focus. Use when safari_press_key's JS path doesn't reach React trust-gated handlers (Discord ProseMirror Enter, Slack send, virtualized editors). Keys: enter, return, tab, escape, space, delete, backspace, up/down/left/right, home, end, pageup, pagedown, f1-f6, a-z, 0-9 and common punctuation. Modifiers: cmd, shift, alt, ctrl. Produces isTrusted:true events. Never activates Safari — runs entirely in the background. |
| safari_native_typeA | Insert text into ANY editor via OS-level clipboard paste (CGEvent Cmd+V targeted to Safari window). Unlike safari_fill which manipulates DOM directly (breaking React/ProseMirror state), this goes through the real paste pipeline — ProseMirror/Slate/Draft.js process the paste event natively and update their internal model. After native_type, pressing Enter (via safari_native_keyboard) will actually submit the form because the framework state matches the DOM. Saves and restores the user's clipboard. No focus stealing. Use for Discord, Slack, and any editor where safari_fill works visually but the content isn't 'really there' when you try to submit. |
| safari_fillA | Fill/replace value in an input, textarea, select, OR contenteditable (rich text). Handles React controlled inputs, ProseMirror, Draft.js, and Google Closure editors automatically. Use for SETTING a value (replaces existing). For code editors (Monaco/CodeMirror/Ace), use safari_replace_editor instead. For character-by-character typing in search boxes, use safari_type_text. IMPORTANT: When using ref, always take a FRESH safari_snapshot first — refs expire after each new snapshot (prefix changes: 5_xx → 6_xx). |
| safari_clear_fieldC | Clear an input field |
| safari_verify_stateA | Verify the framework-level state of an editor/input matches the expected value. Returns JSON {match, mode, actual, expected, hint?}. Modern editors (ProseMirror, Lexical, Closure, React-controlled inputs) maintain state separately from the DOM — |
| safari_select_optionA | Select an option in a native dropdown. Sets .value and dispatches change event. Pass |
| safari_react_select_setA | Set a value in a react-select v5 dropdown by walking React fiber to find the Select component and invoking onChange directly — bypasses the menu UI entirely. Use when safari_click on the chevron or option keeps failing (Cloudflare custom token forms after a few rows, portal-rendered selects that intercept synthetic events). Returns JSON {ok, selected} on success, or {ok:false, error, available:[…]} listing up to 30 option labels on miss. Match is by label, value, or case-insensitive label. Either ref or selector required. NOTE: For Permissions-levels combos that are disabled until a Permission is selected, set the Permissions value first — the level combo becomes enabled and its props.options populate. |
| safari_react_select_list_optionsA | List available options of a react-select v5 dropdown without opening the menu. Returns JSON {ok, total, options:[{label,value}…]}. Useful when safari_react_select_set returns 'option not found' and you need to see exact labels (e.g. 'Email Routing Rules' vs 'Email Routing'). Either ref or selector required. |
| safari_fill_formC | Fill multiple form fields at once |
| safari_press_keyA | Press a keyboard key (enter, tab, escape, arrows, etc). Supports modifiers (cmd, shift, alt, ctrl). |
| safari_type_textA | Type text character-by-character with realistic key events. Best for: search boxes (triggers autocomplete), chat inputs, and fields that react to each keystroke. For rich text editors (Medium, HackerNoon, LinkedIn), use safari_fill instead — it uses framework-native APIs. For code editors (Monaco/CodeMirror), use safari_replace_editor. When using ref, always take a FRESH safari_snapshot first — refs expire after each new snapshot. |
| safari_replace_editorA | Replace ALL content in a code editor (Monaco, CodeMirror, Ace, ProseMirror). Use ONLY for code editors — Airtable automations, GitHub gists, CodePen, n8n code nodes, etc. NOT for rich text editors like Medium/LinkedIn (use safari_fill for those). Detects ProseMirror/Draft.js/CodeMirror/Monaco/Ace and uses their native API. |
| safari_screenshotA | Take a visual screenshot (base64 JPEG). EXPENSIVE — use safari_snapshot instead for most tasks. Only use screenshot when you need to verify visual layout, styling, images, or colors that snapshot can't show. |
| safari_screenshot_elementA | Take a screenshot of a specific element (by CSS selector). Returns base64 PNG image. |
| safari_scrollB | Scroll the page up or down by a specified amount |
| safari_scroll_toB | Scroll to a specific position on the page |
| safari_list_tabsA | List all open tabs in Safari with their titles and URLs |
| safari_reload_extensionA | Hot-reload the Safari MCP Bridge extension — forces it to reload its own code from disk without requiring manual Safari Preferences → Extensions → toggle. Use after editing extension/background.js or extension/content.js in the safari-mcp repo. The extension briefly disconnects during reload and auto-reconnects within ~2 seconds. NOTE: this tool itself requires the extension version already installed to support the |
| safari_new_tabB | Open a new tab, optionally with a URL |
| safari_close_tabA | Close the current tab |
| safari_switch_tabA | Switch to a specific tab by index (use safari_list_tabs to see indices). All subsequent commands (click, fill, evaluate, screenshot, scroll) will target this tab. If commands seem to run on the wrong tab, call switch_tab again to re-anchor. |
| safari_wait_forC | Wait for an element or text to appear on the page |
| safari_wait_for_new_tabA | Wait for a new tab to appear (e.g. after OAuth login click opens popup). Automatically switches to the new tab. |
| safari_evaluateA | Execute JavaScript in the current page. 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_fileA | Execute JavaScript read from a FILE path (avoids passing huge scripts inline / manual copy). Same engine as safari_evaluate: extension-first (no focus steal), AppleScript fallback. Use to upload binary via a generated .js containing base64. |
| safari_get_elementA | Get detailed info about an element (tag, text, rect, attributes, visibility) |
| safari_query_allB | Find all elements matching a CSS selector (returns tag, text, href, value) |
| safari_hoverB | Hover over element. Use ref, selector, or x/y |
| safari_handle_dialogA | Set up handler for the next alert/confirm/prompt dialog |
| safari_resizeC | Resize the Safari window |
| safari_dragB | Drag an element to another element or position. Use CSS selectors or x/y coordinates. |
| safari_upload_fileA | Upload a file to a element via JavaScript DataTransfer — NO file dialog, NO UI interaction. IMPORTANT: Do NOT click the file input before calling this tool — just provide the selector and file path. If a file dialog is already open, this tool will close it first. NOTE: 'verified 0 files' may appear even on success if the site uses a custom upload handler — check visually with safari_snapshot. |
| safari_paste_imageA | Paste an image from a local file into the focused element via JS DataTransfer (no clipboard, no focus steal). Works on Medium, dev.to, HackerNoon, TOI, etc. |
| safari_emulateA | Emulate a mobile device by resizing window and setting user agent. Devices: iphone-14, iphone-14-pro-max, ipad, ipad-pro, pixel-7, galaxy-s24. Or use custom width/height. |
| safari_reset_emulationA | Reset device emulation back to desktop mode |
| safari_get_cookiesA | Get cookies for the current page |
| safari_local_storageA | Get localStorage data for the current page |
| safari_networkA | Quick network overview via Performance API (no setup needed). Shows URLs and timing for resources loaded by the page. For detailed request/response info (headers, status codes, POST bodies), use safari_start_network_capture + safari_network_details instead. |
| safari_run_scriptA | 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'). |
| safari_start_consoleA | Start capturing console messages (log, warn, error, info). Call once per page. |
| safari_get_consoleA | Get captured console messages (must call safari_start_console first) |
| safari_clear_consoleA | Clear all captured console messages |
| safari_save_pdfA | Save the current page as a PDF file. Uses screencapture + PDF rendering (no Safari UI interaction needed). |
| safari_accessibility_snapshotA | Get the accessibility tree of the page (roles, ARIA labels, focusable elements, form states). Essential for a11y auditing. |
| safari_set_cookieC | Set a cookie on the current page |
| safari_delete_cookiesA | Delete a specific cookie or all cookies for the current page |
| safari_session_storageA | Get sessionStorage data for the current page |
| safari_set_session_storageB | Set a value in sessionStorage |
| safari_set_local_storageB | Set a value in localStorage |
| safari_delete_local_storageA | Delete a localStorage key, or clear all localStorage (omit key to clear all) |
| safari_delete_session_storageA | Delete a sessionStorage key, or clear all sessionStorage (omit key to clear all) |
| safari_export_storageA | Export all storage state (cookies + localStorage + sessionStorage) as JSON — useful for saving and restoring login sessions |
| safari_import_storageB | Import storage state from JSON (as exported by safari_export_storage) — restores cookies, localStorage, sessionStorage |
| safari_clipboard_readA | Read the current clipboard content (text) |
| safari_clipboard_writeB | Write text to the system clipboard |
| safari_mock_routeA | Intercept network requests matching a URL pattern and return a mock response. Works with both fetch and XHR. Useful for testing API error states, offline behavior, or replacing API responses. |
| safari_clear_mocksA | Remove all network route mocks (restore real network behavior) |
| safari_waitA | 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. |
| safari_start_network_captureA | Start capturing detailed network requests (fetch + XHR) with headers, status, timing. Call once per page. Intercepts fetch/XHR — captures requests AFTER this call only. For quick overview of already-loaded resources, use safari_network instead. |
| safari_network_detailsA | Get captured network requests with full details (must call safari_start_network_capture first) |
| safari_clear_networkA | Clear all captured network requests |
| safari_performance_metricsA | Get detailed performance metrics: navigation timing, Web Vitals (FCP, LCP, CLS), resource breakdown, memory usage |
| safari_throttle_networkA | Simulate slow network conditions. Profiles: slow-3g, fast-3g, 4g, offline. Or custom latency/speed. Call with no args to reset. |
| safari_console_filterA | Get console messages filtered by level (must call safari_start_console first) |
| safari_extract_tablesA | Extract HTML tables as structured JSON (headers + rows). Perfect for scraping data tables. |
| safari_extract_metaA | Extract all meta tags: title, description, canonical, OG tags, Twitter cards, JSON-LD, alternate languages, RSS feeds |
| safari_extract_imagesA | Extract all images with src, alt, dimensions, loading strategy, viewport visibility |
| safari_extract_linksA | Extract all links with href, text, rel, target, external/nofollow detection |
| safari_override_geolocationB | Override the browser's geolocation API to return custom coordinates |
| safari_get_computed_styleA | Get computed CSS styles for an element. Optionally filter specific properties. |
| safari_list_indexed_dbsA | List all IndexedDB databases on the current page |
| safari_get_indexed_dbB | Read records from an IndexedDB database store |
| safari_css_coverageA | Analyze CSS coverage: find unused CSS rules across all stylesheets. Shows coverage percentage per stylesheet. |
| safari_inspect_viewportA | Validate the page's against iOS Safari best practices: width=device-width, initial-scale, disabled-zoom (WCAG 1.4.4), viewport-fit=cover. Returns parsed attributes + severity-tagged issues (error/warning/info). |
| safari_safe_area_insetsA | Read the live CSS safe-area-inset values (top/right/bottom/left) as the page sees them, whether viewport-fit=cover is set, and whether env(safe-area-inset-*) is used in any stylesheet. For notch / Dynamic Island layout debugging. |
| safari_check_pwaA | Audit the page for iOS 'Add to Home Screen' / PWA readiness: apple-mobile-web-app-capable, apple-touch-icon (incl. 180x180), theme-color, status-bar style, web app manifest, splash screens. Returns a pass/total checklist. |
| safari_webkit_compatA | Check every CSS property used on the page against THIS Safari via CSS.supports() — reports unsupported properties, properties that need a -webkit- prefix, and known Safari rendering quirks (e.g. position:sticky inside overflow ancestors). Tested in the live engine, so no false positives. |
| safari_doctorA | Diagnose the macOS permission + daemon chain in one shot: Safari running, Apple Events/Automation, native helper daemon, Accessibility (native clicks), Screen Recording, and the helper's codesign identity. Returns a pass/fail checklist with the exact System Settings fix per failure. Run this FIRST when clicks/screenshots/startup 'don't work even with permissions granted'. |
| safari_detect_formsA | Auto-detect all forms on the page with their fields, types, selectors, and submit buttons. Great for automated form filling. |
| safari_scroll_to_elementA | Scroll to element by CSS selector OR text. For virtual DOM (Airtable) use text — scrolls down until text appears in DOM. |
| safari_click_and_waitA | Click an element AND wait for the result (page load or element). Use instead of click + wait_for separately. |
| safari_fill_and_submitA | Fill a form AND submit it in one operation. Finds submit button automatically if not specified. |
| safari_analyze_pageA | Full page analysis in ONE call: title, URL, meta tags, OG, headings, link stats, image stats, forms, and text preview. Perfect for SEO/audit. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/achiya-automation/safari-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server