@mgcrea/mcp-ios-simulator
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| IOS_SIMULATOR_ID | No | UDID, name, or `booted`. Two booted and no value is an error that names them. | |
| IOS_SIMULATOR_DEBUG | No | Log every `simctl` and WebDriverAgent call to stderr. | false |
| IOS_SIMULATOR_CONFIG | No | Path to the config file; used to move the default config location. | ~/.config/ios-simulator-mcp/config.json |
| IOS_SIMULATOR_WDA_URL | No | Explicit override; rarely needed. | http://127.0.0.1:8100 |
| IOS_SIMULATOR_WDA_PORT | No | Must match the runner's `USE_PORT`. One port per simulator. | 8100 |
| IOS_SIMULATOR_OUTPUT_DIR | No | Screenshots, launch logs, the runner log. | $TMPDIR/mcp-ios-simulator |
| IOS_SIMULATOR_TIMEOUT_MS | No | Budget for one `simctl` call; a boot is slow. | 120000 |
| IOS_SIMULATOR_LAUNCH_ARGS | No | Launch arguments applied when `launch` passes none of its own. | |
| IOS_SIMULATOR_ALLOW_WRITES | No | `0` drops the fourteen driving tools from `tools/list`. | on |
| IOS_SIMULATOR_MAX_TREE_BYTES | No | Byte cap on a `ui_tree` payload. | 24000 |
| IOS_SIMULATOR_WDA_TIMEOUT_MS | No | Budget for one WebDriverAgent call. | 30000 |
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
} |
| resources | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| ios_simulator_diagnosticsA | Report both lanes separately and never fail: which simulators exist and which are usable, which one this server would drive, its screen geometry, and whether WebDriverAgent is answering — including which simulator owns its port, which is the one way to catch a second runner quietly taking your taps. Start here when anything else misbehaves. |
| ios_simulator_listA | List the simulators on this machine, with the UDID every other tool takes. Shows the usable ones: a typical machine carries thirty-odd simulators and a good fraction of them are orphans whose runtime is no longer installed, which cannot be booted, driven or screenshotted at all. The result still says how many were left out and how to delete them, and |
| ios_simulator_list_appsA | List the apps installed on a simulator, with the bundle id every other tool takes. Defaults to your own apps: a stock simulator carries about thirty, and twenty-five of them are Apple's. Each entry also carries |
| ios_simulator_screenshotA | Capture the screen and return it as an image. By default it is scaled to exactly the device's point size, which means a position read off this image can be passed straight to ios_simulator_tap with no conversion — the returned metadata says |
| ios_simulator_ui_treeA | List the addressable elements on screen — type, label, accessibility identifier, and the exact point to tap — flattened rather than nested. Prefer this over reading coordinates off a screenshot whenever you can: a label or identifier survives the screen moving, and a pixel position does not. The raw hierarchy is tens of KB, so this returns controls only by default; use |
| ios_simulator_wait_for_elementA | Poll until an element appears, or until it goes away. This is the tool for a screen that loads: a generation step, a network round trip, a long import. |
| ios_simulator_tapA | Tap a position on screen, in points. Prefer ios_simulator_tap_element when the target has a label or an accessibility identifier — a position stops being right the moment the layout shifts, and nothing about a wrong tap looks wrong. Coordinates come from a default ios_simulator_screenshot image or from a |
| ios_simulator_tap_elementA | Tap the element with this accessibility identifier or label, letting the device resolve its position. This is the tool to reach for: it survives the screen scrolling, the layout changing and the copy being reworded, none of which a coordinate does. Give exactly one of |
| ios_simulator_swipeA | Drag from one point to another, in points — how you scroll a list, pull to refresh, or swipe a row open. To scroll down a page, swipe from low on the screen to high on it. |
| ios_simulator_typeA | Type text into whatever currently has keyboard focus, or into a named field. Focus is the trap: with nothing focused the keystrokes go nowhere and the call still succeeds, so pass |
| ios_simulator_press_buttonA | Press a hardware button. |
| ios_simulator_powerA | Boot or shut down a simulator. Booting is the one thing this server will not do for you implicitly — a cold boot takes tens of seconds and puts a window on the user's screen, and it changes which simulator an unqualified call resolves to afterwards. Both directions are idempotent: booting a booted simulator succeeds. |
| ios_simulator_eraseA | Wipe a simulator back to a factory state: installed apps, their data, the keychain and every granted permission. The only irreversible tool here, and the reason it is the only one behind |
| ios_simulator_installA | Install a build. The path must be a |
| ios_simulator_launchA | Launch an installed app. Pass |
| ios_simulator_terminateA | Kill a running app. The app is not uninstalled and its data is untouched — this is how you get back to a cold start without erasing anything. |
| ios_simulator_open_urlA | Open a URL on the simulator, which is how you exercise a deep link or a universal link without finding a way to tap one. An |
| ios_simulator_set_environmentA | Stage the simulator before a screenshot or a test: dark mode, Dynamic Type size, increased contrast, a frozen status bar, a simulated location, and app permissions. None of this is possible on a physical device, and it is most of the reason to prefer a simulator for UI work. Every field is optional; those given are applied in order and the result reports the state afterwards. A status bar override survives a reboot, so clear it when you are done or it quietly pollutes later screenshots. |
| ios_simulator_add_mediaA | Put photos or videos into the simulator's photo library. A simulator has no camera, and this is how you get around that: seed the library first, then drive the app's picker as normal. Without it, every flow that starts with an image is untestable here. Files are copied in, so the originals are untouched and the simulator keeps them until it is erased. Pair it with |
| ios_simulator_pushA | Deliver a push notification, with no APNs certificate and no server. The payload is a normal remote-notification body and must contain an |
| ios_simulator_restart_wdaA | Start the WebDriverAgent runner, or restart it after it has died. Only the UI tree and the input tools need it — screenshots and everything simctl does keep working without it. The runner is started detached so it outlives this conversation, and its output goes to a log file rather than to you. It does not wait: give it fifteen seconds or so, then check ios_simulator_diagnostics. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| diagnostics | The same report as ios_simulator_diagnostics, as a resource. |
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/mgcrea/mcp-ios-simulator'
If you have feedback or need assistance with the MCP directory API, please join our Discord server