Skip to main content

ios-simulator-mcp

MCP server that gives AI assistants (Claude, Cursor, etc.) direct control over the iOS Simulator.

Built on xcrun simctl + AppleScript. 21 tools covering device management, UI interaction, app control, sensor simulation, logs, and video recording — no Appium, no WebDriver, no extra services.

Platform: macOS only · Requires Xcode with iOS Simulator installed


Install & run

No installation needed. uv downloads and runs the package in an isolated environment:

uvx ios-simulator-mcp

To install permanently:

uv tool install ios-simulator-mcp
# or
pip install ios-simulator-mcp

Configure your client

Claude Code

Add to ~/.claude/settings.json:

{
  "mcpServers": {
    "ios-simulator": {
      "command": "uvx",
      "args": ["ios-simulator-mcp"]
    }
  }
}

Or run from Claude Code's terminal:

claude mcp add ios-simulator -- uvx ios-simulator-mcp

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "ios-simulator": {
      "command": "uvx",
      "args": ["ios-simulator-mcp"]
    }
  }
}

Restart Claude Desktop after saving.

Cursor

Edit .cursor/mcp.json in your project root (or ~/.cursor/mcp.json globally):

{
  "mcpServers": {
    "ios-simulator": {
      "command": "uvx",
      "args": ["ios-simulator-mcp"]
    }
  }
}

VS Code (with Copilot / MCP extension)

Edit .vscode/mcp.json:

{
  "servers": {
    "ios-simulator": {
      "type": "stdio",
      "command": "uvx",
      "args": ["ios-simulator-mcp"]
    }
  }
}

Pin a specific simulator (optional)

If you have multiple simulators and want to target a specific one without passing udid to every tool:

{
  "mcpServers": {
    "ios-simulator": {
      "command": "uvx",
      "args": ["ios-simulator-mcp"],
      "env": {
        "IOS_SIM_DEFAULT_UDID": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890"
      }
    }
  }
}

Get your UDID with xcrun simctl list devices or by asking the AI to call list_simulators.


Accessibility permission (required for tap & swipe)

tap and swipe use AppleScript to send clicks to the Simulator window. macOS requires Accessibility access for the process running the MCP server — typically your terminal app or the MCP client itself.

Go to System Settings → Privacy & Security → Accessibility and add:

  • Your terminal app (Terminal, iTerm2, Warp, etc.) if running Claude Code from the terminal
  • Claude Desktop or Cursor if using those clients

Without this, tap and swipe will return an error. take_screenshot, input_text, and all other tools work without this permission.


Tools reference

All tools accept an optional udid parameter. When omitted, the server auto-detects the booted simulator or falls back to IOS_SIM_DEFAULT_UDID.


Device management

list_simulators

List all simulators known to Xcode, with their name, UDID, state, and runtime.

Parameter Type Default Description
runtime_filter string — Filter by runtime fragment, e.g. "iOS 18"
state_filter string — Filter by state: "Booted" or "Shutdown"
# Example prompt
"List all booted iOS 18 simulators"
→ calls list_simulators(runtime_filter="iOS 18", state_filter="Booted")

Returns: devices[], total, booted_count, booted[]


get_booted_simulator

Returns the currently booted simulator(s). No parameters.

Useful at the start of a session to confirm which device is active before running other tools.

Returns: booted[], primary (first booted device), count


boot_simulator

Boot a simulator by UDID. The UDID must come from list_simulators.

Parameter Type Required Description
udid string yes Simulator UDID
# Example prompt
"Boot the iPhone 16 Pro simulator"
→ calls list_simulators() first to find the UDID, then boot_simulator(udid="...")

The Simulator app opens automatically. Allow a few seconds before interacting.


shutdown_simulator

Shutdown a booted simulator.

Parameter Type Default Description
udid string auto Simulator UDID

Screenshots & UI interaction

take_screenshot

Capture the current simulator screen and return it as an inline image.

Parameter Type Default Description
udid string auto Simulator UDID

The image is returned directly to the AI so it can analyze the UI, read text, locate elements, and decide where to tap — no file path needed.

# Example workflow
1. take_screenshot()          → AI sees the current screen
2. tap(x=196, y=430)          → AI taps a button it located
3. take_screenshot()          → AI verifies the result

tap

