Skip to main content
Glama

ios-sim-mcp

A Model Context Protocol (MCP) server that lets AI agents (Claude, Windsurf, Cursor, etc.) drive iOS Simulators on macOS — listing devices, launching apps, tapping, typing, swiping, reading the on-screen UI tree and taking screenshots.

The package is published as ios-sim-mcp and exposes the ios-sim-mcp binary. It talks to the simulator through two channels:

  • xcrun simctl — app launch/terminate, installed-app listing, screenshots

  • WebDriverAgent (on localhost:8100) — taps, swipes, key input, hardware buttons, orientation, UI element tree, opening URLs


Table of contents


Related MCP server: Simulator MCP

Architecture

┌──────────────┐  stdio (MCP)  ┌──────────────────────┐
│  MCP client  │──────────────▶│  src/index.js        │
│ (Claude etc.)│◀──────────────│  src/server.js       │  tool registry
└──────────────┘               └─────────┬────────────┘
                                         │ Robot interface (src/robot.js)
                                         ▼
                               ┌──────────────────────┐
                               │ src/iphone-simulator │  Simctl / SimctlManager
                               └───┬──────────────┬───┘
                     xcrun simctl  │              │  HTTP (W3C WebDriver)
                                   ▼              ▼
                          ┌──────────────┐  ┌───────────────────────┐
                          │ iOS Simulator│◀─│ WebDriverAgent :8100  │
                          └──────────────┘  └───────────────────────┘
  • src/index.js starts the MCP server over a stdio transport.

  • src/server.js registers every tool and holds the currently selected device ("robot").

  • src/robot.js documents the Robot interface every device controller implements, plus shared constants (ORIENTATIONS, BUTTONS, SWIPE_DIRECTIONS) and ActionableError.

  • src/iphone-simulator.js implements the Robot interface for iOS Simulators (Simctl) and discovers simulators (SimctlManager).

  • src/webdriver-agent.js is a small WebDriverAgent HTTP client. Each call opens a WDA session, runs the request and deletes the session.

  • src/png.js / src/image-utils.js validate PNG screenshots and optionally downscale/convert them via ImageMagick.

For detailed diagrams, API contracts (MCP, WebDriverAgent HTTP, simctl), connection types and request flows, see ARCHITECTURE.md.

Requirements

Requirement

Notes

macOS

Simulator discovery returns nothing on other platforms.

Xcode + Command Line Tools

Provides xcrun simctl and the iOS Simulator.

Node.js ≥ 18

Uses the built-in fetch API.

WebDriverAgent

Must be running on the simulator, reachable at http://localhost:8100.

ImageMagick 7 (optional)

If magick is on PATH, screenshots are resized and converted to JPEG (quality 75) to shrink the payload. brew install imagemagick

Installation

git clone https://code.devsnc.com/harish-dewangan/ios-sim-mcp.git
cd ios-sim-mcp
npm install

Boot a simulator (via Xcode → Open Developer Tool → Simulator, or):

xcrun simctl list devices          # find a device UDID
xcrun simctl boot <UDID>
open -a Simulator

Running WebDriverAgent

Most tools (everything except app listing/launch/terminate and screenshots) need WebDriverAgent. One way to run it on a booted simulator:

git clone https://github.com/appium/WebDriverAgent.git
cd WebDriverAgent
xcodebuild -project WebDriverAgent.xcodeproj \
  -scheme WebDriverAgentRunner \
  -destination "platform=iOS Simulator,id=<UDID>" \
  test

Verify it is up:

curl http://localhost:8100/status

The host and port (localhost:8100) are hard-coded in src/iphone-simulator.js (WDA_PORT).

Configuring an MCP client

The server speaks MCP over stdio. Point your client at src/index.js:

{
  "mcpServers": {
    "ios-sim-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/ios-sim-mcp/src/index.js"]
    }
  }
}
  • Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Claude Code: claude mcp add ios-sim-mcp -- node /absolute/path/to/ios-sim-mcp/src/index.js

  • Windsurf / Cursor: add the same block to the editor's MCP config.

To run it standalone (e.g. for debugging with the MCP Inspector):

npm start
# or
npx @modelcontextprotocol/inspector node src/index.js

Available tools

Tool

Parameters

Description

mobile_list_available_devices

_unused: string (ignored)

Lists booted iOS simulators by name.

mobile_use_device

device: string, deviceType: "simulator"

Selects the simulator for all later calls. Pass the simulator UDID (see limitations).

mobile_list_apps

—

Lists installed apps as name (bundle id).

mobile_launch_app

packageName: string

Launches an app by bundle id (xcrun simctl launch).

mobile_terminate_app

packageName: string

Terminates an app by bundle id.

mobile_get_screen_size

