MCP server that lets an AI agent drive the iOS Simulator in a loop — accessibility-tree-first perception with screenshot fallback, built on simctl + idb.
Solid iOS automation toolkit with clear, action-oriented naming and comprehensive parameter descriptions. All 14 tools have descriptions (10 - 200 chars, well within baseline). Input schemas are present and typed with Zod. However, output schemas are undocumented, responses are JSON or image blobs with no declared structure. Error handling returns text messages but lacks recovery guidance (e.g., 'Try X next'). Missing tool annotations (readOnlyHint, destructiveHint). Perception tools (describe_ui, screenshot) are well-designed for agent loops; action tools (tap, swipe, type_text) have good parameter constraints. No batch variants for repeated operations.
Boot a simulator. Defaults to the already-booted sim, else the first available iPhone.
Open a URL / universal link in the simulator (jump straight to a screen).
PRIMARY PERCEPTION. Return the accessibility tree of the current screen as a list of elements (label, type, value, enabled, frame). Reason over this and tap by label.
Install a built .app bundle onto the simulator.
Launch an installed app by bundle id. Returns the launch output (pid).
List available simulator devices (udid, name, state, runtime).
Press a hardware button (HOME backgrounds the app; LOCK locks the screen).
Output schemas undocumented. Tools return JSON or image blobs with no declared structure. LLMs cannot plan downstream calls or extract fields reliably.
Error messages lack recovery guidance. Errors return plain text (e.g., 'ERROR: <message>') without suggesting next steps or categorizing as retryable/user-fixable/fatal.
No tool annotations. Tools lack readOnlyHint, destructiveHint, or idempotentHint metadata. Agents cannot infer safety/retry semantics without reading descriptions.
tap() parameter validation incomplete. Requires 'label' OR ('x' AND 'y'), but schema does not enforce mutual exclusivity. LLMs may pass invalid combinations.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | 2026-07-28+ | v2 |
Uninstall then reinstall an app for a clean state.
Capture a PNG screenshot of the current screen. Use as the vision fallback when an element is not exposed in the accessibility tree, or to verify state.
Grant/revoke/reset a privacy permission for an app (e.g. photos, camera, location, notifications).
Swipe/scroll from one point to another. Either give a `direction` (auto-computed from screen center) or explicit from/to coordinates.
Tap an element by accessibility label (preferred) or by raw x,y coordinate (fallback). Provide either `label` or both `x` and `y`.
Terminate a running app by bundle id.
Type text into the currently focused field. Tap the field first to focus it.
swipe() direction and coordinate parameters are mutually exclusive but not documented. LLMs may pass both, causing ambiguous behavior.