Tap at a point on the simulator screen.

Parameter Type Default Description
x int required Horizontal position in logical pixels (from left edge of device screen)
y int required Vertical position in logical pixels (from top edge of device screen)
udid string auto Simulator UDID

Coordinates use the same space as screenshots. (0, 0) is the top-left corner of the device screen (not the window chrome).

Requires Accessibility permission — see above.

# Example prompt
"Tap the Login button"
→ AI calls take_screenshot() to see where Login is, then tap(x=196, y=512)

swipe

Perform a swipe gesture between two points.

Parameter Type Default Description
x1 int required Start X
y1 int required Start Y
x2 int required End X
y2 int required End Y
duration float 0.5 Swipe duration in seconds
udid string auto Simulator UDID
# Scroll down a list
swipe(x1=196, y1=600, x2=196, y2=200, duration=0.4)

# Swipe left (e.g. next page in onboarding)
swipe(x1=350, y1=400, x2=40, y2=400, duration=0.3)

Requires Accessibility permission — see above.


input_text

Type text into the currently focused text field on the simulator.

Parameter Type Default Description
text string required Text to type
udid string auto Simulator UDID

Tap the target field first to focus it, then call input_text.

# Tap the email field, then type
tap(x=196, y=280)
input_text(text="user@example.com")

App control

launch_app

Launch an app on the simulator.

Parameter Type Default Description
bundle_id string required App bundle ID (e.g. com.example.MyApp)
udid string auto Simulator UDID
wait_for_debugger bool false Pause on launch until a debugger attaches
launch_app(bundle_id="com.example.MyApp")

terminate_app

Force-terminate a running app.

Parameter Type Default Description
bundle_id string required App bundle ID
udid string auto Simulator UDID

open_url

Open a URL or deep link in the simulator. Useful for testing deep link routing without tapping through the UI.

Parameter Type Default Description
url string required URL or deep link
udid string auto Simulator UDID
open_url(url="myapp://home/settings")
open_url(url="https://example.com")

uninstall_app

Remove an app and all its data from the simulator. Equivalent to long-pressing → Remove App on device.

Parameter Type Default Description
bundle_id string required App bundle ID
udid string auto Simulator UDID

Permissions

grant_permission / revoke_permission

Grant or revoke a privacy permission for an app without going through the system dialog.

Parameter Type Default Description
bundle_id string required App bundle ID
permission string required Permission name (see below)
udid string auto Simulator UDID

Available permissions: all, calendar, camera, contacts, faceid, homekit, location, medialibrary, microphone, motion, photos, reminders, siri

grant_permission(bundle_id="com.example.MyApp", permission="camera")
revoke_permission(bundle_id="com.example.MyApp", permission="photos")

Sensor simulation

set_location

Override the GPS coordinates reported to all apps on the simulator.

Parameter Type Default Description
latitude float required Decimal degrees (e.g. 40.7128)
longitude float required Decimal degrees (e.g. -74.0060)
udid string auto Simulator UDID
set_location(latitude=48.8566, longitude=2.3522)  # Paris

set_appearance

Switch between light and dark mode.

Parameter Type Default Description
mode string required "light" or "dark"
udid string auto Simulator UDID

set_battery

Override the battery indicator in the status bar.

Parameter Type Default Description
level int required Battery percentage 0–100
state string "charged" "charged", "charging", "discharging", or "unknown"
udid string auto Simulator UDID
set_battery(level=15, state="discharging")  # test low-battery UI

Logs

get_logs

Stream simulator system logs for a short period and return the captured lines. Useful for debugging crashes, reading print statements, and checking network errors.

Parameter Type Default Description
process string — Filter by process name, e.g. "Runner" or your app name
keyword string — Keep only lines containing this string (case-insensitive)
lines int 100 Max lines to return
timeout_seconds int 3 How long to stream before stopping
udid string auto Simulator UDID
# Get the last 50 log lines from your app
get_logs(process="MyApp", lines=50)

# Find crash-related lines
get_logs(keyword="crash", timeout_seconds=5)

# Flutter / React Native: filter by your process
get_logs(process="Runner", keyword="ERROR")

Returns: lines[], count, stderr


Media & recording

add_media

Inject a photo or video file into the simulator's Photos library. Useful for testing image picker flows.

