{"name":"io.github.achiya-automation/safari-mcp","slug":"achiya-automation-safari-mcp","title":null,"description":"Native Safari browser automation for AI agents — 98 tools, zero Chrome overhead.","url":"https://mcp.market/server/achiya-automation-safari-mcp","rating":null,"grade":"C","score":69,"certified":false,"status":"active","category":"scraping","tags":["scraping"],"presence":{"score":54,"stars":204,"forks":28,"downloads_week":2608,"last_push_at":"2026-09-18T05:50:22.000Z","license":"MIT"},"uptime":null,"claimed":false,"transport":"npm","callable_via_gateway":false,"default_price_micros":0,"repository":"https://github.com/achiya-automation/safari-mcp","website":null,"version":"2.21.11","remotes":[],"packages":[{"registryType":"npm","identifier":"safari-mcp","version":"2.21.11","transport":{"type":"stdio"}}],"tools":[{"name":"safari_accessibility_snapshot","description":"Get the accessibility tree of the page (roles, ARIA labels, focusable elements, form states). Essential for a11y auditing.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_analyze_page","description":"Full page analysis in ONE call: title, URL, meta tags, OG, headings, link stats, image stats, forms, and text preview. Perfect for SEO/audit.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_check_pwa","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_clear_console","description":"Clear all captured console messages","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_clear_field","description":"Clear an input field","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_clear_mocks","description":"Remove all network route mocks (restore real network behavior)","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_clear_network","description":"Clear all captured network requests","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_click","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_click_and_read","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_click_and_wait","description":"Click an element AND wait for the result (page load or element). Use instead of click + wait_for separately.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_clipboard_read","description":"Read the current clipboard content (text)","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_clipboard_write","description":"Write text to the system clipboard","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_close_tab","description":"Close the current tab. After a daemon/session restart, pass the opaque receipt returned by safari_new_tab or safari_list_tabs.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_console_filter","description":"Get console messages filtered by level (must call safari_start_console first)","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_css_coverage","description":"Analyze CSS coverage: find unused CSS rules across all stylesheets. Shows coverage percentage per stylesheet.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_delete_cookies","description":"Delete a specific cookie or all cookies for the current page","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_delete_local_storage","description":"Delete a localStorage key, or clear all localStorage (omit key to clear all)","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_delete_session_storage","description":"Delete a sessionStorage key, or clear all sessionStorage (omit key to clear all)","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_detect_forms","description":"Auto-detect all forms on the page with their fields, types, selectors, and submit buttons. Great for automated form filling.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_doctor","description":"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'.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_double_click","description":"Double-click an element by CSS selector or x/y coordinates (e.g. to select a word in text)","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_drag","description":"Drag an element to another element or position. Use CSS selectors or x/y coordinates.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_emulate","description":"Emulate a mobile device: sizes the Safari window to the device's CSS viewport and overrides navigator.userAgent/platform/maxTouchPoints (iOS/iPadOS 27 values) in the current page — JavaScript only: the HTTP User-Agent header is unchanged and a reload or navigation clears it. Devices: …. Or pass width/height (and userAgent).","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_eval_file","description":"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.","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_evaluate","description":"Execute JavaScript in the current page (a returned Promise is awaited — fetch/timers work in background tabs; requestAnimationFrame never fires there). 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.","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_export_storage","description":"Export all storage state (cookies + localStorage + sessionStorage) as JSON — useful for saving and restoring login sessions","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_extract_images","description":"Extract all images with src, alt, dimensions, loading strategy, viewport visibility","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_extract_links","description":"Extract all links with href, text, rel, target, external/nofollow detection","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_extract_meta","description":"Extract all meta tags: title, description, canonical, OG tags, Twitter cards, JSON-LD, alternate languages, RSS feeds","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_extract_tables","description":"Extract HTML tables as structured JSON (headers + rows). Perfect for scraping data tables.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_fill","description":"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","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_fill_and_submit","description":"Fill a form AND submit it in one operation. Finds submit button automatically if not specified.","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_fill_form","description":"Fill multiple form fields at once","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_get_computed_style","description":"Get computed CSS styles for an element. Optionally filter specific properties.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_get_console","description":"Get captured console messages (must call safari_start_console first)","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_get_cookies","description":"Get cookies for the current page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_get_element","description":"Get detailed info about an element (tag, text, rect, attributes, visibility)","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_get_indexed_db","description":"Read records from an IndexedDB database store","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_get_source","description":"Get HTML source of current page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_go_back","description":"Go back in browser history","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_go_forward","description":"Go forward in browser history","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_handle_dialog","description":"Set up handler for the next alert/confirm/prompt dialog","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_hover","description":"Hover over element. Use ref, selector, or x/y","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_import_storage","description":"Import storage state from JSON (as exported by safari_export_storage) — restores cookies, localStorage, sessionStorage","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_inspect_viewport","description":"Validate the page's <meta name=viewport> 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).","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_list_frames","description":"List every document in the tab — the main page plus each iframe — with its frameId, URL and text length. Use when a page's content lives in a cross-origin iframe (an embedded app, a micro-frontend shell, a payment field): safari_read_page and safari_evaluate see only the main document there and come back empty or with a loader. Pass the frameId or a URL substring as safari_evaluate's `frame` to ru","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_list_indexed_dbs","description":"List all IndexedDB databases on the current page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_list_tabs","description":"List every tab in this session's Safari window (titles + URLs, including the user's own tabs — verbose and rarely needed). Tabs this session owns carry a receipt. Prefer keeping the receipt from safari_new_tab over listing.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_local_storage","description":"Get localStorage data for the current page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_mock_route","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_native_click","description":"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_snapsho","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_native_hover","description":"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 ren","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_native_keyboard","description":"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, page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_native_type","description":"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 ","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_navigate","description":"Navigate this session's tab to a URL (pass `receipt` to pin the tab). Waits for the page to load. Returns {title, url} — plus a fresh `receipt` when the origin changed; use that one from then on.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_navigate_and_read","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_network","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_network_details","description":"Get captured network requests with full details (must call safari_start_network_capture first)","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_new_tab","description":"Open a new background tab (never steals focus), optionally with a URL. Returns {tabIndex, safeUrl, receipt}. KEEP THE RECEIPT and pass it as `receipt` to every later call on this tab — it survives MCP reconnects, daemon restarts, parallel sessions and subagents, and makes safari_list_tabs / safari_switch_tab unnecessary.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_override_geolocation","description":"Override the browser's geolocation API to return custom coordinates","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_paste_image","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_performance_metrics","description":"Get detailed performance metrics: navigation timing, Web Vitals (FCP, LCP, CLS), resource breakdown, memory usage","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_press_key","description":"Press a keyboard key (enter, tab, escape, arrows, etc). Supports modifiers (cmd, shift, alt, ctrl).","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_query_all","description":"Find all elements matching a CSS selector (returns tag, text, href, value). x/y are relative to each element's own frame viewport — for matches inside an iframe, click by selector or snapshot ref, not by these coordinates","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_react_select_list_options","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_react_select_set","description":"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:[…]","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_read_page","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_reload","description":"Reload the current page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_reload_extension","description":"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 instal","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_replace_editor","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_reset_emulation","description":"Reset device emulation: restores the window size from before safari_emulate and removes its navigator overrides (no reload)","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_resize","description":"Resize the Safari window","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_right_click","description":"Right-click (context menu) an element by CSS selector or x/y coordinates","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_run_script","description":"Batch Safari actions in one MCP session. Named profiles use the verified extension and support: newTab, switchTab, getReceipt, listTabs, closeTab, navigate, navigateAndRead, readPage, snapshot, getElementInfo, querySelectorAll, waitFor, waitForTime, click, clickAndOpenPopup, fill, fillForm, clearField, typeText, selectOption, pressKey, scroll, scrollTo, scrollToElement, hover, evaluate, reload, go","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_safe_area_insets","description":"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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_save_pdf","description":"Save the current page as a PDF file. Uses screencapture + PDF rendering (no Safari UI interaction needed).","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_screenshot","description":"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. Pass maxWidth (e.g. 1024) for layout checks — far fewer tokens.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_screenshot_element","description":"Take a screenshot of a specific element (by CSS selector). Returns a base64 image.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_scroll","description":"Scroll the page up or down by a specified amount","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_scroll_to","description":"Scroll to a specific position on the page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_scroll_to_element","description":"Scroll to element by CSS selector OR text. For virtual DOM (Airtable) use text — scrolls down until text appears in DOM.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_select_option","description":"Select an option in a native <select> dropdown. Sets .value and dispatches change event. Pass `ref` (from safari_snapshot) for a select inside an iframe or shadow DOM — a plain `selector` only reaches the top document. For custom dropdowns (React/LinkedIn), use safari_click on the dropdown trigger, then safari_click on the option instead.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_session_storage","description":"Get sessionStorage data for the current page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_set_cookie","description":"Set a cookie on the current page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_set_local_storage","description":"Set a value in localStorage","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_set_session_storage","description":"Set a value in sessionStorage","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_snapshot","description":"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 l","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_start_console","description":"Start capturing console messages (log, warn, error, info). Call once per page.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_start_network_capture","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. For quick overview of already-loaded resources, use safari_network instead.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_switch_tab","description":"Switch the MCP session's logical target without focusing Safari. Pass an index for the current session window, or an opaque receipt to recover the exact owned tab across Safari windows; a valid receipt takes precedence over any supplied index. Rarely needed: passing `receipt` on each tool call already targets that tab.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_throttle_network","description":"Simulate slow network conditions. Profiles: slow-3g, fast-3g, 4g, offline. Or custom latency/speed. Call with no args to reset.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_type_text","description":"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 — re","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_upload_file","description":"Upload a file to a <input type='file'> 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 s","write_action":true,"price_micros":0,"input_schema":null},{"name":"safari_verify_state","description":"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 — `.value` or `.textContent` may show new text while the internal store still holds old data, so a Submit click sends stale data. Call this AFTER safari_fil","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_wait","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.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_wait_for","description":"Wait for an element or text to appear on the page","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_wait_for_new_tab","description":"Wait for a new tab to appear (e.g. after OAuth login click opens popup). Automatically switches to the new tab.","write_action":false,"price_micros":0,"input_schema":null},{"name":"safari_webkit_compat","description":"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.","write_action":false,"price_micros":0,"input_schema":null}],"scan":{"score":69,"grade":"C","scanned_at":"2026-09-19T19:34:39.425Z","report":{"scannerVersion":"0.1.5","scannedAt":"2026-09-19T19:34:39.326Z","components":{"code":{"score":10,"max":25,"notes":["18 source files scanned"]},"reliability":{"score":-1,"max":20,"notes":["no gateway calls yet and no remote to probe"]},"poisoning":{"score":-1,"max":15,"notes":["tools not inspected (local package is not executed); not counted"]},"auth":{"score":12,"max":15,"notes":["local package, no credentials required"]},"maintenance":{"score":15,"max":15,"notes":["last push 2 days ago"]},"identity":{"score":8,"max":10,"notes":["registry namespace matches repository owner","GitHub account older than a year"]}},"findings":[{"id":"install.script","severity":"medium","component":"code","title":"npm install lifecycle script present"},{"id":"exec.eval","severity":"medium","component":"code","title":"eval / new Function used","evidence":"extension/background.js: …ictions --- // Strategy 1: indirect eval (fast, works when CSP allows unsafe-eval)…"},{"id":"install.script","severity":"medium","component":"code","title":"npm install lifecycle script present","evidence":"package.json: …typecheck\": \"tsc -p jsconfig.json\", \"postinstall\": \"node scripts/postinstall.cjs || true\" …"}],"inputs":{"packages":[{"registryType":"npm","identifier":"safari-mcp","version":"2.21.11","found":true,"license":"MIT","hasInstallScripts":true,"dependencyCount":2,"publishedAt":"2026-09-18T05:53:35.975Z","repositoryUrl":"git+https://github.com/achiya-automation/safari-mcp.git","weeklyDownloads":2608}],"repo":{"found":true,"owner":"achiya-automation","repo":"safari-mcp","archived":false,"pushedAt":"2026-09-18T05:50:22Z","stars":204,"forks":28,"openIssues":9,"ownerType":"User","ownerAvatarUrl":"https://avatars.githubusercontent.com/u/154928410?v=4","ownerCreatedAt":"2023-12-26T20:39:43Z","license":"MIT"},"icon":{"url":"https://avatars.githubusercontent.com/u/154928410?v=4&s=128","source":"registry","width":128,"height":128},"presence":{"stars":204,"forks":28,"downloadsWeek":2608,"license":"MIT","lastPushAt":"2026-09-18T05:50:22.000Z","score":54}}}},"grade_history":[],"reviews":[]}