—

Returns screen size in points via WDA.

mobile_click_on_screen_at_coordinates

x: number, y: number

Taps at the given coordinates.

mobile_list_elements_on_screen

—

Returns visible UI elements (TextField, Button, Switch, Icon, SearchField, StaticText, Image, WebView…) with rect, label/name and WDA attributes.

mobile_press_button

button: string

HOME, VOLUME_UP, VOLUME_DOWN, or ENTER (sent as \n).

mobile_open_url

url: string

Opens a URL on the device via WDA.

swipe_on_screen

direction: "up" | "down"

Vertical swipe between y=200 and y=600 at x=200.

mobile_type_keys

text: string, submit: boolean

Types into the focused element; presses Enter if submit is true.

mobile_take_screenshot

—

Returns the screenshot as an image and saves a copy to disk (see OUTPUT_DIR).

mobile_set_orientation

orientation: "portrait" | "landscape"

Rotates the device.

mobile_get_orientation

—

Returns the current orientation.

All tools except mobile_list_available_devices and mobile_use_device require a device to be selected first.

Typical agent workflow

  1. mobile_list_available_devices — see what's booted.

  2. mobile_use_device — select a simulator (by UDID).

  3. mobile_launch_app — e.g. com.apple.mobilesafari.

  4. mobile_list_elements_on_screen and/or mobile_take_screenshot — understand the UI.

  5. mobile_click_on_screen_at_coordinates / mobile_type_keys / swipe_on_screen — interact.

  6. Repeat 4–5, then mobile_terminate_app.

Example prompt to an agent:

Open Safari on the booted iPhone simulator, go to example.com and take a screenshot.

Project structure

.
├── src/
│   ├── index.js            # Entry point: MCP server over stdio
│   ├── server.js           # Tool definitions and device selection
│   ├── robot.js            # Robot interface docs, constants, ActionableError
│   ├── iphone-simulator.js # Simctl (Robot impl) + SimctlManager (discovery)
│   ├── webdriver-agent.js  # WebDriverAgent HTTP client
│   ├── png.js              # PNG signature / dimension parsing
│   └── image-utils.js      # ImageMagick-based resize / JPEG conversion
├── examples/               # (currently empty)
├── package.json
├── LICENSE
├── ARCHITECTURE.md
└── README.md

npm scripts

Script

Command

Notes

start

chmod +x src/index.js && node src/index.js

Runs the MCP server on stdio.

lint

eslint .

No ESLint config file is present in the repo yet.

test

nyc mocha test/*.js

No test/ directory exists yet.

clean

rm -rf lib

prepare

husky

Runs on npm install; no .husky/ hooks are committed.

Error handling

Tools are wrapped so that:

  • An ActionableError (e.g. "No device selected", "WebDriverAgent is not running on simulator", unsupported button) is returned as plain text ending in "Please fix the issue and try again." so the agent can self-correct.

  • Any other exception is returned with isError: true and the message Error: <message>.

Known limitations

These reflect the current code and are worth knowing before relying on the server:

  • iOS Simulator only. No Android or physical iOS device support; deviceType only accepts "simulator".

  • Device name vs. UDID. mobile_list_available_devices returns simulator names, but mobile_use_device passes its argument straight to xcrun simctl as the device identifier. Supply the UDID (from xcrun simctl list devices); booted may also work when a single simulator is running.

  • Hard-coded screenshot directory. OUTPUT_DIR in src/server.js is set to /Users/harish.dewangan/Documents/ios-demo/. Change it for your machine. Files are always saved with a .png extension, even when ImageMagick has converted them to JPEG.

  • stdout logging. Several tools use console.log, which writes to stdout — the same stream the stdio MCP transport uses. Some clients may report protocol/parse errors because of this; switching those calls to console.error avoids it.

  • mobile_list_apps parsing. The regexes in Simctl.parseIOSAppData use \\s inside regex literals, which matches a literal backslash rather than whitespace, so app listing may return an empty list.

  • Swipe supports only up/down with fixed coordinates, regardless of screen size.

  • WebDriverAgent location is fixed at localhost:8100, and a new WDA session is created per call (slower, but stateless).

  • zod is imported by src/server.js but not declared in package.json; it currently resolves as a transitive dependency of @modelcontextprotocol/sdk.

License

MIT © 2026 harishdk522

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to automate iOS Simulator interactions including device management, UI element interaction (tap, swipe, type), screenshot capture, and execution of YAML-defined navigation workflows.
    26 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI to control iOS simulators through the MCP protocol. Supports device management, UI automation, and network interception including screenshot capture, text input, and HTTP request mocking.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to control real iPhones and simulators on macOS, allowing for UI interaction, testing, and automation.
    33 npm
    92
    MIT