Parameter Type Default Description
file_path string required Absolute path to an image or video file
udid string auto Simulator UDID
add_media(file_path="/Users/you/Desktop/test-photo.jpg")

start_video_recording

Start recording the simulator screen to an .mp4 file.

Parameter Type Default Description
output_path string /tmp/sim_recording_<timestamp>.mp4 Output file path
udid string auto Simulator UDID

Returns the output path and PID. Call stop_video_recording() to finalize the file.


stop_video_recording

Stop an active screen recording and save the file.

Parameter Type Default Description
udid string auto Simulator UDID

Returns: output_path, size_bytes


Example workflows

Test a login flow end-to-end

1. boot_simulator(udid="...")          boot iPhone 16 Pro
2. launch_app(bundle_id="com.myapp")  open the app
3. take_screenshot()                   confirm login screen is shown
4. tap(x=196, y=320)                  tap email field
5. input_text(text="test@example.com")
6. tap(x=196, y=390)                  tap password field
7. input_text(text="secret123")
8. tap(x=196, y=490)                  tap Login button
9. take_screenshot()                   verify logged-in state

Test location-based features

1. grant_permission(bundle_id="com.myapp", permission="location")
2. set_location(latitude=40.7128, longitude=-74.0060)  New York
3. launch_app(bundle_id="com.myapp")
4. take_screenshot()                                   verify location shown

Debug a crash

1. launch_app(bundle_id="com.myapp")
2. get_logs(process="MyApp", keyword="error", timeout_seconds=10)
   → returns relevant error lines
3. open_url(url="myapp://the-crashing-screen")
4. get_logs(process="MyApp", lines=200)

Record a demo video

1. start_video_recording(output_path="/tmp/demo.mp4")
2. ... perform actions ...
3. stop_video_recording()   → returns /tmp/demo.mp4

Environment variables

Variable Default Description
IOS_SIM_DEFAULT_UDID auto-detect Pin a specific simulator UDID
IOS_SIM_DEVICE_WIDTH auto-detect Logical screen width in points, used for coordinate mapping in tap/swipe. Set this if your device is not in the built-in lookup table
IOS_SIM_LOG_FILE stderr only Path to write server logs in addition to stderr

Limitations

  • macOS only. Requires Xcode 14+ with iOS Simulator.
  • tap and swipe require Accessibility permission for the process running the server (terminal or MCP client). See Accessibility permission.
  • tap / swipe bring the Simulator window to the foreground.
  • Device width auto-detection covers iPhone 12 and later. For older or iPad device types, set IOS_SIM_DEVICE_WIDTH manually.
  • One video recording active per simulator at a time.

License

MIT

Metadata

Release files for ios-simulator-mcp 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ios-simulator-mcp 0.1.0
File Size Uploaded Provenance Actions
ios_simulator_mcp-0.1.0.tar.gz 18.4 kB With provenance Details for ios_simulator_mcp-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ios-simulator-mcp 0.1.0
File Interpreter ABI Platform Actions
ios_simulator_mcp-0.1.0-py3-none-any.whl Python 3 none any Details for ios_simulator_mcp-0.1.0-py3-none-any.whl

Total release size: 32.3 kB

Release files / ios_simulator_mcp-0.1.0.tar.gz

Download URL ios_simulator_mcp-0.1.0.tar.gz
Size 18.4 kB
Tags Source
SHA-256 checksum
How to use checksums
504842a5af95701aa003a7d3bdaf4fc7d7233a6fed8dc3fbebfe89add7a0c1d4
BLAKE2b-256 checksum
How to use checksums
8e2e2f0f43601c41a000d70178f846388b2c5d65db1c9f82d28bfccf15101190
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 29, 2026.

Transparency log

Release files / ios_simulator_mcp-0.1.0-py3-none-any.whl

Download URL ios_simulator_mcp-0.1.0-py3-none-any.whl
Size 13.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
27de754a94eb03a630bada2ebdc9645649270dde3462984366f81ac643248a02
BLAKE2b-256 checksum
How to use checksums
f396ddb2ca807791c568b24897a6a651037aae3586f6fedc5c66e41e7b74710b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 29, 2026.

Transparency log

Security for ios-simulator-mcp 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ios_simulator_mcp-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 29, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page