@mgcrea/mcp-ios-simulator
Drive and inspect an iOS Simulator from an MCP client, covering screenshots, accessibility, input, app lifecycle, and device staging.
List simulators, installed apps, and diagnostics for both
simctland WebDriverAgent lanes.Capture screenshots directly via
simctlin point coordinates, with no runner needed.Read flattened accessibility UI trees with precomputed tap points (requires WebDriverAgent).
Wait for elements to appear or disappear.
Tap by coordinate or accessibility element, swipe, type, and press Home.
Boot, shut down, and erase simulators.
Install, launch with fixture arguments, terminate apps, and open deep/universal links.
Stage the device: dark mode, Dynamic Type, increased contrast, frozen status bar, simulated location, and app permissions.
Seed the photo library with images or videos.
Deliver remote push notifications without an APNs certificate or server.
Start or restart the WebDriverAgent runner when input/tree tools are needed.
Provides tools for driving an iOS Simulator, including screen capture, accessibility tree inspection, touch input (tap, swipe, type), app management, device staging (appearance, permissions, location), and push notification delivery.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@mgcrea/mcp-ios-simulatortake a screenshot and read the accessibility tree of the current app"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@mgcrea/mcp-ios-simulator
Model Context Protocol server for driving an iOS Simulator from a model: screenshot the screen, read its accessibility tree, tap, swipe, type, manage the app under test — and stage the device itself, which is the part no physical device can do.
No Apple Developer team. No code signing. No device trust. No tunnel. Nothing to unlock. And screenshots work with nothing installed at all.
Features
See the screen, with zero setup.
simctlcaptures it directly, scaled to exactly the device's point size, so a position read off the image is a tap coordinate with no conversion. No WebDriverAgent needed for this.Read the screen. A flattened, pruned accessibility tree — type, label, identifier and the precomputed tap point per element — instead of the tens of KB of nested JSON WebDriverAgent actually returns.
Drive the screen. Tap by coordinate or by accessibility label, swipe, type, press Home. Every action returns the resulting screen by default, so a mis-aimed tap is visible on the call that made it.
Stage the device. Dark mode, Dynamic Type size, increased contrast, a frozen 9:41 status bar, a simulated location, and app permissions granted or denied without a prompt anyone has to tap. None of this is possible on real hardware.
Push without APNs. Deliver a real remote notification with no certificate and no server.
Manage the app. Install a build, launch it with fixture arguments, terminate it, uninstall it, open a deep link. An app's data container is an ordinary path on this Mac, so its database or logs are read directly — there is nothing to copy off a device.
Read its logs.
launchwithcapture_logs: truewrites the app's stdout, stderr and everyLogger/os_logmessage into one file, andread_logsfollows it with a cursor, a regex filter and Xcode's thirty-character line prefix cut down to the time.Read its crashes. Simulator crash reports land among this Mac's own in
~/Library/Logs/DiagnosticReports;list_crash_logskeeps only the simulators', says which simulator each came from, andget_crash_logreturns the exception and the faulting thread with library names resolved.
Related MCP server: Shotter
Security
Writes are on by default, and that is deliberate. The rest of the fleet is
read-only until a flag is set because a mutating tool acts on someone's real
account or someone's real phone. A simulator is neither: it holds no person's
data, and ios_simulator_erase puts it back to factory in seconds.
What that still costs you, stated honestly:
installandlaunchrun code on your Mac. A simulated process is a host process.The app's data container is a plain host path, readable by anything.
eraseanduninstallare irreversible — they are the two tools behind an explicitconfirm.list_crash_logsreads this Mac's DiagnosticReports folder. It keeps only simulator reports andget_crash_logrefuses a Mac app's, but the folder is yours and the server reads it as you.IOS_SIMULATOR_ALLOW_WRITES=0restores the device server's posture in one variable, and then the seventeen driving tools are absent fromtools/listrather than refused, because a refusal still lets a model try, retry and reason about a way around it.
Your credentials. There are none. The server holds no tokens and talks to no
vendor API. Everything goes through xcrun simctl and a loopback HTTP server.
Supply chain. Three runtime dependencies: @modelcontextprotocol/server,
zod, and @mgcrea/mcp-ios-core — our own, and itself
dependent on only the first two. Scaling images uses sips and reading property
lists uses plutil, both of which ship with macOS, specifically so neither an
image library nor a plist parser has to be installed.
How it reaches the simulator
Lane | Carries | Needs |
| simulators, apps, install, launch, deep links, the screenshot, appearance, status bar, location, permissions, push, boot/shutdown/erase | Xcode. Nothing else. |
WebDriverAgent over HTTP | the accessibility tree, tap, swipe, type, buttons | a runner started once with |
The asymmetry with mcp-ios-device is worth stating plainly: there, every
pixel comes through WebDriverAgent, so nothing about the screen works until a
signed runner is installed and trusted on the phone. Here simctl captures the
screen itself, so eighteen of the twenty-five tools work with no runner at all
— only ios_simulator_ui_tree, ios_simulator_wait_for_element and the five
input tools need one, and building it
takes about two minutes with no Apple account.
ios_simulator_diagnostics reports both lanes separately, so "the simulator is
fine but the runner is not up" is a distinguishable answer rather than a generic
failure.
Configure
Variable | Default | What it does |
| the only booted simulator | UDID, name, or |
| on |
|
| none | Launch arguments applied when |
|
| Must match the runner's |
|
| Explicit override; rarely needed. |
|
| Byte cap on a |
|
| Budget for one |
|
| Budget for one WebDriverAgent call. |
|
| Screenshots, launch logs, the runner log. |
|
| Where |
| off | Log every |
The same keys in camelCase can go in ~/.config/ios-simulator-mcp/config.json
(IOS_SIMULATOR_CONFIG to move it). The environment wins per field, so a
one-off IOS_SIMULATOR_ALLOW_WRITES=0 beats a file that says true. Unknown keys
in the file are an error rather than silently ignored — a typo that looks like
"that setting had no effect" is the worst way to learn where your configuration
came from.
See .env.example for the annotated version.
Quick start
Requires macOS with Xcode and a booted simulator.
A. Everything except the tree and the taps, with no setup
npx -y @mgcrea/mcp-ios-simulatorlist, list_apps, screenshot, diagnostics, power, install, launch,
open_url, set_environment, push and erase all work immediately.
B. The input lane
ui_tree, tap, tap_element, swipe, type and press_button need a
WebDriverAgent runner. Build and start it — no team id, no signing, no prompt:
scripts/wda.sh setup # ~2 minutes
scripts/wda.sh run # leave this running
scripts/wda.sh status # is it answering?Installed from npm, the same script is the ios-simulator-wda binary:
npx -p @mgcrea/mcp-ios-simulator ios-simulator-wda setup
npx -p @mgcrea/mcp-ios-simulator ios-simulator-wda runC. Wired into a client
See .mcp.json.example.
Tools
Twenty-five. Eight are read-only; the other seventeen disappear with
IOS_SIMULATOR_ALLOW_WRITES=0. read_logs is among those seventeen although it
changes nothing: it only reads what launch started capturing, so it goes where
launch goes.
Tool | Writes? | What it does |
| Every simulator, with state and whether its runtime is installed | |
| Both lanes, the resolved target, the geometry, and who owns the WDA port | |
| Installed apps, with bundle id and host-path data container | |
| The screen, in point space — no runner needed | |
| Addressable elements with precomputed tap points | |
| Poll until something appears, or goes away | |
| Simulator crash reports, newest first, by simulator and process | |
| One report: exception, termination, faulting thread | |
| ✓ | Tap a point |
| ✓ | Tap by identifier, label or predicate |
| ✓ | Drag between two points |
| ✓ | Type into the focused field, or a named one |
| ✓ | Home |
| ✓ | Boot or shut down; never implicit |
| ✓ confirm | Wipe to factory |
| ✓ | Install a simulator |
| ✓ | Launch, with fixture arguments and captured output |
| ✓ (gate only) | Follow a |
| ✓ confirm | Remove one app and its data |
| ✓ | Kill a running app |
| ✓ | Deep links and universal links |
| ✓ | Appearance, Dynamic Type, contrast, status bar, location, permissions |
| ✓ | Seed the photo library — the way around the missing camera |
| ✓ | A remote notification, with no APNs certificate |
| ✓ | Start or restart the runner, detached |
Deliberately absent: create, clone, delete, rename, upgrade and pair
(fleet management, not driving, and delete all is a footgun with no upside);
get_app_container (list_apps already returns the path); keychain,
pbcopy, spawn, diagnose and recordVideo (real capabilities that an agent
would use approximately never, and every tool costs listing bytes on every
connect).
addmedia was on that list until 0.2.0, and it was the wrong call. A simulator
has no camera, so seeding the photo library is not a nice-to-have — it is the
only way an app whose first step is "choose a photo" can be driven here at all.
Anyone hitting that had to drop out to a shell, which is exactly what these
tools exist to avoid.
uninstall was on it too, on the grounds that install overwrites and erase
covers a first run. But erase takes every other app's data and a reboot with
it, and "this app's first launch, everything else as it was" is the ordinary
case. It sits behind confirm like erase.
Traps worth knowing
Measured on Xcode 26.6 (17F113) unless marked Xcode 27, which was checked on Xcode 27.0 (27A266a) with an iOS 27.0 runtime.
simctl io … screenshot -does not write to stdout. The help text says it does. It creates a file literally named-in the current working directory and printsWrote screenshot to: …to stderr, exit 0. This server always passes a real path.simctl ioon a simulator whose runtime is missing aborts — SIGABRT, exit 134, an uncaughtNSInternalInconsistencyExceptionand a thirty-line stack trace, not an error message. Availability is checked in the resolver, before the call. On a typical machine a large fraction of simulators are in this state.erase,deleteandshutdownall accept the literalall. A target of"all"reachingsimctl erasewipes every simulator on the machine. Refused in the resolver and again in the adapter.bootedis a coin flip. simctl's own help: "If multiple devices are booted … simctl will choose one of them." Resolved to a concrete UDID here first.WebDriverAgent scans ports 8100-8199 when
USE_PORTis unset. With two booted simulators, the second runner comes up healthy on 8101 and a server pointed at 8100 drives the first one while every call reports success.scripts/wda.shalways pinsUSE_PORT, anddiagnosticsreports the port's real owner viaSIMULATOR_UDIDfromps -Eww.listappsreturns an old-style NeXTSTEP plist, not JSON.--jsonis a flag onlistand nothing else.A status bar override survives a reboot. Clear it or it quietly pollutes every later screenshot.
simctl launchenvironment variables need aSIMCTL_CHILD_prefix on the calling process, not a flag.An app's
Loggeroutput reaches no file unlessOS_ACTIVITY_DT_MODEis set (Xcode 27). Settings launched plainly wrote 8 lines to stderr; launched withSIMCTL_CHILD_OS_ACTIVITY_DT_MODE=YESit wrote 77 in the same eight seconds, the unified log mirrored with Xcode's prefix.capture_logssets it.--stdoutand--stderrmay be the same file (Xcode 27). A probe app alternatingprint, stderr andLoggerproduced one file with all fifteen lines in order and nothing overwritten. The redirect appends, so a relaunch into the same path keeps the previous run's lines — everycapture_logslaunch gets a fresh file.A launch log under
/tmpor$TMPDIRis not where you asked (Xcode 27). The simulator opens the redirect itself, and it has its own/tmpand/var/folders:--stdout=/tmp/x/a.outcreated<device>/data/tmp/x/a.out, and the path given never existed — which is where this server's default output directory is.launchnow looks in both places and returns the real one. A path under/Usersis written as given.A simulator crash report says it is one in
platform, notis_simulated(Xcode 27). Of 593 reports on one Mac, the 464 from simulators all had headerplatform: 7(PLATFORM_IOSSIMULATOR), the Mac's all had 1, andis_simulated: 1was on 13 Mac reports — Safari, Mail and two helpers.procPathis anonymised, so the simulator's UDID comes from the body'scoalitionName(com.apple.CoreSimulator.SimDevice.<UDID>), which sat in the first 1.8 KB of every one.A Swift
fatalErrormessage is in the log, not the crash report (Xcode 27). The probe's report had the_assertionFailureframe and no application-specific text; the message was on stderr.get_crash_logsays so when it happens.simctl uninstallof an app that is not installed succeeds (Xcode 27), silently, exit 0. Success does not prove it was there.Launching an app that is not installed fails as "The request to open … failed" (Xcode 27),
FBSOpenApplicationServiceErrorDomaincode 4, with nothing about installation. The error now carries that remedy.A label belongs to the control and to every container around it. WebDriverAgent answers depth-first, so an unqualified label match lands on the navigation bar as readily as on the button — and a tap on a container does nothing while reporting success.
tap_elementnarrows a label to the interactive types first, and sayspreferredControlwhen it did.isVisibleis not always truthful. APHPickerpresented over Safari reports all nine of its asset cellsisVisible: "0"while they are on screen and tappable — a synthesised tap on one opens the preview. The defaultui_treefilter drops them, which is why the result carries afilteredtally: a short list that has been filtered and a screen that is genuinely bare are otherwise the same answer.simctl installwants a.appbundle directory built for the simulator — an.ipaor a device build fails with "No such file or directory", which reads like a path typo.simctl bootgives you no window. It runs headless, which is what an agent wants and confusing the first time;poweropens a window by default.Xcode 27 ships no Simulator.app. The simulator's window belongs to DeviceHub (
com.apple.dt.Devices), andopen -a Simulatorfails.powertries Simulator.app first and falls back to opening DeviceHub by bundle id; a window that still will not open is awarningon a boot that worked, never an error.DeviceHub cannot be told which device to show. It keeps one device per window, on whatever was last picked in its sidebar. No
devices://URL switches it —device/<UDID>, a bare UDID andsimulator/<UDID>were all ignored — and a query-string form it did not recognise made it quit, taking every booted simulator down with it.powertherefore opens it by bundle id and says in itsnoteto select the device. Screenshots and the WDA lane do not care which device the window shows.Quitting DeviceHub shuts every booted simulator down. Unlike Simulator.app, whose window could close with the device left running, a plain Quit takes the simulators with it; DeviceHub's separate "Quit and Keep Simulators Running" does not. Since
poweropens DeviceHub by default, a device that vanishes mid-session usually means someone quit that window. Passopen_window: falseto boot headless when nobody needs to watch.Xcode 27 moved the screen geometry out of
profile.plist. No device type's profile carriesmainScreen*any more, old types included; the same numbers are undercapabilities.ScreenDimensionsCapabilityincapabilities.plist. Reading only the profile defaults the scale to 1 and labels a 1206×2622 pixel capture as points, with nothing looking wrong.Two runtimes can share one identifier, so the key of
list devicesis not a primary key.
Develop
pnpm install
pnpm lint && pnpm format:check && pnpm typecheck && pnpm test && pnpm buildLicense
MIT — see LICENSE.
Available Tools
25 toolsios_simulator_add_mediaiOS 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 permission on ios_simulator_set_environment to skip the access prompt entirely.
| Name | Required | Description | Default |
|---|---|---|---|
| paths | Yes | Absolute paths to the images or videos, e.g. ["/Users/me/fixtures/monstera.jpg"]. Formats are the ones Photos itself accepts — JPEG, PNG, HEIC, MOV, MP4. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say non-read-only, non-idempotent, non-destructive. The description adds meaningful behavioral detail beyond those flags: 'Files are copied in, so the originals are untouched and the simulator keeps them until it is erased.' This clarifies persistence, non-destructiveness to source files, and the fact that the simulator's library is mutated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is about five sentences long, but every sentence earns its place: purpose, motivation, workflow, side effects, and integration with a sibling tool. It is front-loaded with the core function and avoids filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with two parameters, no output schema, and only generic annotations, the description plus schema gives an agent everything needed to select and invoke it correctly: what it does, why it exists, how to sequence it in a test flow, what side effects to expect, and how to combine it with permission handling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already has 100% description coverage with clear explanations for both `paths` and `device`, so the baseline is 3. The description does not add parameter-level semantics beyond the schema; it provides useful workflow context, but the schema itself carries the parameter documentation burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and noun: 'Put photos or videos into the simulator's photo library.' This clearly distinguishes it from sibling tools like screenshot, install, or launch, none of which address media seeding. It also gives the motivating problem ('A simulator has no camera'), so an agent understands exactly what unique gap this tool fills.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description is explicit about when and how to use the tool: seed the library first, then drive the app's picker as normal. It states the consequence of not using it ('every flow that starts with an image is untestable here') and even gives complementary guidance by pairing it with `permission` on ios_simulator_set_environment to skip the access prompt.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_diagnosticsiOS Simulator: DiagnosticsARead-only
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.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description adds meaningful behavioral context: it reports 'both lanes separately', 'never fail[s]', and can detect a second runner by identifying which simulator owns the WDA port. This gives the agent useful expectations about reliability and output structure without contradicting the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but efficient, front-loading the core behavior ('Report both lanes separately and never fail') before enumerating the diagnostic contents. The later clauses about catching a second runner are slightly wordy but still earn their place by clarifying a key diagnostic use case.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by enumerating the major output categories: existing/usable simulators, the server-selected simulator, screen geometry, and WDA port ownership. This is enough for an agent to know what to expect, though exact output formatting remains unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides full coverage for the optional 'device' parameter, including guidance on omitting it and the distinction from simctl's 'booted'. The tool description itself adds no parameter-specific detail, so the high schema coverage establishes the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action ('Report') and a concrete diagnostic resource: simulator existence/usability, server-chosen simulator, screen geometry, and WDA status with port ownership. This distinguishes it from sibling tools like ios_simulator_list or ios_simulator_restart_wda by emphasizing an aggregated diagnostic report.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Start here when anything else misbehaves' provides explicit situational guidance for when to invoke this tool. It does not spell out exclusions or contrast itself against specific sibling tools, but the context is clear enough for an agent to select it as a first-line diagnostic.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_eraseiOS Simulator: EraseADestructive
Wipe a simulator back to a factory state: installed apps, their data, the keychain and every granted permission. Irreversible, hence confirm; ios_simulator_uninstall is the narrower way to a first launch of one app. A booted simulator is shut down first and booted again afterwards, because simctl refuses to erase a running one.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| confirm | Yes | Must be true. Explicit acknowledgement that this changes state on a real simulator. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and readOnlyHint=false, but the description goes further by naming precisely what is destroyed (apps, data, keychain, permissions), that it is irreversible, and a non-obvious side effect: a booted simulator is shut down then re-booted because simctl refuses to erase a running one. That is real behavioral context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, zero filler, front-loaded with the destructive scope before the alternative and the mechanical side effect. Every clause carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, two-parameter tool with no output schema, the definition is complete: safety profile (via annotations plus the description), scope of destruction, reversibility, sibling routing, and the shutdown/reboot side effect are all covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns an upgrade by explaining the rationale for `confirm` ('Irreversible, hence confirm') rather than just restating it. It does not add anything about `device` beyond the schema, which already documents UDID/name omission and the never-picks-arbitrarily guarantee.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Wipe... back to a factory state') and enumerates exactly what is destroyed: installed apps, their data, the keychain and every granted permission. It explicitly separates itself from ios_simulator_uninstall, so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the sibling alternative and the condition that selects it: use uninstall when the goal is merely 'a first launch of one app' rather than a full reset. The irreversibility note plus the required `confirm` also tells the agent this is a last-resort operation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_get_crash_logiOS Simulator: Get Crash LogARead-only
Read one simulator crash report and return what matters in it: the exception, why the process was terminated, any application-specific message, and the faulting thread's top frames with library names resolved. The full report's path is returned too; it is often tens of kilobytes, so read it only when the summary is not enough. A Swift fatalError's message may not be in the report at all — on a simulator it goes to the app's stderr.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The report's `name` from ios_simulator_list_crash_logs, e.g. "Canopy-2026-10-08-101500.ips" or "Retired/Canopy-2026-10-02-213409.ips". Older reports move under Retired/, so a name that worked yesterday may need listing again. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds rich context beyond the readOnlyHint annotation: report size (tens of kilobytes), the fact that a Swift fatalError message may be absent from the report and instead appear on the app's stderr, and the summary-vs-full-report tradeoff. These are non-obvious behavioral traits an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: what is returned, the cost/benefit of fetching the full file, and the fatalError caveat. Front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with no output schema, the description covers what the summary contains, the tradeoff of the full report, and a significant real-world caveat about missing fatalError messages. No output schema exists, so the description appropriately explains what is returned.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema's `name` description already documents the filename pattern, Retired/ subfolder behavior, and where to get the name from list_crash_logs. The description adds no parameter detail beyond the schema, so a baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read one simulator crash report') and enumerates what it returns: exception, termination reason, app message, top frames with resolved libraries. This clearly distinguishes it from the sibling ios_simulator_list_crash_logs, which only lists.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Tells the agent to read the full .ips path only when the summary is 'not enough', implying the summary is the default. It does not name list_crash_logs as the required prerequisite for obtaining the name, though the schema's description of `name` effectively routes the agent there.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_installiOS Simulator: InstallAIdempotent
Install a build. The path must be a .app bundle directory built for the simulator — not an .ipa, and not a device build, both of which fail with a bare "No such file or directory" that reads like a typo. Installing over an existing copy replaces it and keeps its data.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to the .app bundle, e.g. ~/Library/Developer/Xcode/DerivedData/…/Build/Products/Debug-iphonesimulator/Foo.app | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses the important overwrite behavior: installing over an existing copy replaces it and keeps its data. It also explains the misleading 'No such file or directory' failure mode for invalid builds, which is exactly the kind of context an agent needs to interpret errors correctly. This adds real value beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences deliver the core instruction, the key input constraint, the failure mode, and the overwrite behavior with no filler. The most important constraint is front-loaded, and every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter install operation with no output schema, the description covers the required input shape, the common failure cases, and the side effect of reinstalling. Device-selection details are already fully specified in the schema, so nothing necessary for a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents both the .app path format and the device-selection rules, so the baseline is 3. The description adds meaning by explaining that .ipa and device builds fail with a confusing error, which sharpens the agent's understanding of the path parameter beyond the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with the specific action 'Install a build' and precisely identifies the target resource as a simulator-built .app bundle. It also clearly separates this from invalid inputs like .ipa and device builds, making the tool's purpose easy to distinguish from sibling tools such as ios_simulator_launch.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The primary use case is explicit: install a simulator build from a .app bundle. It also gives strong negative guidance by warning that .ipa files and device builds fail. It does not explicitly name an alternative tool for launching or listing apps, but the install operation itself is unambiguous enough that no direct sibling comparison is required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_launchiOS Simulator: LaunchA
Launch an installed app. Pass arguments to put it into a fixture or demo mode — that is what IOS_SIMULATOR_LAUNCH_ARGS sets as the default for every launch that does not override it. Standard output and error are captured to files under the output directory, so an app that dies on launch leaves something readable behind. Pass capture_logs: true to also get its Logger/os_log output, in one file read with ios_simulator_read_logs.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| arguments | No | Launch arguments, e.g. ["-DemoMode", "YES"]. Overrides IOS_SIMULATOR_LAUNCH_ARGS rather than adding to it. | |
| bundle_id | Yes | The app's bundle identifier, e.g. "io.mgcrea.Canopy". List them with ios_simulator_list_apps. | |
| capture_logs | No | Write stdout, stderr and every Logger/os_log message to one fresh file, for ios_simulator_read_logs. Sets OS_ACTIVITY_DT_MODE=YES in the app's environment, which is what Xcode sets to mirror unified logging onto stderr; without it an app's Logger output reaches no file at all. | |
| terminate_first | No | Replace a running copy rather than attaching to it. On by default so a launch means a fresh process and a predictable first screen. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and destructiveHint=false, so the write-and-safe profile is covered. The description adds meaningful context beyond annotations: stdout/stderr captured to files, terminate_first default behavior, OS_ACTIVITY_DT_MODE env var, and the IOS_SIMULATOR_ID/LAUNCH_ARGS environment defaults. This is richer than annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, front-loaded with the core action ('Launch an installed app'). Each sentence delivers distinct information (env defaults, log capture, capture_logs semantics). Slight density with env-var references but no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a launch tool with no output schema, the description covers what is needed: how to pass args, where logs go, how to read them (pointing to ios_simulator_read_logs), and terminate_first behavior. Missing explicit mention of app-not-installed failure mode, but core operational knowledge is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description reinforces and contextualizes key parameters — arguments behavior (overrides env default), capture_logs purpose (Logger output to file), and the output directory context — adding narrative that links parameters to the operation's side effects.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Launch an installed app'), which is immediately distinguishable from siblings like ios_simulator_install and ios_simulator_terminate. It doesn't explicitly name the closest alternative (ios_simulator_terminate or ios_simulator_restart_wda), but the action is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains how to use key features (arguments for fixture mode, capture_logs for logging) but never states when to use this tool versus ios_simulator_terminate, ios_simulator_restart_wda, or ios_simulator_open_url. Usage is implied through the feature descriptions rather than explicit routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_listiOS Simulator: ListARead-only
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 include_unavailable brings them back with available: false and the reason, so "why can't I use that one" is still answerable here.
| Name | Required | Description | Default |
|---|---|---|---|
| booted_only | No | Only simulators that are currently running. | |
| name_contains | No | Case-insensitive substring filter on the name, e.g. "iPhone 17". | |
| include_unavailable | No | Also list simulators whose runtime is not installed. Off by default because they are not usable for anything; turn it on to see why a specific one is missing. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses substantial behavior: unavailable simulators are filtered out, the result reports how many were omitted and how to delete them, and include_unavailable reveals them with available: false and the reason. This is rich, non-obvious behavior that an agent needs to know.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in the first sentence. The subsequent illustrative detail about typical simulators is useful context but slightly extended; it earns its place by justifying the default filtering, yet could be trimmed without losing essential guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite lacking an output schema, the description covers the essential return values: UDID, available flag, reason, and count of excluded simulators. It also explains the default filtering and how to opt into seeing unavailable ones, making the tool self-sufficient for an agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds extra meaning for include_unavailable, explaining the returned available: false flag and the reason, which goes beyond the schema. booted_only and name_contains are already well documented in the schema, so no further elaboration is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool 'List the simulators on this machine' and highlights the key output, the UDID, which every other tool consumes. This distinguishes it from sibling tools like ios_simulator_list_apps, which lists apps rather than simulators.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: it shows usable simulators by default, and explains when to use include_unavailable to understand why a simulator is missing. It implies this is the tool to obtain a UDID for other tools, though it does not explicitly name alternatives or state 'use this before X'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_list_appsiOS Simulator: List AppsARead-only
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 dataContainer — an ordinary path on this Mac, so an app's database or logs can be read directly with no copy step.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| include_all | No | Include Apple's built-in apps as well. Off by default; the list is long. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses meaningful behavior: results are filtered to the user's own apps by default, stock simulators contain about thirty apps, and each entry exposes a real filesystem path in dataContainer that enables direct reads. This is rich, non-obvious context that helps an agent trust and interpret the result.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with no filler: the main purpose is front-loaded, followed by high-value behavioral details and a practical note about dataContainer. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only listing tool with two optional parameters and no output schema, the description plus schema fully cover how to invoke it, what the output will contain, and how to use the returned values. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents both parameters fully, including the device ambiguity rule and include_all default, so the description does not need to add parameter-level detail. The description's 'Defaults to your own apps' reinforces include_all but adds little beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action and resource: 'List the apps installed on a simulator', and immediately adds the key value proposition that it returns the bundle id used by other tools. This clearly separates it from sibling tools like ios_simulator_list and ios_simulator_ui_tree.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives practical context for when to use the tool: to obtain bundle ids that other tools consume, and it explains the default filtering behavior. It does not explicitly name an alternative or state a when-not-to-use condition, but the purpose is so distinct that the omission is minor.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_list_crash_logsiOS Simulator: List Crash LogsARead-only
List crash reports from simulator processes, newest first. A simulator app's crash is written by this Mac into ~/Library/Logs/DiagnosticReports alongside the Mac's own crashes; this keeps only the simulators' and says which simulator each came from. Most of them are the simulators' own system daemons, so pass process to find your app's. Read one with ios_simulator_get_crash_log. Nothing needs to be booted.
| Name | Required | Description | Default |
|---|---|---|---|
| kinds | No | Report kinds to include, e.g. ["crash"]. Defaults to ["crash", "jetsam", "user_fault"]; kinds without a name come back as "bug_type_<n>". Pass ["all"] for everything. | |
| limit | No | Maximum reports to return, newest first (1-200). Defaults to 20. | |
| device | No | Only reports from this simulator, by UDID or name as shown by ios_simulator_list. Omit for every simulator's — unlike the other tools, this does not default to the booted one, since a crash often outlives the boot it happened in. | |
| process | No | Case-insensitive substring of the process name or bundle id, e.g. "Canopy" or "io.mgcrea". The process name is the app's executable name, usually but not always its display name. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover readOnlyHint, so the description carries real behavioral weight: it explains where reports physically live (~/Library/Logs/DiagnosticReports), that output is filtered to simulators only and labeled by simulator, and that no boot is required. It also flags the non-obvious defaulting difference (device does not default to booted) — genuinely useful context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then layered with the most decision-relevant facts in a compact sequence. Every sentence earns its place; no filler or restatement of the name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with no output schema, the definition supplies the location of the data, the filtering semantics, the follow-up tool, and the boot precondition — everything an agent needs to call it correctly and interpret the results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all four parameters, and the description mainly echoes `process`. However it adds interpretive value the schema lacks — that most results are system daemons, so `process` is the practical filter for finding your own app's crash.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List crash reports from simulator processes'), immediately scoping to simulators and ordering 'newest first'. It clearly distinguishes itself from the sibling ios_simulator_get_crash_log, which it names for reading individual reports.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete selection guidance ('pass `process` to find your app's') and routes the agent to the right sibling for the follow-up action. It also states an important precondition contrast ('Nothing needs to be booted'), though it does not explicitly exclude versus sibling listers like ios_simulator_read_logs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_open_urliOS 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 https:// link opens in Safari unless the app claims it; a custom scheme goes straight to whichever app registered it.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | e.g. "myapp://garden/42" or "https://example.com/garden/42". | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are neutral (no readOnly/destructive hints), so the description carries the behavioral burden. It discloses non-obvious routing behavior for https vs custom schemes, which is valuable context beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences: the first front-loads the purpose, the second adds a key behavioral detail. No filler or repetition of schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with no output schema, the description plus detailed parameter schema covers purpose, usage context, scheme behavior, and device selection. Nothing needed for a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds extra meaning by explaining how the URL's scheme affects behavior, helping an agent choose an appropriate value beyond the schema's examples.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the exact action ('Open a URL on the simulator') and the purpose ('exercise a deep link or a universal link'), immediately distinguishing it from tap-based sibling tools. The additional scheme-routing details further clarify what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a clear use case: when you need to exercise a deep/universal link without tapping one. It implies this tool overrides manual tapping but does not explicitly name alternatives or exclusions, so it misses a fully explicit routing statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_poweriOS Simulator: PowerAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| state | Yes | The state to put it in. `booted` also waits for it to actually get there. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| wait_ms | No | How long to wait for a boot to complete before reporting what it saw. | |
| open_window | No | Bring up a window on the device — Simulator.app, or DeviceHub on Xcode 27 — so the screen is visible. A `boot` on its own is headless, which is fine for an agent and confusing for a person watching. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare idempotentHint=true and readOnlyHint=false, but the description adds real behavioral context the annotations cannot: a cold boot takes tens of seconds, puts a window on the user's screen, and shifts which simulator an unqualified call resolves to. Idempotency is restated with concrete detail (booting a booted simulator succeeds), which reinforces rather than merely repeats the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core action and each clause carrying distinct information (latency, user-visible side effect, resolution side effect, idempotency). The em-dash construction makes it slightly dense but nothing reads as filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With four fully documented parameters, idempotency annotations, and no output schema, the description covers the operationally risky facts an agent needs: latency, window visibility, and post-boot resolution changes. Only minor gaps remain around failure/timeout behavior, which is partly addressed by wait_ms in the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds one genuinely non-schema nuance — that the boot changes what an unqualified call resolves to — but it does not describe the `state`, `wait_ms`, or `open_window` parameters, leaving the schema to carry that load.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb pair and resource: 'Boot or shut down a simulator.' This is immediately distinguishable from siblings like ios_simulator_erase, ios_simulator_install, and ios_simulator_launch, which mutate content rather than power state.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains when this tool is mandatory ('Booting is the one thing this server will not do for you implicitly'), which tells the agent it must call this before other tools can work on a fresh device. It does not explicitly name alternatives or state when-not-to-use beyond idempotency, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_press_buttoniOS Simulator: Press ButtonA
Press a hardware button. home is the way back to the home screen and the reliable way to background the app under test without terminating it.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Which button. `home` works on Face ID devices too — it is the gesture, not the physical button. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| settle_ms | No | Milliseconds to wait before the follow-up screenshot, so an animation finishes first. Raise it for a screen that loads data; a capture taken mid-transition shows neither state. This is a pause for an animation, not a wait for work to finish — which is why it stops at ten seconds. For anything longer, use ios_simulator_wait_for_element. | |
| screenshot | No | Return a screenshot of the resulting screen. On by default, and worth leaving on: it is how you find out that the action landed where you meant it to. Turn it off only for a sequence whose intermediate states you do not need to see. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnly/idempotent/destructive hints; the description adds the key behavioral consequence that home backgrounds the app without terminating it, and the schema notes that home is a gesture on Face ID devices. It does not contradict the annotations and gives useful behavioral context beyond the structured hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences with the verb and resource front-loaded and the most useful guidance in the second sentence. There is no filler or repetition of what the schema already states.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich per-parameter descriptions, the annotations, and the simplicity of the action, an agent has enough to select and invoke the tool correctly. The lack of an output schema is mitigated by the screenshot parameter explicitly describing the returned screenshot behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3; the tool description adds value by explaining what the `home` parameter accomplishes (returning home/backgrounding without termination). The remaining parameters are already richly described in the schema, including device-selection behavior and settle_ms semantics, so the overall parameter guidance is strong.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete action ('Press a hardware button') and immediately explains the purpose of the only supported button: returning to the home screen and backgrounding the app without terminating it. This clearly differentiates it from terminate, launch, screenshot, and other simulator actions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear when-to-use context: use home to go back to the home screen or to background the app safely without terminating it. The settle_ms parameter description further routes longer waits to ios_simulator_wait_for_element, but the prose does not enumerate exclusions for every sibling, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_pushiOS 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 aps key. Only remote pushes are simulated — not VoIP, complications or file-provider. The app must be installed; it does not have to be running.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| payload | Yes | The APNs payload, e.g. {"aps":{"alert":{"title":"Watering due","body":"Monstera"},"sound":"default","badge":1}}. Max 4096 bytes. | |
| bundle_id | Yes | The app's bundle identifier, e.g. "io.mgcrea.Canopy". List them with ios_simulator_list_apps. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only provide readOnly/idempotent/destructive hints, so the description carries most of the burden. It discloses the simulated nature, the payload requirement to contain an 'aps' key, and the fact that the app need not be running. It stops short of describing the visible result or any permission behavior, but the core behavior is clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences with no filler. Each clause adds a necessary constraint or limitation, and the most important scoping information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter action with a nested payload and no output schema, the description plus schema gives the agent everything needed to invoke it correctly: device selection behavior, payload format and size, bundle id pattern, and push-type restrictions. No critical selection or invocation information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds semantic value beyond the schema: it requires the payload to be a 'normal remote-notification body' containing an 'aps' key. The schema already covers device selection rules, the payload example, byte limit, and bundle id pattern.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with a specific verb and resource: 'Deliver a push notification' to the iOS simulator. It immediately distinguishes this tool from real APNs delivery by adding 'with no APNs certificate and no server,' and no sibling tool performs push, so there is no ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear context for use: simulator push testing without needing APNs infrastructure. It also states explicit exclusions ('not VoIP, complications or file-provider') and prerequisites ('The app must be installed; it does not have to be running'), though it does not name alternative tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_read_logsiOS Simulator: Read LogsARead-only
Read an app's log output: stdout, stderr and every Logger/os_log message the process emits, interleaved in one file. Only available for an app started with ios_simulator_launch capture_logs: true. Returns the newest limit lines plus a next cursor; pass it back to get only what arrived since, which is how to see what one tap logged. capturing turns false once the app's process has exited, and what it wrote stays readable. A crash's backtrace is not in here — see ios_simulator_list_crash_logs — but its fatalError message is.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Most lines to return; the newest are kept and the rest counted in `omitted`. Defaults to 200 — filter rather than raising this. | |
| cursor | No | The `next` value from the previous read, to get only newer lines. Omit to read from the start of the capture. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| filter | No | Case-insensitive regular expression a line must match, e.g. "error|fail" or "\[Sync\]". Applied before `limit`, so it finds matches across the whole range. | |
| bundle_id | No | Which app's capture, e.g. "io.mgcrea.Canopy". Defaults to the most recent capture. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only assert readOnlyHint=true, but the description discloses the capture lifecycle ('capturing turns false once the app's process has exited, and what it wrote stays readable') and the crash-content boundary (backtrace excluded, fatalError included). This is substantial behavioral context beyond the safety profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core capability, then preconditions, then return contract, then boundaries. Every sentence carries distinct information — the crash-log routing and the capture-persistence note are not padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return contract itself: newest `limit` lines plus a `next` cursor. Combined with the precondition and the crash-log boundary, an agent has everything needed to call and interpret this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds integration semantics: the cursor is described in terms of the incremental workflow, filter is noted effectively in the 'see what one tap logged' framing, and the device-omission rule is reinforced. It stops short of restating every field, which is appropriate given the schema already covers them.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read an app's log output') and enumerates exactly what is captured: stdout, stderr, and Logger/os_log messages interleaved. It also distinguishes itself from the sibling ios_simulator_list_crash_logs, so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition ('Only available for an app started with ios_simulator_launch capture_logs: true'), names the crash-log tool as the alternative for backtraces, and explains the incremental-read pattern ('pass it back to get only what arrived since'). When-to-use, when-not-to-use, and the alternative are all covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_restart_wdaiOS Simulator: Restart WebDriverAgentA
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.
| Name | Required | Description | Default |
|---|---|---|---|
| port | No | Port to bind, passed to the runner as USE_PORT. Defaults to IOS_SIMULATOR_WDA_PORT. Two simulators need two ports: they share this Mac's loopback, and a runner with no USE_PORT scans 8100-8199 and silently takes the next free one. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses key behavioral traits: the runner is started detached, it outlives the conversation, output goes to a log file, and it does not wait. This is exactly the kind of context an agent needs to use the tool correctly and verify success.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, each earning its place: purpose, scope, runtime behavior, and verification step. The description is front-loaded with the core function and avoids fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a side-effecting tool with no output schema, the description covers what the tool does, when to use it, what side effects to expect, how long to wait, and where to check results. That is sufficient for an agent to invoke and verify it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool description itself does not add parameter-level meaning, but the input schema provides 100% coverage with detailed descriptions for both `port` and `device`. Baseline 3 is appropriate because the schema already carries the semantic weight.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: 'Start the WebDriverAgent runner, or restart it after it has died.' It clearly differentiates from siblings by stating that only UI tree and input tools need it, while screenshots and simctl operations do not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says when this tool is needed and when it is not: 'Only the UI tree and the input tools need it.' It also gives the follow-up action ('check ios_simulator_diagnostics') and a timing expectation, which is strong practical guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_screenshotiOS Simulator: ScreenshotARead-only
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 coordinateSpace: "points" when that holds. Pair it with ios_simulator_ui_tree rather than choosing between them: the image shows you what the screen looks like, the tree gives you exact labels and identifiers. Re-screenshot after every action rather than chaining blind taps.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| quality | No | JPEG quality 1-100. Flat interface screenshots stay perfectly legible at 70. | |
| save_path | No | Also write the full-resolution PNG to this absolute path, for attaching to a bug report. The returned image is still the downscaled one. | |
| max_dimension | No | Longest side of the returned image, in pixels. Leave it unset unless you have a reason: the default matches the device's point size, and any other value makes image positions stop being tap coordinates (the result then reports `coordinateSpace: "image_pixels"` and the `pointsPerPixel` factor to multiply by). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses the key behavioral traits: default scaling to device point size, the resulting coordinateSpace metadata ('points'), the shift to image_pixels when max_dimension is overridden, and the fact that save_path writes a full-resolution PNG while 'the returned image is still the downscaled one.' This is exactly the kind of non-obvious behavior an agent needs to interpret results correctly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, each earning its place: core purpose, the critical coordinate-space behavior, sibling complementarity, and workflow rule. The most decision-relevant fact (tap-coordinate compatibility) is front-loaded in sentence two. No filler, no repetition of schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description conveys the return semantics that matter (image plus coordinateSpace metadata), and the schema handles the four optional parameters exhaustively. The readOnly annotation covers the safety profile. Nothing an agent needs to invoke this correctly — coordinate systems, sibling relationships, workflow cadence, parameter trade-offs — is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3 — and indeed the schema's per-parameter descriptions are rich on their own. The main description adds one genuinely additive semantic: the default scaling means 'a position read off this image can be passed straight to ios_simulator_tap with no conversion,' which gives the default parameter behavior a concrete cross-tool consequence not stated in the schema. This nudges it above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource — 'Capture the screen and return it as an image' — and immediately distinguishes itself from the closest sibling, ios_simulator_ui_tree: 'the image shows you what the screen looks like, the tree gives you exact labels and identifiers.' An agent can tell exactly what this tool does and how it differs from alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit pairing guidance: 'Pair it with ios_simulator_ui_tree rather than choosing between them,' complete with the reason for each tool's role. It also prescribes a workflow rule ('Re-screenshot after every action rather than chaining blind taps') and the device parameter description further advises when to omit it. This is actionable usage direction, not just a vague context hint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_set_environmentiOS Simulator: Set EnvironmentAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| location | No | Teleport the device, for location-gated screens. | |
| appearance | No | Interface style. | |
| permission | No | Set an app permission directly. This is how you reach the denied branch of a permission check, which is otherwise a prompt nobody can tap. | |
| status_bar | No | Freeze the status bar. Overrides persist until cleared. | |
| content_size | No | Dynamic Type size. The accessibility- sizes are where layouts break. | |
| clear_location | No | Stop simulating a location. | |
| clear_status_bar | No | Drop every status bar override, restoring the real one. | |
| increase_contrast | No | Increase Contrast accessibility mode. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already marking the tool as non-read-only, idempotent, and non-destructive, the description adds important behavioral context beyond the annotations: fields are applied in order, the result reports the resulting state, and status bar overrides persist across reboots and can pollute later screenshots if not cleared. This is genuinely useful operational warning.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded. The first sentence states purpose and lists capabilities; the second justifies simulator preference; the third explains optionality and ordering; the fourth warns about persistence. Each sentence earns its place without redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 9-parameter tool with no output schema, the description covers the essential invocation semantics: optional fields, application order, state reporting, and the key persistence caveat. It doesn't detail what 'reports the state afterwards' includes, but given the strong schema coverage, this is complete enough for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds value by summarizing the parameter groups and by stating two cross-cutting facts not in the schema: every field is optional, and provided fields are applied in order. This helps an agent understand interactions between parameters like clear_location and location.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pair: 'Stage the simulator before a screenshot or a test' and then enumerates the exact capabilities (dark mode, Dynamic Type, increased contrast, frozen status bar, simulated location, app permissions). This clearly distinguishes it from sibling tools like screenshot, tap, or launch, which do different jobs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear usage context: use this tool to prepare state before screenshots or tests. It also explains why simulator-only features matter for UI work. It does not explicitly name alternatives or exclusion conditions, but no sibling tool offers equivalent functionality, so the guidance is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_swipeiOS 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. duration_ms is what separates a scroll from a fling: a short one throws the list past where you aimed.
| Name | Required | Description | Default |
|---|---|---|---|
| to_x | Yes | Horizontal position in points, from the left edge. This is the same space as the `tap` field from ios_simulator_ui_tree and as a default ios_simulator_screenshot image — no conversion. | |
| to_y | Yes | Vertical position in points, from the top edge. Same space as ios_simulator_ui_tree `tap` and a default ios_simulator_screenshot image. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| from_x | Yes | Horizontal position in points, from the left edge. This is the same space as the `tap` field from ios_simulator_ui_tree and as a default ios_simulator_screenshot image — no conversion. | |
| from_y | Yes | Vertical position in points, from the top edge. Same space as ios_simulator_ui_tree `tap` and a default ios_simulator_screenshot image. | |
| settle_ms | No | Milliseconds to wait before the follow-up screenshot, so an animation finishes first. Raise it for a screen that loads data; a capture taken mid-transition shows neither state. This is a pause for an animation, not a wait for work to finish — which is why it stops at ten seconds. For anything longer, use ios_simulator_wait_for_element. | |
| screenshot | No | Return a screenshot of the resulting screen. On by default, and worth leaving on: it is how you find out that the action landed where you meant it to. Turn it off only for a sequence whose intermediate states you do not need to see. | |
| duration_ms | No | How long the drag takes. 400 is a controlled scroll; under 150 becomes a fling with momentum, which lands somewhere you did not choose. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the minimal annotations, the description discloses that duration_ms distinguishes a controlled scroll from a momentum fling, and that short drags 'throw the list past where you aimed.' This adds meaningful behavioral context. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: the core action, the practical direction mapping, and the duration behavior. The most important conceptual guidance is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description, combined with the richly documented 100% schema coverage, gives an agent everything needed to invoke the tool correctly. No output schema exists, but returning a screenshot is handled by the screenshot parameter, which is already documented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value by explaining the direction-to-screen relationship and the semantic difference between scroll and fling via duration_ms, which enriches the raw parameter meanings.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a concrete action and object: 'Drag from one point to another, in points.' It then names real user goals — scroll a list, pull to refresh, swipe a row open — which clearly separates it from sibling tap and type tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit guidance for when to use the gesture, including how to scroll down and what duration produces a fling. It does not explicitly name alternatives or state when not to use it, but the use cases are clear enough for an agent to select it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_tapiOS 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 tap field in ios_simulator_ui_tree, which are the same space.
| Name | Required | Description | Default |
|---|---|---|---|
| x | Yes | Horizontal position in points, from the left edge. This is the same space as the `tap` field from ios_simulator_ui_tree and as a default ios_simulator_screenshot image — no conversion. | |
| y | Yes | Vertical position in points, from the top edge. Same space as ios_simulator_ui_tree `tap` and a default ios_simulator_screenshot image. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| hold_ms | No | How long to hold the touch, in milliseconds. Around 700 makes it a long press, which is what opens context menus and edit affordances. | |
| settle_ms | No | Milliseconds to wait before the follow-up screenshot, so an animation finishes first. Raise it for a screen that loads data; a capture taken mid-transition shows neither state. This is a pause for an animation, not a wait for work to finish — which is why it stops at ten seconds. For anything longer, use ios_simulator_wait_for_element. | |
| screenshot | No | Return a screenshot of the resulting screen. On by default, and worth leaving on: it is how you find out that the action landed where you meant it to. Turn it off only for a sequence whose intermediate states you do not need to see. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only carry readOnly/destructive/idempotent hints, all false, so they don't reveal failure modes. The description adds meaningful behavioral context: coordinate taps silently break after layout changes and 'nothing about a wrong tap looks wrong.' This is the kind of behavioral warning that helps an agent decide between coordinate and element taps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences each carry distinct value: what the tool does, when not to use it, and how coordinates are sourced. The warning is front-loaded right after the purpose, before any lower-priority detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description plus fully documented input schema give an agent everything needed to select and invoke the tool correctly: purpose, coordinate space, failure mode, and parameter semantics. It stops short of explicitly describing the return value beyond the screenshot parameter, but the schema already covers that detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema covers 100% of parameters with detailed descriptions, including units, defaults, and distinctions like 'pause for animation, not wait for work.' The description reinforces the coordinate-space relationship, but does not need to compensate for schema gaps because none exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and object — 'Tap a position on screen, in points' — and immediately differentiates itself from ios_simulator_tap_element by naming the condition under which the element-based sibling should be preferred. The coordinate-source sentence also anchors exactly what the tool acts on.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing guidance: prefer ios_simulator_tap_element when the target has a label or accessibility identifier, with a concrete reason (layout shifts make coordinates stale). It also tells the agent where coordinates come from — default screenshot or ui_tree tap field — closing the main usage ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_tap_elementiOS 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 id, label or predicate; identifiers from ios_simulator_ui_tree.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Accessibility identifier — the `id` field from ios_simulator_ui_tree, e.g. "garden.tab". The most durable way to address an element, because it is set in code and does not change when the visible text does. | |
| index | No | Which match to tap when several match, zero-based, counted in the order ios_simulator_ui_tree lists them. Giving it turns off the control preference `label` normally applies, because it means you have read the tree and are counting real positions in it. Leave it off unless that is what you are doing. | |
| label | No | Exact accessibility label, i.e. the visible text — e.g. "Today". Matched exactly, and it changes with the app's language, so prefer `id` where one exists. A label is shared by a control and every container around it, so this matches controls first and falls back to the rest only when no control carries it. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| predicate | No | Escape hatch: a raw NSPredicate over element attributes, e.g. `type == "XCUIElementTypeButton" AND label BEGINSWITH "Add"`. | |
| settle_ms | No | Milliseconds to wait before the follow-up screenshot, so an animation finishes first. Raise it for a screen that loads data; a capture taken mid-transition shows neither state. This is a pause for an animation, not a wait for work to finish — which is why it stops at ten seconds. For anything longer, use ios_simulator_wait_for_element. | |
| screenshot | No | Return a screenshot of the resulting screen. On by default, and worth leaving on: it is how you find out that the action landed where you meant it to. Turn it off only for a sequence whose intermediate states you do not need to see. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It discloses useful behavioral traits beyond annotations: the device resolves the element's position, and the approach is robust to scrolling, layout changes, and reworded copy. Annotations only cover read-only/idempotent/destructive hints, so this extra context genuinely helps an agent predict behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with no filler: the core action comes first, followed by the rationale and the essential param rule. The 'identifiers from ios_simulator_ui_tree' note is compact and useful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter action tool with no output schema, the description covers the main decisions an agent must make: which selector to use, where identifiers come from, and how this differs from coordinates. The screenshot parameter description already clarifies the output expectation, though the description itself could have mentioned what happens on no-match or multiple-match cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents all 7 parameters thoroughly, so this dimension starts near baseline. The description adds a key semantic constraint not enforced by the schema: exactly one of id, label, or predicate must be provided, and it points to ios_simulator_ui_tree as the source of identifiers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and object: tap an element by accessibility identifier or label. It also contrasts itself with coordinate-based interaction, signaling clearly that this is the element-aware counterpart to ios_simulator_tap.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly frames this as 'the tool to reach for' when the element may move or the text may change, and explains why it beats coordinate-based taps. It does not name ios_simulator_tap or list exclusions, but the usage context is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_terminateiOS Simulator: TerminateAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| bundle_id | Yes | The app's bundle identifier, e.g. "io.mgcrea.Canopy". List them with ios_simulator_list_apps. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide idempotentHint=true and destructiveHint=false, and the description adds meaningful context: the app is not uninstalled, its data remains intact, and the result is a cold start. This goes beyond the structured hints without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence with no filler. It front-loads the core action, then immediately states the key behavioral nuance (no uninstall, data untouched) and the practical purpose (cold start).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter kill operation, the description plus schema and annotations cover what an agent needs: required bundle_id, optional device selection guidance, non-destructive behavior, idempotency, and the use case. No out-of-schema return format is necessary for a command like this.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents both parameters fully, so the baseline is 3. The description adds value for the optional device parameter by explaining when to omit it, how IOS_SIMULATOR_ID applies, and that it avoids simctl's arbitrary selection behavior, which helps an agent pick the right value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Kill a running app') and a clear resource, and goes beyond a simple restatement of the title by explaining what it does not do: it does not uninstall the app and does not touch its data. This distinguishes it from destroy/erase-style operations, and 'back to a cold start without erasing anything' sharpens the intended effect.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear context for use: when you want a cold start without erasing app data. It implicitly contrasts with uninstall/erase operations, though it does not explicitly name an alternative sibling tool or say when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_typeiOS 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 id or label to have the field tapped first unless you know a field is already active.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Accessibility identifier of the field to focus first — from ios_simulator_ui_tree. | |
| text | Yes | The text to type. Sent character by character, as a real keyboard would. | |
| label | No | Exact label of the field to focus first, if it has no identifier. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| settle_ms | No | Milliseconds to wait before the follow-up screenshot, so an animation finishes first. Raise it for a screen that loads data; a capture taken mid-transition shows neither state. This is a pause for an animation, not a wait for work to finish — which is why it stops at ten seconds. For anything longer, use ios_simulator_wait_for_element. | |
| screenshot | No | Return a screenshot of the resulting screen. On by default, and worth leaving on: it is how you find out that the action landed where you meant it to. Turn it off only for a sequence whose intermediate states you do not need to see. | |
| clear_first | No | Replace the field's contents instead of appending. Only possible when `id` or `label` names the field — there is no way to clear a field addressed only by focus. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses the important silent-success trap: with no focus, keystrokes go nowhere but the call still succeeds. It also explains that id/label trigger a pre-tap. It does not cover what happens if the named field is not found, but the core behavioral risk is clearly exposed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The main description is two tight sentences with the most important caveat (focus trap) front-loaded. Every sentence carries load, and the parameter descriptions handle the remaining detail without bloating the main description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The schema covers all seven parameters, including device selection, screenshot behavior, settle semantics, and clear_first constraints, so an agent has most of what it needs. Missing top-level detail about return shape and invalid-identifier behavior is a minor gap given no output schema, but the overall definition is still quite complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds meaningful cross-parameter semantics by explaining that id/label are how the caller ensures focus, and it ties clear_first to the presence of id/label. This goes beyond the simple field-level descriptions in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: typing text into the current keyboard focus or a named field. It also explains the two ways to target input, which distinguishes it from the tap-oriented siblings and makes the tool's job immediately clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit usage rule: pass id or label to tap the field first unless a field is already active, and warns against relying on focus when nothing is focused. It does not name alternative sibling tools in the main description, though the settle_ms parameter does direct longer waits to ios_simulator_wait_for_element.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_ui_treeiOS Simulator: UI TreeARead-only
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 contains or types to narrow further and detail to widen. A short answer is not proof the screen is bare — check the filtered field, which counts what the filters left out and names the argument that brings it back. Coordinates are in points, the same space ios_simulator_tap takes.
| Name | Required | Description | Default |
|---|---|---|---|
| types | No | Keep only these element types, without the `XCUIElementType` prefix, e.g. ["Button", "Cell"]. | |
| detail | No | How much of the hierarchy to return. `interactive` (default) is controls only — buttons, cells, fields, switches — and is what you want to decide where to tap. `labelled` adds text and images that carry a label, for reading the screen's content. `all` is every visible node and is usually far too large to be useful. | interactive |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| contains | No | Keep only elements whose label, identifier or value contains this, case-insensitively — e.g. "Today". | |
| include_invisible | No | Include elements XCUITest marks as not visible. Off by default, because on a scrolling list they outnumber the visible ones many times over — but the flag is not always truthful: a photo picker and a share sheet report their own contents as invisible while they are on screen and respond to a tap. Turn this on when `filtered.notVisible` says something was left out and the screen plainly has more on it than came back. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description reveals important behavioral traits: results are flattened, the raw hierarchy is tens of KB, defaults return only controls, the `filtered` field counts omissions, and coordinates are in the same point space as ios_simulator_tap. It also warns that `include_invisible` is not always truthful, which is valuable non-obvious behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: purpose, comparison to screenshots, default behavior, filtering guidance, and coordinate-space note are all packed into a compact, front-loaded description with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description explains what elements contain, how filtering affects results, what the `filtered` field means, and how coordinates relate to tapping. For a read-only inspection tool with this parameter richness, the description gives an agent enough context to invoke it correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds practical parameter semantics by explaining how to narrow (`contains`, `types`) and widen (`detail`), and by tying the coordinate output to ios_simulator_tap's input space. This goes beyond merely restating the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List the addressable elements on screen — type, label, accessibility identifier, and the exact point to tap — flattened rather than nested.' It clearly differentiates the tool from screenshot-based inspection by explicitly saying to prefer this over reading coordinates off a screenshot.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance: '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.' It also advises how to narrow or widen results with `contains`, `types`, and `detail`, and warns to check `filtered` before concluding the screen is empty.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_uninstalliOS Simulator: UninstallADestructiveIdempotent
Remove an app from the simulator, with its data container — documents, databases and preferences all go, and nothing brings them back. To get back to a cold start while keeping the data, use ios_simulator_terminate. To test a genuine first launch of one app, this is narrower than ios_simulator_erase, which wipes every app on the simulator. Uninstalling an app that is not installed also succeeds, so success does not prove it was there.
| Name | Required | Description | Default |
|---|---|---|---|
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| confirm | Yes | Must be true. Explicit acknowledgement that the app's data is deleted. | |
| bundle_id | Yes | The app's bundle identifier, e.g. "io.mgcrea.Canopy". List them with ios_simulator_list_apps. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=true, but the description adds substantive context beyond them: what exactly is destroyed (documents, databases, preferences, 'nothing brings them back'), and the non-obvious behavioral quirk that uninstalling a missing app still succeeds, so success is not proof of prior presence. That last detail is a real edge case an agent could otherwise misinterpret.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: destruction scope, cold-start alternative, narrower vs erase, and the success-flag caveat. Front-loaded with the destructive consequence rather than burying it behind pleasantries.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive mutation tool with no output schema, the description supplies the critical missing semantics: what is destroyed, alternatives for different intents, and the false-success edge case. Annotations cover the safety flag, schema covers parameters, and the description covers behavior and routing — nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all three parameters thoroughly (device omitting behavior, confirm must be true, bundle_id pattern and examples). The description adds no parameter syntax beyond the schema. Baseline 3 is correct when the schema fully carries parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (remove an app from the simulator) and immediately differentiates scope ('with its data container', narrower than erase). It explicitly names sibling tools (terminate, erase) with their distinguishing scope, so an agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly provides when-to-use and when-not: 'to get back to a cold start while keeping the data, use ios_simulator_terminate' and 'to test a genuine first launch of one app, this is narrower than ios_simulator_erase, which wipes every app'. This is direct routing to alternatives with conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ios_simulator_wait_for_elementiOS Simulator: Wait For ElementARead-only
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. settle_ms on the action tools is a pause for an animation and caps at ten seconds — it is not a wait, and using it as one is how you end up verifying a server instead of the screen. Give exactly one of id, label or predicate, the same way ios_simulator_tap_element takes them. Your MCP client may have a request timeout of its own, commonly 60 seconds, and it will cut this call off before timeout_ms does — for a longer wait, raise it there too or call this twice.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Accessibility identifier — the `id` field from ios_simulator_ui_tree. | |
| label | No | Exact accessibility label, i.e. the visible text. Matched against controls first, as in ios_simulator_tap_element. | |
| absent | No | Wait for the element to *stop* matching instead of to start. This is how you wait out a spinner, a progress view or a placeholder, which is the same wait from the other side. | |
| device | No | Which simulator: its UDID or its name as shown by ios_simulator_list. Omit it when exactly one is booted — that is the normal case, and IOS_SIMULATOR_ID pins it when it is not. Unlike simctl's own `booted`, this never picks arbitrarily between two. | |
| poll_ms | No | How long to wait between polls. Each poll is one query to the device, so a long wait costs less at 2000 than at 250 and arrives at almost the same moment. | |
| predicate | No | A raw NSPredicate, e.g. `type == "XCUIElementTypeButton" AND label BEGINSWITH "Add"`. | |
| screenshot | No | Return a screenshot of the resulting screen. On by default, and worth leaving on: it is how you find out that the action landed where you meant it to. Turn it off only for a sequence whose intermediate states you do not need to see. | |
| timeout_ms | No | How long to keep polling before giving up. Read the note about your client's own request timeout in this tool's description before setting it above 60000. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already covers the safety profile, and the description earns substantial credit beyond it: the warning that an MCP client's own request timeout "will cut this call off before timeout_ms does," the polling semantics, and the "give exactly one of" constraint. No contradiction with the annotation — polling and observing are inherently non-destructive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with purpose front-loaded in the first clause, and every sentence earns its place: the settle_ms exclusion prevents a common misuse and the client-timeout note is a necessary caveat. It is dense, with the timeout caveat arguably better placed after the parameter rule, but there is no waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter polling tool with no output schema, the description covers purpose, use cases, exclusions, parameter exclusivity, and an external failure mode. The remaining gap is the return contract — nothing states what a timeout or successful wait returns beyond the optional screenshot — but this is minor and largely inferable from the polling semantics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and every parameter carries a rich description, so the baseline is 3. The description adds a genuinely non-derivable constraint — "Give exactly one of id, label or predicate" — and points to ios_simulator_tap_element as the convention reference, which raises it above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource in the opening clause — "Poll until an element appears, or until it goes away" — covering both wait directions immediately. It positions itself as "the tool for a screen that loads" and explicitly contrasts with the settle_ms pause on action tools, so an agent can tell it apart from the tap/action siblings without inspecting schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use context ("a generation step, a network round trip, a long import") alongside an explicit when-not-to: settle_ms "caps at ten seconds — it is not a wait, and using it as one is how you end up verifying a server instead of the screen." It names the alternative pattern it is not, which is the strongest possible routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.3.1- Added
ios_simulator_get_crash_log - Changed
ios_simulator_launch1 field changed- added
Input schema / properties / capture_logsAdded value: +{ + "default": false, + "description": "Write stdout, stderr and every Logger/os_log message to one fresh file, for ios_simulator_read_logs. Sets OS_ACTIVITY_DT_MODE=YES in the app's environment, which is what Xcode sets to mirror unified logging onto stderr; without it an app's Logger output reaches no file at all.", + "type": "boolean" +}
- Added
ios_simulator_list_crash_logs - Added
ios_simulator_read_logs - Added
ios_simulator_uninstall
1 tool update
v0.2.2- Changed
ios_simulator_power1 field changed- changed
Input schema / properties / open_window / descriptionPrevious value: -"Bring up the Simulator app so the screen is visible. A `boot` on its own is headless, which is fine for an agent and confusing for a person watching."New value: +"Bring up a window on the device — Simulator.app, or DeviceHub on Xcode 27 — so the screen is visible. A `boot` on its own is headless, which is fine for an agent and confusing for a person watching."
21 tool updates
v0.2.0- First observed
ios_simulator_add_media - First observed
ios_simulator_diagnostics - First observed
ios_simulator_erase - First observed
ios_simulator_install - First observed
ios_simulator_launch - First observed
ios_simulator_list - First observed
ios_simulator_list_apps - First observed
ios_simulator_open_url - First observed
ios_simulator_power - First observed
ios_simulator_press_button - First observed
ios_simulator_push - First observed
ios_simulator_restart_wda - First observed
ios_simulator_screenshot - First observed
ios_simulator_set_environment - First observed
ios_simulator_swipe - First observed
ios_simulator_tap - First observed
ios_simulator_tap_element - First observed
ios_simulator_terminate - First observed
ios_simulator_type - First observed
ios_simulator_ui_tree - First observed
ios_simulator_wait_for_element
TDQS
Scored across 25 tools
Each tool targets a clearly distinct action, and the descriptions explicitly steer between look-alikes: tap vs tap_element, terminate vs uninstall vs erase, and the three log/crash tools are all distinguished with concrete guidance. Overlaps that could confuse (screenshot vs ui_tree) are addressed directly by telling the agent to pair them rather than choose.
Every tool uses the same ios_simulator_ snake_case prefix with a predictable verb_noun or verb structure (list_apps, launch, terminate, press_button, open_url). No mixed casing or divergent verb styles; the pattern is uniform across all 25 tools.
At 25 tools it sits at the heavy end, but the domain genuinely spans device lifecycle, app lifecycle, UI interaction, log reading, media, push, and WDA management, so the count is earned rather than padded. Each tool maps to a real capability with no redundancy.
Coverage is broad and lifecycle-complete for simulators, apps, UI input, logs, media, and push. Minor gaps remain around input gestures (no long-press, pinch, or rotation/orientation control), which agents can partially work around but would notice.
Maintenance
Related MCP Connectors
Build, run, and inspect iOS apps in disposable hosted Simulators from cloud coding agents.
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Control real Android and iOS devices with LLM agents — tap, swipe, type, automate flows.
Launch and verify high-fidelity mobile simulations from an AI agent.
Related MCP Servers
- AlicenseAqualityAmaintenanceEnables interaction with iOS simulators by providing tools to inspect UI elements, control UI interactions, and manage simulators through natural language commands.177,301 npm2,193MIT
- AlicenseNot gradedqualityDmaintenanceEnables 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.10 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables comprehensive control of iOS simulators and real devices through AI assistants, supporting app management, UI automation, screenshots, media operations, and location simulation for iOS development and testing workflows.8MIT
- FlicenseNot gradedqualityDmaintenanceEnables 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.-