Skip to main content
Glama

iphone-safari-mcp

An MCP server that drives Safari on a physically attached iPhone through Apple's safaridriver (platformName: "ios"). No Xcode, no Appium, no WebDriverAgent.

Gives a coding agent the closed loop: navigate → screenshot + DOM snapshot + console + network timings → click/type/tap/scroll → repeat, all on the real device.

Prerequisites

On the iPhone — Settings → Apps → Safari → Advanced:

  • Web Inspector: ON

  • Remote Automation: ON

On the Mac, once:

safaridriver --enable

At session time the phone must be plugged in, unlocked, and trusted. Only one WebDriver session can exist at a time — close any Selenium script or Web Inspector automation session first.

Related MCP server: paparazzi

Install

Needs uv. Nothing else — uv fetches Python and the dependencies itself.

Run it straight from the repo, no clone and no venv:

uvx --from git+https://github.com/ikatkov/iphone-safari-mcp \
  iphone-safari-mcp --selftest https://example.com

Or work on it locally:

git clone https://github.com/ikatkov/iphone-safari-mcp
cd iphone-safari-mcp
uv sync                       # resolves dependencies into .venv
uv run iphone-safari-mcp --selftest https://example.com

The selftest prints the user agent (should say iPhone), writes /tmp/iphone-safari-selftest.png, and reports how many interactive elements it found. --help lists everything.

The examples below use uv run iphone-safari-mcp (from a clone); every one of them works with the uvx --from git+… form too.

How it talks to safaridriver

The server starts one long-lived safaridriver and reuses it, rather than letting Selenium spawn a throwaway one per session.

This matters. safaridriver needs several seconds after launch to enumerate USB devices. Selenium's webdriver.Safari() spawns a fresh driver and fires New Session immediately — which lands inside that window, when the attached iPhone is still invisible and only already-cached network-paired devices exist. The symptom is baffling: session creation fails naming some other household device, and your cabled phone is absent from the list entirely while sitting right there in Safari → Develop.

So session creation also retries for IPHONE_SAFARI_DISCOVERY_TIMEOUT seconds (default 45) instead of failing on the first miss.

To debug discovery, run your own driver and attach to it:

safaridriver --diagnose -p 4444          # logs to ~/Library/Logs/com.apple.WebDriver/
IPHONE_SAFARI_DRIVER_URL=http://localhost:4444 uv run iphone-safari-mcp --verify

Pick the right phone

safaridriver will use any paired host that matches, including devices paired over the network that you never plugged in. Always pin the device:

uv run iphone-safari-mcp --list-devices     # what safaridriver can see, and why each was rejected
uv run iphone-safari-mcp --device "My iPhone" --selftest https://example.com

For the MCP server, pin it with an env var — IPHONE_SAFARI_DEVICE_NAME, IPHONE_SAFARI_DEVICE_UDID, or IPHONE_SAFARI_DEVICE_TYPE. UDID is the robust choice since names change. session_info reports both what you pinned and what you got.

A device missing from --list-devices entirely is not paired — check the cable, tap Trust, and confirm it appears under Safari → Develop on the Mac. A device that is listed but rejected tells you the reason ("Web Inspector is not enabled on device").

Register with Claude Code

Verify before you register. Other household devices pair too, and a wrong pin fails silently — it just drives someone else's phone. --verify paints a large random code on whatever screen it actually controls:

uv run iphone-safari-mcp --verify --device "My iPhone"

Only register once the code appears on the phone you intend to drive:

claude mcp add iphone-safari --scope user \
  -e IPHONE_SAFARI_DEVICE_UDID=<udid confirmed by --verify> \
  -- uvx --from git+https://github.com/ikatkov/iphone-safari-mcp iphone-safari-mcp

That pins nothing to this directory — the agent can launch it from anywhere. uv caches the environment, so only the first start needs the network.

To run your own checkout instead, point uv at it by absolute path, since the agent won't launch from this directory:

claude mcp add iphone-safari --scope user \
  -e IPHONE_SAFARI_DEVICE_UDID=<udid confirmed by --verify> \
  -- uv run --directory /abs/path/to/iphone-safari-mcp iphone-safari-mcp

Prefer the UDID over the name: --verify prints the UDID that safaridriver actually bound to, and unlike names it can't drift or collide.

Run this from a real terminal with Claude Code closed — it rewrites ~/.claude.json on exit and will clobber the edit otherwise.

Then in a session: "Use iphone-safari. Report what device you're connected to, open http://localhost:5173, screenshot it and list any console errors."

Tools

Tool

Purpose

session_info

Confirm you're on the iPhone, not Mac Safari — user agent, viewport, DPR

navigate

Open a URL and arm console capture

screenshot

Downscaled PNG of the viewport

snapshot

Start here. URL, viewport, scroll, and every visible interactive element with a CSS selector, label and rect

page_source

Raw HTML, truncated

click / type_text

Act on an element by css, xpath or text

tap

Real single-finger touch at viewport coordinates

scroll

Scroll by pixel delta

evaluate_javascript

Run JS in the page

console_logs / install_console_capture

Console + uncaught errors + rejections

network_timings

Resource timings; transferSize: 0 usually means a failed request

go_back / reload_page / close_session

Session control

Prefer snapshot over page_source — it's a fraction of the tokens and gives you selectors you can act on directly.

Limits

Apple's Safari WebDriver is deliberately web-content automation, not device automation. No Home screen, Settings, app switching, rotation, or system dialogs — Apple calls general device automation a non-goal. If you need those, use mobile-next/mobile-mcp, which drives the whole device but requires go-ios + WebDriverAgent provisioned onto the phone.

Safari 27 / STP 247+ ship an MCP server inside safaridriver itself (safaridriver --mcp), but as of Safari 26.2 that flag does not exist, and Apple only documents it against Safari on the Mac.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    B
    maintenance
    Local MCP server for Android and iOS mobile automation and performance telemetry, enabling device control (screenshot, tap, swipe, input, app launch) and metric collection (CPU, memory, launch time) via ADB, simctl, and WebDriverAgent with SQLite session history.
    21
    1
    MIT
  • A
    license
    -
    quality
    D
    maintenance
    MCP server that connects to your browser to capture screenshots, inspect console logs, network requests, and more via Chrome DevTools Protocol.
    4
    2
    MIT
  • A
    license
    -
    quality
    B
    maintenance
    An MCP server for headless mobile QA automation that controls real Safari, Flutter, and native iOS apps on Xcode Simulators via WebKit Remote Debugging Protocol, enabling parallel multi-device testing and persistent login sessions.
    12
    15
    MIT

View all related MCP servers

Related MCP Connectors

  • Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.

  • MCP connector for iMessage & Contacts via a local Mac agent + Vercel relay

  • Live browser debugging for AI assistants — DOM, console, network via MCP.

View all MCP Connectors

Latest Blog Posts

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/ikatkov/iphone-safari-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server