XC-MCP: XCode CLI wrapper
XC-MCP wraps Xcode's CLI tools (xcodebuild, simctl, idb) as 81 MCP tools so AI agents can build, run, and drive iOS apps while keeping output context-efficient.
Build & test — compile projects with
xcodebuild-build, run tests (xcodebuild-test), clean, list schemes/targets, inspect schemes, check versions/SDKs, and validate app capabilities; large logs are summarized with a cache ID and fetched on demand viaxcodebuild-get-details.Manage simulators — list, boot, shutdown, create, delete, erase, clone, rename, and get AI-ranked device suggestions or environment health checks.
Manage apps — install, uninstall, launch (with args/env vars), terminate, open URLs/deep links, and locate app containers.
Drive the UI — tap, type text, press keys, swipe/scroll/rotate/shake, and find elements by label; accessibility-tree reads replace screenshots for cheaper, faster, coordinate-accurate automation.
Audit accessibility — score tree richness and run a WCAG-aligned audit with fix guidance.
Debug & diagnose — stream simulator logs, list/show/delete crash reports, capture app state bundles, detect main-thread hangs (HangBuster), simulate memory warnings, and run
idb-doctorfor Xcode 27 idb issues.Configure test environments — set privacy permissions, push notifications, clipboard text, media library, status bar, appearance (light/dark, text size, locale, RTL), and simulated GPS location.
Capture & compare visuals — screenshots (optimized, inline base64), video recording, and pixel-diff regression checks.
Inspect project files — audit localization catalogs and inspect Core Data/SwiftData models without a simulator.
Run high-level workflows — build-and-run, fresh install, tap-element-by-name, and scripted test recording/reporting in single calls.
Manage caches & self-documentation — view/tune/clear caches, enable/disable disk persistence of learned preferences, and query
rtfmfor any tool's documentation.
Provides intelligent Xcode CLI tooling with progressive disclosure, enabling build operations, simulator management, project discovery, and cache management while solving token overflow issues through smart caching and concise summaries
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., "@XC-MCP: XCode CLI wrapper list available iPhone simulators"
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.
XC-MCP
An MCP server that lets AI agents build, run and drive iOS apps — without drowning in Xcode's output.
XC-MCP wraps xcodebuild, simctl and idb as 81 tools. Its job is not just to expose those
commands but to make their output fit in a model's context: summaries first, full detail on demand,
and the accessibility tree instead of screenshots wherever the app allows it.
Why it exists
Xcode tooling produces output at a scale no context window survives. Measured against a real app (Grapla, Xcode 27, iPhone 17 Pro simulator):
Operation | Raw output | XC-MCP response | Reduction |
One incremental | 1.67 MB · ~419,000 tokens | 1.1 KB · ~285 tokens | ~1,470× |
| 131 KB · ~32,800 tokens | 1.5 KB · ~370 tokens | ~90× |
One crash report ( | 10.7 KB | 1.4 KB summary | ~7.5× |
A single raw build log would overflow a 200k-token context on its own. The full output is never thrown away: it is cached and returned as an MCP resource link, so an agent can drill into the exact errors it needs.
Related MCP server: xcforge
Quick start
Claude Code:
claude mcp add xc-mcp -- npx -y xc-mcpCodex CLI:
codex mcp add xc-mcp -- npx -y xc-mcpor add it to ~/.codex/config.toml directly:
[mcp_servers.xc-mcp]
command = "npx"
args = ["-y", "xc-mcp"]Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"xc-mcp": { "command": "npx", "args": ["-y", "xc-mcp"] }
}
}Then ask your agent to build and run your app. rtfm({}) lists the tool categories.
Requirements
Requirement | Version | Needed for |
macOS | 13+ | everything |
Node.js | 20+ (CI tests 22 and 24) | running the server |
Xcode + Command Line Tools | 15+ (26+ for iOS 26/27 simulators) |
|
| 1.5.1+ | every |
xcode-select --install
# idb — required for all UI automation
brew tap facebook/fb
brew install facebook/fb/idb-companion facebook/fb/idb-cli
brew install idb-companionno longer works — it moved from Homebrew core to Meta'sfacebook/fbtap.
Run idb-doctor whenever UI automation misbehaves. It checks the CLI, the companion version,
the Xcode framework layout, stale companion registrations, CLI/companion version mismatches, and the axbridge guest needed by deep reads.
Xcode 27
idb-companion must be 1.5.1 or newer. Xcode 27 moved SimulatorKit.framework, and older
companions fail silently: the accessibility tree reads correctly and every tap reports success,
while the simulator discards the events. idb-ui-tap, idb-ui-gesture and idb-ui-input detect
this and refuse to run rather than pretend.
brew upgrade facebook/fb/idb-companion
brew list --versions idb-companion # expect >= 1.5.1There is no
Simulator.app— Xcode 27 replaced it withDeviceHub.app.simctl-bootwithopenGuiopens whichever this Xcode ships.If every
idbcall fails withConnection refused, a dead companion is still registered in/tmp/idb/state. Runidb disconnect <udid>;idb-doctordetects this.
How it works
Summaries first, detail on demand
Tools that produce large output return a summary plus an ID. The full output stays in a 30-minute
cache and is exposed two ways: an MCP resource at xcmcp://response/{id}, and the matching
*-get-details tool for clients without resource support.
xcodebuild-build({ projectPath: "./MyApp.xcodeproj", scheme: "MyApp" })
// → { buildId, success: false, errorCount: 3, warningCount: 1, durationMs: 18000 }
xcodebuild-get-details({ buildId, detailType: "errors-only" })
// → the three errors, not the 419k-token logThe accessibility tree before screenshots
For UI automation, reading the accessibility tree is cheaper and faster than sending an image, and it gives exact coordinates instead of visual estimates. Measured on the same screen:
Approach | Response | Latency |
| ~450 tokens of JSON | ~270 ms |
| ~22.5 KB image | ~1,700 ms |
The first idb call in a session takes several seconds while the target cache warms.
This only works when the app is accessible — which is the point. An app VoiceOver can navigate is
an app an agent can navigate. accessibility-quality-check says which path to take;
accessibility-audit says what to fix.
idb-ui-find-element({ query: "Sign In" })
// → { centerX: 201, centerY: 572, visible: true }
idb-ui-tap({ x: 201, y: 572 })Coordinates are not always tappable. The tree reports frames in scrolled-content space, so an
element can sit below the fold. Every match carries visible and, when off-screen, an
offscreenReason naming the gesture that brings it into view.
Simulator automation in v5
idb-semantic-actionpresses a uniquely identified control or replaces a field value with read-back verification. Useexpectto guard a toggle's current value. Secure field values cannot be verified.idb-ui-find-elementsupports exact, type, identifier and index selection.workflow-tap-elementuses accessibility presses for single matching controls.idb-ui-describe({ operation: "all", deep: true })opts into axbridge for web content and alerts. This enables device accessibility automation mode, which idb does not restore. Deep web frames are unsuitable for coordinate taps.idb-ui-gestureadds scroll (content direction), refresh, label-based drag, pinch, long press, multi-tap, rotation and shake. Newer accessibility actions and gestures require idb CLI and companion 1.7+.app-state-capture({ outputDir: "/tmp/app-captures" })creates a bundle of screenshot, accessibility tree, recent logs, device metadata and summary files. Individual artifact failures are reported.
See the parity audit for capability mappings and verification limits.
iPhone Duo
Use simctl-duo with an explicit booted Duo UDID and operation: "state" to read
the hinge angle and enumerate displays. Set operation: "hinge" with pose: "closed",
"partial", "open", or an explicit angle in degrees. Use operation: "rotate"
with orientation: "portrait", "landscape", "portrait-upside-down", or
"landscape-flipped". Changes verify readback; failures include actionable guidance.
Pass the returned display ID as a string in display to screenshot or simctl-io.
Inactive displays can capture black. Explicit display capture omits unverified coordinate
mapping; idb inner-display touch routing is not supported by this integration.
The small bundled Objective-C helper compiles on first use with the selected Xcode
and is cached under ~/Library/Caches/xc-mcp/duo. No community CLI is required.
Mechanism research credit: hinge and
duoctl. XC-MCP implements its own focused helper.
These private interfaces are experimental. Replace the internal backend as supported
headless APIs become available and verified; folding and rotation may migrate separately.
An XCTest-only API does not replace this headless workflow.
Example MCP calls (replace <duo-udid> with a booted Duo UDID):
{"name":"simctl-duo","arguments":{"udid":"<duo-udid>","operation":"state"}}
{"name":"simctl-duo","arguments":{"udid":"<duo-udid>","operation":"hinge","pose":"open"}}
{"name":"simctl-duo","arguments":{"udid":"<duo-udid>","operation":"hinge","angle":127}}
{"name":"simctl-duo","arguments":{"udid":"<duo-udid>","operation":"rotate","orientation":"portrait"}}
{"name":"screenshot","arguments":{"udid":"<duo-udid>","display":"3","size":"full"}}Use the display ID from your own state result; IDs above are examples. Supply exactly
one of pose or angle for hinge operations. partial means 90°. The response includes
hingeAngle, activeScreen, displayId, rotation, and the display inventory.
Verified on Xcode 27.1 / iOS 27.1. Rapid rotation can time out even when a paused
sequence succeeds; cover landscape also timed out in live checks. Read the returned
success and observed state before proceeding. The five-second polling budget excludes
initial readback and dispatch, so total request time can be longer. See the
live verification matrix.
Duo controls are available in default and --mini modes, and excluded by --build-only.
Tools that declare their risk
Every tool carries MCP annotations — readOnlyHint, destructiveHint, idempotentHint — so a
client can ask before running simctl-erase, idb-crash-delete or idb-clear-keychain, and run
simctl-list freely. Build, test, audit and crash tools also declare an outputSchema and return
validated structuredContent.
Tools
81 tools. TOOL_SIGNATURES.md indexes every tool with its annotations;
parameters come from the server itself via rtfm({ toolName: "..." }).
Area | Tools |
Build & test |
|
Simulators |
|
Apps |
|
UI automation |
|
Accessibility |
|
Diagnostics |
|
Test setup |
|
Capture & analysis |
|
Workflows |
|
Cache & docs |
|
Configuration
Flag | Effect |
| One-line tool descriptions; |
| Registers 18 build-focused tools instead of 81 |
Flags combine: ["-y", "xc-mcp", "--mini", "--build-only"] — the same args array works in Claude Desktop and Codex's config.toml. Both matter mainly for clients that
load every tool description upfront; see the history below.
Environment variable | Default | Controls |
|
| Disk persistence for caches |
|
| HangBuster capture sessions |
|
| Test recording reports |
How context cost shaped this server
XC-MCP has been rebuilt three times, and each rebuild answered the same question — what does a tool cost in context? — differently, because the answer kept changing underneath it. The tool count went 51 → 28 → 77, and each time the right number was set by what clients and the protocol could do.
v1 · Aug 2025 — 51 tools, every description paid upfront
MCP clients of the time loaded every tool's name, description and input schema when they connected, and kept them in context for the whole session. Tool count was a tax on context, paid before the agent did any work.
v1.3.2 cut the tax per tool: descriptions shrank to a few words and the real documentation moved
behind rtfm, fetched only when asked for. A separate, smaller xc-mini-mcp package was also
published — and reverted shortly after.
v2 · Nov 2025 — 28 tools, consolidated into routers
If the count is the tax, cut the count. v2 folded 21 tools into six operation-enum routers —
simctl-device({ operation: "boot" }) instead of simctl-boot — sharing one schema per router.
That bought a debt nobody could see yet. A router is a single tool, so it carries a single description and a single set of properties for every operation behind it. That cost nothing while tools had no per-tool properties worth losing.
v3 · Nov 2025 — betting on deferred loading
v3 set defer_loading: true on every tool, expecting tools to load on demand and baseline cost to
fall toward zero. The goal was right; the mechanism could not work.
defer_loading is a field of the Messages API. It belongs on tool definitions sent to the model,
alongside the tool-search server tools, and an MCP server has no way to set it. The MCP SDK also
drops unrecognised keys from a tool's registration, so the flag never reached a client — a live
tools/list later showed 0 of 77 tools carrying it.
Deferral did arrive, on the client side. Clients with tool search, Claude Code among them, began listing only tool names at startup and fetching a tool's schema when it is first used. No server flag was involved.
v4 · Jun 2026 — 70 tools, routers dissolved
Two developments reversed the v2 trade-off.
Client-side tool search made tool count cheap. With schemas deferred, 77 tools cost roughly what their names cost — about 1,240 tokens at startup, server instructions included.
The protocol gained per-tool metadata. Revision
2025-03-26added tool annotations (#185). Revision2025-06-18added structured tool output (#371), resource links in tool results (#603), and a human-readabletitle(#663).
Annotations are precisely what a router cannot express. simctl-device hid both boot, which is
harmless, and erase, which destroys a simulator, behind one tool — so no client could tell them
apart. The routers were dissolved into discrete tools that each declare their own risk and output
shape, and resource links replaced ad-hoc cache IDs as the way to return large output. The server
negotiates protocol 2025-06-18.
v4.1 · Sep 2026 — 71 tools, Xcode 27 readiness
Xcode 27 broke idb in a way that failed silently: older companions read the accessibility tree
correctly but dropped every tap while reporting success. v4.1 added idb-doctor, a 1.5.1 companion
floor, and a preflight that makes HID-writing tools refuse to run rather than pretend.
v4.2 · Sep 2026 — 77 tools, tested against a real app
Driving a real app end-to-end found four bugs that had passed 1,456 tests, all in parsing idb's
output. The tests mocked a format idb never emits — newline-delimited objects with label fields —
where idb really returns one JSON array using AXLabel. So accessibility-quality-check rated every
screen unusable and idb-ui-find-element never matched anything, each while returning well-formed,
plausible JSON. Fixtures now use captured idb output, and reintroducing one of those bugs fails ten
tests.
The same pass added crash reporting, element visibility and test-isolation tools, and removed the
inert defer_loading flag.
v5.0 · Simulator skill capabilities
Adds semantic accessibility actions, diagnostic bundles, batch simulator filters, media import,
container export, and hang-capture controls. The breaking change is explicit consent:
simctl-erase, simctl-delete, simctl-uninstall and idb-uninstall require confirm: true.
workflow-fresh-install retains its eraseSimulator: true opt-in. Use either a single deviceId
or batch selectors (all, deviceType, runtime); combining an explicit ID with filters fails.
Photo-library clearing also requires confirmation.
The trade-off, version by version
Version | Tools | What set the context cost |
v1.0 | 51 | Every description loaded at connect |
v1.3.2 | 51 | Descriptions trimmed; documentation moved behind |
v2.0 | 28 | Tool count cut by consolidating into routers |
v3.0 | 30 | A server-side deferral flag that never took effect |
v4.0 | 70 | Client-side deferral; routers dissolved for per-tool annotations |
v4.1 | 71 | Unchanged model; Xcode 27 support |
v4.2 | 77 | Unchanged model, verified against real idb output |
v5.1 | 81 | Duo pose controls and display-aware capture |
v5.0 | 80 | Semantic actions, diagnostic bundles and simulator skill capabilities |
Two lessons carried forward. Context cost is the client's call — a server should describe its tools honestly and let the client decide how to spend context on them. And a structured response can hide a broken tool — test against the real command, not a mock of it.
Release detail is in CHANGELOG.md.
Migrating from v2/v3 routers
Drop the operation field and call the matching tool. Operation-specific parameters are unchanged.
Removed router | Replacement tools |
|
|
|
|
|
|
|
|
|
|
idb-targets keeps its operation enum. rtfm({ toolName: "simctl-device" }) still suggests the
replacements.
Development
git clone https://github.com/conorluddy/xc-mcp.git
cd xc-mcp && npm install
npm run build # compile to dist/
npm test # jest
npm run lint # eslintInstall the current checkout locally
Build and package the checkout, then install the exact tarball into the active Node.js prefix:
npm run build
npm pack --pack-destination /tmp
npm install --global /tmp/xc-mcp-5.1.0.tgzUse xc-mcp as the MCP client's command (with --mini if desired). npx -y xc-mcp may resolve
an npm release rather than this local build. After switching Node.js versions, check command -v xc-mcp
because global installations belong to that Node.js prefix. The CLI speaks MCP over stdio;
verify it with an MCP client using initialize, tools/list and tools/call.
Point any MCP client at a local build with node /path/to/xc-mcp/dist/index.js. A running server
holds dist/ in memory, so restart the client session after rebuilding.
AGENTS.md supplies contributor guidance; CLAUDE.md covers the architecture, how to add a tool, and the rules learned the hard way.
Contributing
Contributions are welcome but reviewed slowly — this repo sits well down my priority list. Forking and adapting it is usually the faster route.
Pull requests need a passing build, tests and lint.
License
MIT, as declared in package.json.
Available Tools
80 toolsaccessibility-auditAccessibility (WCAG) AuditARead-onlyIdempotent
accessibility-audit
WCAG-aligned accessibility audit of the live iOS simulator accessibility tree.
Overview
Fetches the full accessibility tree via idb ui describe-all, flattens it, and evaluates
every element against a tiered rule set (critical → warning → info). Returns a severity
summary and either the full issue list (verbose mode) or the top issues grouped by rule.
Distinct from accessibility-quality-check, which only scores tree richness. This tool
diagnoses what is broken and how to fix it.
Parameters
Optional
udid (string): Target identifier — auto-detects if omitted
verbose (boolean): Return all issues instead of grouped top-10 (default: false)
Rules
Critical — blocks assistive technology users
Rule | Condition | Fix |
missing_label | Button or Link with no AXLabel | Add accessibilityLabel |
empty_button | Button with no AXLabel AND no AXValue | Set button title or accessibilityLabel |
image_no_alt | Image with no AXLabel | Add accessibilityLabel with description |
Warning — degrades UX
Rule | Condition | Fix |
missing_hint | Slider or TextField with no help text | Add accessibilityHint |
missing_traits | Element has type but no traits | Set appropriate accessibilityTraits |
small_touch_target | Tappable frame < 44×44pt | Increase tappable area to at least 44×44pt |
Info — best-practice suggestions
Rule | Condition | Fix |
no_identifier | Element missing AXUniqueId | Add accessibilityIdentifier for testing |
deep_nesting | Element depth > 5 | Simplify view hierarchy |
Returns
summary:
{ total, critical, warning, info }issues (verbose mode): Full issue list
topIssues (default): Issues grouped by rule, sorted by severity then count, capped at 10
Structured Content
{ "total": 3, "critical": 1, "warning": 1, "info": 1 }Examples
// Quick audit — top issues only
const result = await accessibilityAuditTool({});
// Full details for CI reporting
const result = await accessibilityAuditTool({ verbose: true });Related Tools
accessibility-quality-check: Richness score — use before deciding accessibility vs screenshotidb-ui-describe: Full accessibility tree for manual inspection
Inputs: udid, verbose. Returns: info, total, warning, critical
accessibility-quality-checkAccessibility Quality CheckARead-onlyIdempotent
accessibility-quality-check
Quick assessment of accessibility tree richness - decide whether to use accessibility or screenshots.
Overview
Rapidly queries the accessibility tree and assesses data richness without returning full element details. Returns a quality score and recommendation (accessibility-ready or screenshot-fallback) in ~80ms with minimal token cost. Prevents agents from wasting tokens on expensive screenshots when accessibility data is sufficient.
Parameters
Optional
udid (string): Target identifier - auto-detects if omitted
screenContext (string): Screen name for semantic tracking (e.g., "LoginScreen")
Returns
quality: "rich" | "moderate" | "minimal"
recommendation: "accessibility-ready" | "consider-screenshot"
elementCounts: Total elements, tappable elements, text fields, element types
queryTime: Query execution time in milliseconds
queryGuidance: Next steps based on quality assessment
Examples
Quick check of current screen
const check = await accessibilityQualityCheckTool({
screenContext: 'LoginScreen'
});
if (check.quality === 'rich') {
// Use accessibility: idb-ui-describe
} else {
// Fall back to screenshot
}Check before deciding automation approach
const assessment = await accessibilityQualityCheckTool({
udid: 'DEVICE-UDID'
});
// Workflow guided by qualityQuality Levels
Rich (✅ Use accessibility)
3 tappable elements, OR
Text input fields detected
Recommendation: Use idb-ui-describe and accessibility-based navigation
Moderate (⚠️ Try accessibility first)
2-3 tappable elements
Some custom UI that may not be recognized
Recommendation: Try accessibility tree first, fall back to screenshot if needed
Minimal (📸 Use screenshot)
≤1 element, OR
No tappable elements found
Recommendation: Take screenshot for visual analysis
How It Works
Quick query: Calls
idb ui describe-all(~80ms)Assess richness: Counts tappable elements, text fields
Return score: Quality assessment + recommendation
No elements returned: Just the counts and guidance
Cost Comparison
accessibility-quality-check: ~80ms, 30 tokens
Full idb-ui-describe: ~120ms, 50 tokens
screenshot: ~2000ms, 170 tokens
Related Tools
idb-ui-describe: Full accessibility tree with element detailsidb-ui-find-element: Search for specific element by namescreenshot: Visual fallback when accessibility insufficient
Notes
Returns quality assessment only (not full element tree)
Recommended as first step before choosing automation approach
Saves tokens by preventing unnecessary screenshots
Identifies when UI has minimal accessibility support
Inputs: udid, screenContext. Returns: quality, success, textFields, totalElements, +2 more
app-state-captureCapture App StateA
app-state-capture
Capture a diagnostic bundle containing screenshot.png, accessibility.json, app-logs.txt, device.json, summary.json, and README.md. Requires outputDir. udid is auto-detected; bundleId optionally filters recent logs. Creates a fresh capture directory and reports individual artifact failures. Log capture covers the last five minutes, capped at 100 lines.
Inputs: outputDir (required), udid, bundleId.
cache-clearClear CacheADestructiveIdempotent
cache-clear
🗑️ Clear cached data to force fresh retrieval and resolve stale state - Purge cache systems.
Removes all entries from the specified cache system(s). Forces fresh data retrieval on the next operation. Useful for troubleshooting stale cache issues, resetting learned patterns, or clearing memory after major project changes. Can target individual caches or clear all at once.
Advantages
• Force fresh data after major Xcode project changes (new targets, schemes, build settings) • Resolve issues caused by stale cached simulator or project data • Clear memory before performance testing to establish baseline • Reset learned patterns when switching between project configurations
Parameters
Required
cacheType (string): Which cache to clear - "simulator", "project", "response", or "all"
Optional
(None)
Returns
Tool execution results with clear operation confirmation
Results per cache type showing successful clearing
Timestamp of cache clearing
Related Tools
cache-get-stats: Monitor cache before clearing
cache-set-config: Configure cache retention
cache-get-config: View cache configuration
Notes
Tool is auto-registered with MCP server
Operation is immediate and irreversible
Clearing all caches forces fresh retrieval on all tools
Use before performance benchmarking
Inputs: cacheType.
cache-get-configGet Cache ConfigurationARead-onlyIdempotent
cache-get-config
🔍 Get current cache retention configuration settings - View cache policies.
Retrieves the current cache retention policies for simulator, project, and response caches. Shows both millisecond values and human-readable durations. Essential for understanding your current cache configuration before making adjustments or troubleshooting performance.
Advantages
• Verify cache retention settings before tuning for specific workflows • Understand current configuration when troubleshooting stale data issues • Document cache settings for team collaboration or CI/CD configuration • Compare settings across different environments (development vs production)
Parameters
Required
(None)
Optional
cacheType (string): Which cache config to retrieve - "simulator", "project", "response", or "all". Defaults to "all"
Returns
Tool execution results with current cache configuration
Retention times in both milliseconds and human-readable format
Fixed response cache duration (30 minutes)
Related Tools
cache-set-config: Configure cache retention times
cache-get-stats: Monitor cache performance
cache-clear: Clear cached data
Notes
Tool is auto-registered with MCP server
Shows default configurations before any customization
Response cache duration is fixed at 30 minutes
Use to verify config changes after using cache-set-config
Inputs: cacheType.
cache-get-statsGet Cache StatisticsARead-onlyIdempotent
cache-get-stats
📊 Get comprehensive statistics across all XC-MCP cache systems - Monitor cache performance and effectiveness.
Retrieves detailed statistics from the simulator cache, project cache, and response cache systems. Shows hit rates, entry counts, storage usage, and performance metrics across all caching layers. Essential for monitoring cache effectiveness and identifying optimization opportunities.
Advantages
• Monitor cache performance across all simulator, project, and response caches • Understand cache hit rates to optimize build and test workflows • Track memory usage and identify tuning opportunities • Debug performance issues by analyzing cache patterns
Parameters
Required
(None - retrieves statistics from all cache systems automatically)
Optional
(None)
Returns
Tool execution results with structured cache statistics
Statistics for each cache system (simulator, project, response)
Hit rates, entry counts, and performance metrics
Timestamp of statistics collection
Related Tools
cache-set-config: Configure cache retention times
cache-get-config: Get current cache configuration
cache-clear: Clear cached data
Notes
Tool is auto-registered with MCP server
Statistics are calculated in real-time
Use regularly to monitor cache effectiveness
Export statistics for performance analysis across time
Inputs: no named parameters.
cache-set-configSet Cache ConfigurationAIdempotent
cache-set-config
⚙️ Configure cache retention times to optimize for your workflow - Fine-tune cache policies.
Fine-tune cache retention policies for simulator, project, and response caches. Allows you to balance performance (longer cache retention) against freshness (shorter retention). Default is 1 hour for most caches. Supports specifying duration in milliseconds, minutes, or hours for convenience.
Advantages
• Optimize for development workflows (longer cache = faster repeated operations) • Optimize for CI/CD environments (shorter cache = fresher data, less stale state) • Reduce memory usage by lowering retention times for infrequently-accessed caches • Extend retention for slow-changing projects to maximize performance gains
Parameters
Required
cacheType (string): Which cache to configure - "simulator", "project", "response", or "all"
Optional
maxAgeMs (number): Cache retention in milliseconds
maxAgeMinutes (number): Cache retention in minutes (alternative to maxAgeMs)
maxAgeHours (number): Cache retention in hours (alternative to maxAgeMs)
Note: Specify exactly one of maxAgeMs, maxAgeMinutes, or maxAgeHours. Minimum 1000ms (1 second).
Returns
Tool execution results with configuration update confirmation
Results per cache type with human-readable durations
Timestamp of configuration change
Related Tools
cache-get-config: Get current cache configuration
cache-get-stats: Monitor cache performance
cache-clear: Clear cached data
Notes
Tool is auto-registered with MCP server
Changes apply immediately
Response cache is currently fixed at 30 minutes
Use with cache-get-stats to verify effectiveness
Inputs: cacheType (required), maxAgeMs, maxAgeHours, maxAgeMinutes.
hang-get-detailsGet Hang Capture DetailsARead-onlyIdempotent
hang-get-details
Return the full L2 summary for a stopped HangBuster session, or the per-event detail of a specific cluster.
Parameters
sessionId(required)cluster(optional, 1-indexed): drill into one cluster's events
Returns
Formatted L2 summary (severity histogram, bursts, process distribution) or cluster detail.
Inputs: sessionId (required), cluster.
hang-listList Hang Capture SessionsARead-onlyIdempotent
hang-list
List all HangBuster capture sessions (newest first) with status, device, and timestamps.
Parameters
None.
Returns
Array of sessions with sessionId/status/udid/createdAt/stoppedAt.
Inputs: no named parameters.
hang-startStart Hang CaptureA
hang-start
Begin a HangBuster capture session. Spawns a detached simctl log stream filtered to
hang/stall/watchdog/jetsam events, writing to the session's raw log. Reproduce the hang,
then call hang-stop to parse, cluster, and rank the results.
Parameters
rawCapture(optional): capture all NDJSON log records, skip clustering, and gzip at stopnoGzip(optional): keep raw capture uncompressedudid(optional): simulator UDID (default: booted)predicate(optional): override the os_log predicateminHangMs(optional, default 250): drop hang events shorter than this at stop time
Returns
sessionId (pass to hang-stop / hang-get-details), pid, and guidance.
Inputs: udid, noGzip, minHangMs, predicate, +1 more.
hang-stopStop & Analyze Hang CaptureAIdempotent
hang-stop
Stop a HangBuster session, parse its captured log through the clustering pipeline (parse → normalise → threshold → fingerprint → cluster → rank), persist the summary, and return a token-budgeted view (L0/L1/L2 auto-selected).
Parameters
sessionId(required): the session from hang-starttopN(optional): number of top clusters to keep (default 3)budgetTokens(optional): cap output size; picks L0/L1/L2 to fit
Returns
Hang/cluster counts and a formatted summary. Drill deeper with hang-get-details.
Inputs: sessionId (required), topN, budgetTokens.
idb-clear-keychainClear Simulator KeychainADestructiveIdempotent
idb-clear-keychain
Clear a simulator's keychain, for test isolation.
Overview
Keychain entries survive app uninstall — that is the point of the keychain, and it is why a "fresh install" test can still start logged in. Clearing it gives a genuinely clean credential state before an onboarding or authentication test.
Parameters
Optional
udid (string): Target identifier - auto-detects if omitted
scenario (string): Test scenario name, recorded in the audit entry
step (number): Step number within the scenario
Returns
Confirmation with an audit entry (timestamp, action, scenario, step).
Examples
// Genuinely clean login state — uninstalling the app alone would not do this
await idbClearKeychainTool({ scenario: 'First-run onboarding' });
await workflowFreshInstallTool({ projectPath: './MyApp.xcodeproj', scheme: 'MyApp' });Related Tools
workflow-fresh-install: Wipes app data, but NOT the keychain
simctl-erase: Factory-resets the whole simulator (heavier; also clears the keychain)
simctl-privacy: Reset permission grants, the other thing that survives reinstall
Notes
Destructive: clears credentials for EVERY app on the simulator, not just yours.
Cheaper and more targeted than simctl-erase when credentials are all you need reset.
Inputs: step, udid, scenario.
idb-crash-deleteDelete Crash ReportsADestructiveIdempotent
idb-crash-delete
Delete crash reports from a simulator.
Overview
Mainly useful for establishing a clean baseline before a test run, so that any crash found afterwards is known to belong to that run. Deletion is permanent.
Parameters
Optional (exactly one selector required)
name (string): Delete one specific report, by name from idb-crash-list
bundleId (string): Delete all reports for one bundle
all (boolean): Delete every crash report on the target
udid (string): Target identifier - auto-detects if omitted
Returns
Confirmation with the selector used and the raw idb output.
Examples
Clean baseline before a test run
await idbCrashDeleteTool({ bundleId: 'com.example.MyApp' });
// ... run the test ...
await idbCrashListTool({ bundleId: 'com.example.MyApp' }); // anything here is from this runRelated Tools
idb-crash-list: Inspect before deleting
Notes
Destructive and irreversible: clients may gate this behind confirmation.
Requires exactly one of name / bundleId / all, to avoid deleting more than intended.
Inputs: all, name, udid, bundleId.
idb-crash-listList Crash ReportsARead-onlyIdempotent
idb-crash-list
List crash reports on a simulator, so an agent can tell a crash from a no-op.
Overview
Without this, a failed interaction is ambiguous: an agent cannot distinguish "my tap did nothing" from "the app crashed and is gone". Crash reports are written by the OS and persist across app launches and reboots.
Simulators accumulate crashes from unrelated system processes. An unfiltered list is mostly
noise from other apps and extensions. The useful question is scoped:
"did MY bundle crash since I launched it?" — so pass bundleId and since.
Parameters
Optional
udid (string): Target identifier - auto-detects if omitted
bundleId (string): Only crashes for this bundle (e.g. "com.example.MyApp")
since (number): Unix timestamp in SECONDS - only crashes newer than this
before (number): Unix timestamp in SECONDS - only crashes older than this
limit (number, default 20): Maximum crashes to return, newest first
Returns
crashCount, a crashes array (name, bundleId, processName, timestamp, occurredAt) and the
filters that were applied. Pass a name to idb-crash-show for the full report.
Examples
Did my app crash during this test run?
const launchedAt = Math.floor(Date.now() / 1000);
// ... drive the app ...
await idbCrashListTool({ bundleId: 'com.example.MyApp', since: launchedAt });Everything recent, regardless of app
await idbCrashListTool({ since: Math.floor(Date.now() / 1000) - 3600 });Related Tools
idb-crash-show: Full report for one crash
idb-crash-delete: Remove reports (e.g. to get a clean baseline before a test)
simctl-stream-logs: Live log stream, which catches non-fatal errors a crash report will not
hang-start: Main-thread hangs, which produce no crash report at all
Notes
Timestamps are unix SECONDS, not milliseconds.
An empty list is a meaningful result: the app did not crash.
Inputs: udid, limit, since, before, +1 more. Returns: crashes, success, crashCount, totalMatched
idb-crash-showShow Crash ReportARead-onlyIdempotent
idb-crash-show
Fetch one crash report, summarized, with the full report available on demand.
Overview
Crash reports are large — 10KB for a trivial one and far more with full thread backtraces — so this
returns a summary plus a cache ID rather than dumping the report into context. The full text is
retrievable as an MCP resource at xcmcp://response/{cacheId}.
An .ips file is TWO concatenated JSON documents: a single-line header followed by a
pretty-printed body. This tool parses both and merges the useful parts.
Parameters
Required
name (string): Crash report name from idb-crash-list (e.g. ".MyApp-2026-09-12-104512.ips")
Optional
udid (string): Target identifier - auto-detects if omitted
Returns
Summary with appName, bundleId, timestamp, osVersion, exception type/signal, termination reason,
and the top frames of the faulting thread — usually enough to identify the cause without reading
the full report. Plus cacheId and a resource link to the complete text.
Examples
const crashes = await idbCrashListTool({ bundleId: 'com.example.MyApp' });
await idbCrashShowTool({ name: crashes.crashes[0].name });Related Tools
idb-crash-list: Find crash report names
xcodebuild-get-details: The same progressive-disclosure pattern for build logs
Notes
Symbol names appear only where the binary is symbolicated; unsymbolicated frames show the image and offset instead.
Inputs: name (required), udid.
idb-doctorDiagnose idb EnvironmentARead-onlyIdempotent
Diagnose whether idb can drive simulator UI on this machine.
Checks the idb CLI and companion, the companion version against the 1.5.1 floor, the Xcode framework layout, and stale companion registrations.
Run this first when taps, swipes or typing appear to succeed but nothing happens on screen - on Xcode 27 an idb-companion older than 1.5.1 drops every HID event while still reporting success, and reads continue to work normally.
Returns a JSON report plus remediation commands.
Inputs: no named parameters.
idb-installInstall App (IDB)AIdempotent
idb-install
Install application to iOS target - deploy .app bundles or .ipa archives for testing.
Overview
Transfers and registers application bundles (.app) or archives (.ipa) to iOS targets. Validates app path format before transfer, handles installation process (transfer, registration, signature validation), extracts bundle ID from output for launching, and provides detailed error guidance for common failures (code signing, architecture mismatch, already installed).
Parameters
Required
appPath (string): Absolute path to .app bundle or .ipa archive
Optional
udid (string): Target identifier - auto-detects if omitted
Returns
Installation status with success indicator, app path, extracted bundle ID (if available), installation output, and context-specific troubleshooting guidance (code signing issues, architecture mismatches, already installed, file not found).
Examples
Install simulator build
const result = await idbInstallTool({
appPath: '/path/to/DerivedData/Build/Products/Debug-iphonesimulator/MyApp.app'
});Install signed IPA to physical device
await idbInstallTool({
appPath: '/path/to/MyApp.ipa',
udid: 'DEVICE-UDID-123'
});Related Tools
idb-list-apps: Find bundle ID after installation
idb-launch: Launch installed app by bundle ID
idb-uninstall: Remove app for clean reinstall
Notes
Supports .app bundles (from Xcode build) and .ipa archives (signed/unsigned)
Installation can take 10-60 seconds depending on app size
Simulators accept unsigned .app bundles
Physical devices require valid provisioning profile
Auto-terminates running apps before installation
Extracts bundle ID from output when available
Inputs: appPath (required), udid.
idb-launchLaunch App (IDB)A
idb-launch
Launch application on iOS target - start apps with optional output streaming and environment control.
Overview
Launches installed applications by bundle ID with optional stdout/stderr streaming, command-line arguments, and environment variables. Extracts process ID for tracking, streams app output when debugging is needed, and provides detailed error guidance for launch failures (app not installed, already running, crashed on launch).
Parameters
Required
bundleId (string): App bundle identifier (from idb-list-apps or app installation)
Optional
udid (string): Target identifier - auto-detects if omitted
streamOutput (boolean): Enable stdout/stderr capture with -w flag
arguments (string[]): Command-line arguments to pass to app
environment (object): Environment variables to set (KEY=VALUE format)
Returns
Launch status with success indicator, bundle ID, extracted process ID, streaming status, captured stdout/stderr (if streaming enabled), error details if failed, and troubleshooting guidance (app not found, already running, crash logs).
Examples
Simple launch for UI automation
const result = await idbLaunchTool({
bundleId: 'com.example.MyApp'
});Launch with debug output streaming
await idbLaunchTool({
bundleId: 'com.example.MyApp',
streamOutput: true,
environment: { DEBUG: '1', LOG_LEVEL: 'verbose' }
});Launch with arguments
await idbLaunchTool({
bundleId: 'com.example.MyApp',
arguments: ['--test-mode', '--skip-intro']
});Related Tools
idb-list-apps: Find bundle ID of installed apps
idb-terminate: Stop running app
idb-ui-tap: Interact with launched app UI
Notes
With -w flag: Streams stdout/stderr (useful for debugging)
Without -w: Fire and forget (app runs in background)
Returns process ID for tracking app lifecycle
Supports command-line arguments and environment variables
IDB uses --env KEY=VALUE format for environment variables
Inputs: bundleId (required), udid, arguments, environment, +1 more.
idb-libraryManage Notifications and PhotosADestructiveIdempotent
idb-library
Manage delivered notifications and the simulator photo library.
operation: notification-list | notification-clear | photos-clear. udid is optional. Notification operations require bundleId. List output defaults to 25 entries; limit controls the cap. photos-clear requires confirm: true and permanently deletes all simulator photos. Requires idb 1.7+; unsupported commands return errors with upgrade guidance.
Inputs: operation (required), udid, limit, confirm, +1 more.
idb-list-appsList Installed Apps (IDB)ARead-onlyIdempotent
idb-list-apps
List installed applications - discover apps available for testing with bundle IDs and running status.
Overview
Enumerates all installed applications on iOS targets with structured metadata including bundle ID, app name, install type (system/user/internal), running status, debuggability, and architecture. Filters apps by install type or running status to focus on user apps or active processes. Parses IDB's pipe-separated output into structured JSON for easy programmatic access.
Parameters
Required
None - all parameters are optional
Optional
udid (string): Target identifier - auto-detects if omitted
filterType (string): Filter by install type ("system", "user", or "internal")
runningOnly (boolean): Show only currently running apps
Returns
Structured app list with summary counts (total, running, debuggable, by install type), separate arrays for running vs. installed apps, applied filter details, and actionable guidance for launching, terminating, installing, or debugging apps.
Examples
List user-installed apps to find test target
const result = await idbListAppsTool({
filterType: 'user'
});Find running app for UI automation
const running = await idbListAppsTool({ runningOnly: true });List all apps on specific device
const all = await idbListAppsTool({
udid: 'DEVICE-UDID-123'
});Related Tools
idb-launch: Launch app by bundle ID discovered here
idb-terminate: Stop running app found in list
idb-install: Install new app to target
Notes
IDB outputs pipe-separated text, converted to structured JSON
Output format: bundle_id | app_name | install_type | arch | running | debuggable
Filter by install type to focus on user apps vs system apps
Running status helps identify active processes for UI automation
Debuggable status indicates if debugger can be attached
Inputs: udid, filterType, runningOnly.
idb-semantic-actionAct on Accessibility ElementA
idb-semantic-action
Press a uniquely identified control or replace and verify a field value.
query matches AXUniqueId or AXLabel exactly, case-insensitively; exact:false enables substring search. Ambiguous targets fail before mutation. operation is press or set-value; the latter requires value. expect optionally guards the current AXValue. udid is optional. Marker uniqueness includes untyped nodes. Failed accessibility presses fall back to coordinates. Field updates are read back up to three times; secure fields explicitly report unverified success.
Inputs: query (required), operation (required), udid, exact, +2 more.
idb-simulate-memory-warningSimulate Memory WarningAIdempotent
idb-simulate-memory-warning
Deliver a memory warning to a simulator, to exercise low-memory code paths.
Overview
iOS reclaims memory aggressively, and the paths that respond to it — didReceiveMemoryWarning,
SwiftUI cache eviction, NSCache purging — are among the least exercised in a typical test run.
Bugs there surface as blank views or lost state on a real device under pressure, long after release.
This delivers the warning on demand, so those paths can be tested deliberately.
Parameters
Optional
udid (string): Target identifier - auto-detects if omitted
scenario (string): Test scenario name, recorded in the audit entry
step (number): Step number within the scenario
Returns
Confirmation with an audit entry (timestamp, action, scenario, step) for test-run reconstruction.
Examples
// Check the app survives memory pressure mid-flow
await idbSimulateMemoryWarningTool({ scenario: 'Checkout under pressure', step: 3 });
await accessibilityQualityCheckTool({}); // did the UI survive?Related Tools
idb-crash-list: Check whether the warning actually killed the app
accessibility-quality-check: Cheap check that the UI is still intact afterwards
simctl-stream-logs: Watch for memory-related log output
Notes
The warning is advisory: iOS may or may not terminate the app depending on its footprint.
Follow with idb-crash-list to distinguish "handled it" from "was jettisoned".
Inputs: step, udid, scenario.
idb-targetsManage IDB TargetsAIdempotent
idb-targets
Unified IDB target management - discover, inspect, focus, and manage connections.
Overview
Single tool for IDB target discovery and connection management. Routes to specialized handlers while maintaining clean operation semantics.
Operations
list
List all available IDB targets.
Parameters:
state(string, optional): Filter by state - 'Booted' or 'Shutdown'type(string, optional): Filter by type - 'device' or 'simulator'
Example:
await idbTargetsToolUnified({
operation: 'list',
state: 'Booted'
})Returns: List of targets with metadata, state, and type information.
describe
Get detailed information about a specific target.
Parameters:
udid(string): Target UDID
Example:
await idbTargetsToolUnified({
operation: 'describe',
udid: 'ABC-123-DEF'
})Returns: Detailed target information including screen dimensions, device model, iOS version.
focus
Focus simulator window for interactive testing.
Parameters:
udid(string): Simulator UDID
Example:
await idbTargetsToolUnified({
operation: 'focus',
udid: 'ABC-123-DEF'
})connect
Establish IDB companion connection to target.
Parameters:
udid(string, optional): Target UDID - auto-detects if omitted
Example:
await idbTargetsToolUnified({
operation: 'connect',
udid: 'ABC-123-DEF'
})Notes: Establishes persistent gRPC connection for faster subsequent operations. Useful for warming up connections before automated testing.
disconnect
Close IDB companion connection to target.
Parameters:
udid(string, optional): Target UDID
Example:
await idbTargetsToolUnified({
operation: 'disconnect',
udid: 'ABC-123-DEF'
})Related Tools
idb-install/idb-launch/idb-terminate/idb-uninstall: App management on IDB targetsidb-ui-tap,idb-ui-input,idb-ui-gesture: UI automation on targets
Inputs: operation (required), type, udid, state.
idb-terminateTerminate App (IDB)AIdempotent
idb-terminate
Terminate running application - force-quit apps for clean state testing and debugging.
Overview
Force-terminates running applications by bundle ID with immediate stop (no graceful shutdown). Idempotent operation that succeeds even if app not running. Detects whether app was actually running from output parsing to provide accurate status. Essential for resetting app state between test runs and preparing for reinstallation.
Parameters
Required
bundleId (string): App bundle identifier to terminate
Optional
udid (string): Target identifier - auto-detects if omitted
Returns
Termination status with success indicator, bundle ID, wasRunning flag (parsed from output to distinguish actual termination from no-op), command output, error details if failed, and next steps guidance (relaunch, reinstall, verification).
Examples
Force-quit app before reinstall
const result = await idbTerminateTool({
bundleId: 'com.example.MyApp'
});Stop app on specific device
await idbTerminateTool({
bundleId: 'com.example.MyApp',
udid: 'DEVICE-UDID-123'
});Related Tools
idb-launch: Relaunch app after termination
idb-list-apps: Verify running status before/after termination
idb-uninstall: Remove app after termination for clean install
Notes
This is a force-kill operation (not graceful shutdown)
Idempotent - succeeds even if app not running
IDB terminate sends termination signal to running app
wasRunning flag indicates if app was actually terminated vs already stopped
Safe to call multiple times - no error if app already stopped
Inputs: bundleId (required), udid.
idb-ui-describeDescribe Accessibility TreeAIdempotent
idb-ui-describe
🔍 Query UI accessibility tree - discover tappable elements and text fields for precise automation
What it does
Queries iOS accessibility tree to discover UI elements, their properties (type, label, enabled state), coordinates (frame, centerX, centerY), and accessibility identifiers. Returns full tree with progressive disclosure (summary + cache ID for full data), element-at-point queries for tap validation, and data quality assessment (rich/moderate/minimal) to guide automation strategy. Automatically parses NDJSON output to extract all elements (not just first), includes AXFrame coordinate parsing for precise tapping, and caches large outputs to prevent token overflow.
Progressive Filtering: Supports 4 filter levels for element discovery - start conservative with moderate filtering (default), escalate to permissive/none if minimal data found.
iOS Compatibility: Recognizes iOS-specific accessibility fields (role, role_description, AXLabel, AXFrame) in addition to standard fields.
Why you'd use it
Discover all tappable elements from accessibility tree - buttons, cells, links identified by JSON element objects
Get precise tap coordinates (centerX, centerY) for elements without needing screenshots
Assess data quality before choosing automation approach - rich data enables precise targeting, minimal data requires screenshots
Validate tap coordinates by querying elements at specific points before execution
Progressive disclosure prevents token overflow on complex UIs - get summary first, full tree on demand
Progressive filter escalation - start with moderate filtering, escalate to permissive/none if minimal data found
Deep reads
For operation all, deep: true opts into axbridge. It enables device accessibility automation mode, which idb does not restore. Default reads retain the ordinary accessibility backend.
Parameters
Required
operation (string): "all" | "point"
Point operation parameters
x (number, required for point operation): X coordinate to query
y (number, required for point operation): Y coordinate to query
Optional
udid (string): Target identifier - auto-detects if omitted
screenContext (string): Screen name for context (e.g., "LoginScreen")
purposeDescription (string): Query purpose (e.g., "Find tappable button")
filterLevel (string): "strict" | "moderate" | "permissive" | "none" (default: "moderate")
strict: Only obvious interactive elements via type field (original behavior)
moderate: Include iOS roles (role, role_description) - DEFAULT, fixes iOS button detection
permissive: Any element with role/type/label information
none: Return everything (debugging)
Returns
For "all": UI tree summary with element counts (total, tappable, text fields), data quality assessment (rich/moderate/minimal), top 20 interactive elements preview with centerX/centerY coordinates, uiTreeId for full tree retrieval, current filter level, and guidance on automation strategy including suggestions to escalate filter level if minimal data found.
For "point": Element details at coordinates including type, label, value, identifier, frame coordinates (x, y, centerX, centerY), enabled state, and tappability.
Examples
Query full UI tree with default moderate filtering
const result = await idbUiDescribeTool({
operation: 'all',
screenContext: 'LoginScreen',
purposeDescription: 'Find email and password fields'
});
// Result includes elements with centerX, centerY for direct tappingProgressive filter escalation pattern
// 1. Start with default (moderate)
let result = await idbUiDescribeTool({ operation: 'all' });
// 2. If minimal data, try permissive
if (result.summary.dataQuality === 'minimal') {
result = await idbUiDescribeTool({
operation: 'all',
filterLevel: 'permissive'
});
}
// 3. If still minimal, try none (return everything)
if (result.summary.dataQuality === 'minimal') {
result = await idbUiDescribeTool({
operation: 'all',
filterLevel: 'none'
});
}
// 4. If STILL minimal, fall back to screenshots
if (result.summary.dataQuality === 'minimal') {
// Use screenshot-based approach
}Validate element at tap coordinates
const element = await idbUiDescribeTool({
operation: 'point',
x: 200,
y: 400
});
// Element includes frame coordinates if availableRelated Tools
idb-ui-tap: Tap discovered elements using centerX/centerY coordinates
screenshot: Capture screenshot for visual element identification
idb-ui-find-element: Semantic element search by label/identifier
accessibility-quality-check: Quick assessment before choosing approach
Inputs: operation (required), x, y, deep, +3 more.
idb-ui-find-elementFind UI ElementARead-onlyIdempotent
idb-ui-find-element
Find UI elements by semantic search in accessibility tree - no screenshots needed.
Overview
Queries the accessibility tree and searches for elements matching a label or identifier. Returns matching elements with tap-ready coordinates (centerX, centerY), enabling agents to find specific UI controls without visual analysis. Fast semantic search replaces screenshot-based visual scanning for complex UIs.
Parameters
Required
query (string): Search term to match against element labels or identifiers
Optional
exact (boolean): Exact matching instead of substring matching
elementType (string): Filter by accessibility type; can be used without query
identifier (string): Exact identifier filter; can be used without query
index (integer): Zero-based selection returned as selectedElement
udid (string): Target identifier - auto-detects if omitted
Returns
Array of matching elements with:
Type, label, identifier
Tap-ready coordinates (centerX, centerY)
Full frame boundaries (x, y, width, height)
Returns empty array if no matches found.
Examples
Find login button
const result = await idbUiFindElementTool({
query: 'login'
});Find email field on specific device
const emailField = await idbUiFindElementTool({
query: 'email',
udid: 'DEVICE-UDID'
});Find by identifier partial match
const search = await idbUiFindElementTool({
query: 'submit'
});How It Works
Query accessibility tree: Calls
idb ui describe-all(~80ms)Filter by query: Searches element labels and identifiers (case-insensitive partial match)
Return coordinates: Provides tap-ready centerX/centerY for direct use with idb-ui-tap
Related Tools
accessibility-quality-check: Quick assessment of accessibility data richnessidb-ui-describe: Full accessibility tree with all element detailsidb-ui-tap: Tap elements using coordinatesscreenshot: Visual fallback if accessibility insufficient
Notes
Uses case-insensitive partial matching ("log" matches "Login")
Returns all matching elements (filter in agent logic if needed)
Only returns elements with valid frame coordinates
Much faster than visual analysis (~80ms vs 2000ms for screenshot)
5-6x cheaper token cost (~40 tokens vs ~170 for screenshot)
Inputs: udid, exact, index, query, +2 more.
idb-ui-gesturePerform Gesture / Button PressA
idb-ui-gesture
👆 Perform gestures and hardware button presses - swipes, scrolls, and device controls for navigation
What it does
Executes swipe gestures (directional or custom paths) and hardware button presses on iOS targets. Supports standard swipe directions (up, down, left, right) with automatic screen-relative path calculation using configurable profiles (flick, swipe, drag), custom swipe paths with precise start/end coordinates, and hardware button simulation (HOME, LOCK, SIRI, SCREENSHOT, APP_SWITCH). Automatically validates velocity to ensure iOS recognizes gestures as swipes (>6000 px/sec). Validates coordinates against device bounds and provides semantic action tracking.
Why you'd use it
Automate scroll and navigation gestures - swipe to reveal content, dismiss modals, page through carousels
Use optimized swipe profiles for different UIs - flick for fast page changes, swipe for standard scrolling, drag for slow interactions
Test hardware button interactions without physical device access - home button, lock, app switching
Execute precise custom swipe paths for complex gesture-based UIs (drawing, map navigation)
Track gesture-based test scenarios with semantic metadata (actionName, expectedOutcome)
Scrolling
operation: scroll uses content direction up/down and amount (default 3, maximum 100). refresh performs one downward pull.
Additional gestures
operation also accepts pinch (startX/startY and positive scale), long-press (startX/startY, duration in milliseconds; default 2000), double-tap (startX/startY, count >= 2), drag (start/end coordinates or source/destination accessibility labels), rotate (orientation: portrait, portrait-upside-down, landscape-left, landscape-right), and shake. Newer operations require a supporting idb CLI and companion.
Parameters
Required
operation (string): "swipe" | "button"
Swipe operation parameters
direction (string): "up" | "down" | "left" | "right" - auto-calculates screen-relative path
profile (string, default: "standard"): "standard" | "flick" | "gentle" - gesture profile
startX, startY, endX, endY (numbers): Precise POINT coordinates for custom swipe path
duration (number, default: 200): Swipe duration in MILLISECONDS (e.g., 200 for 200ms) - uses profile default if omitted
Button operation parameters
buttonType (string): "HOME" | "LOCK" | "SIDE_BUTTON" | "APPLE_PAY" | "SIRI" | "SCREENSHOT" | "APP_SWITCH"
Optional
udid (string): Target identifier - auto-detects if omitted
actionName (string): Semantic action name (e.g., "Scroll to Bottom")
expectedOutcome (string): Expected result (e.g., "Reveal footer content")
Swipe Profiles (Empirically Tested)
standard: Default balance (75% distance, 200ms, 1475 points/sec) - perfect for general navigation
flick: Fast page changes (85% distance, 120ms, 2775 points/sec) - use for carousel/rapid navigation
gentle: Slow scrolling (50% distance, 300ms, 653 points/sec) - reliable but near-minimum threshold
All coordinates in POINT space (393×852 for iPhone 16 Pro), NOT pixel space. All profiles tested and verified working on iOS 18.5 home screen.
Complete JSON Examples
Swipe Up (Scroll Down)
{"operation": "swipe", "direction": "up", "profile": "standard", "actionName": "Scroll Down"}Swipe Down (Scroll Up)
{"operation": "swipe", "direction": "down", "profile": "standard", "actionName": "Scroll Up"}Swipe Left (Navigate Forward)
{"operation": "swipe", "direction": "left", "profile": "standard", "actionName": "Go to Next Page"}Swipe Right (Navigate Back)
{"operation": "swipe", "direction": "right", "profile": "standard", "actionName": "Go to Previous Page"}Flick Swipe (Fast Page Navigation)
{"operation": "swipe", "direction": "left", "profile": "flick", "duration": 120, "actionName": "Fast Swipe to Next"}Gentle Swipe (Slow Scrolling)
{"operation": "swipe", "direction": "up", "profile": "gentle", "duration": 300, "actionName": "Slow Scroll Down"}Custom Swipe Path (Precise Coordinates)
{"operation": "swipe", "startX": 196, "startY": 600, "endX": 196, "endY": 200, "duration": 200, "actionName": "Custom Scroll"}Press Home Button
{"operation": "button", "buttonType": "HOME", "actionName": "Background App"}Press Lock Button
{"operation": "button", "buttonType": "LOCK", "actionName": "Lock Device"}Press Side Button
{"operation": "button", "buttonType": "SIDE_BUTTON", "actionName": "Trigger Side Button Action"}Press Siri Button
{"operation": "button", "buttonType": "SIRI", "actionName": "Activate Siri"}Press Screenshot Button
{"operation": "button", "buttonType": "SCREENSHOT", "actionName": "Capture Screenshot"}Press App Switch Button
{"operation": "button", "buttonType": "APP_SWITCH", "actionName": "Show App Switcher"}Returns
Gesture execution status with operation details (direction/button, path coordinates for swipes), duration, velocity info, gesture context metadata, error details if failed, and verification guidance.
Examples
Standard swipe up (default profile)
const result = await idbUiGestureTool({
operation: 'swipe',
direction: 'up',
actionName: 'Scroll to Bottom',
expectedOutcome: 'Reveal footer content'
});Flick swipe for fast page navigation
await idbUiGestureTool({
operation: 'swipe',
direction: 'left',
profile: 'flick',
actionName: 'Go to Next Page'
});Press home button
await idbUiGestureTool({ operation: 'button', buttonType: 'HOME' });Related Tools
idb-ui-tap: For precise element tapping
idb-ui-describe: Find element coordinates
Inputs: operation (required), endX, endY, udid, +13 more.
idb-ui-inputSend Text/Key InputA
idb-ui-input
Hardware key aliases: home, lock/power, side, siri, apple-pay, volume-up/down (volume requires idb 1.6.3+).
⌨️ Input text and keyboard commands - automated text entry and special key presses for form automation
What it does
Sends text input and keyboard commands to focused elements on iOS targets. Types text strings into active text fields, presses special keys (home, return, delete, arrows), and executes key sequences for complex input workflows. Automatically redacts sensitive data (passwords) in responses and provides semantic field context tracking for test documentation.
Why you'd use it
Automate form filling without manual keyboard interaction - login flows, search, data entry
Execute keyboard shortcuts and navigation (tab, return, arrows) for multi-field workflows
Safely handle sensitive data with automatic redaction in tool responses and logs
Track input operations with semantic metadata (actionName, fieldContext, expectedOutcome)
Additional input operations
operation: clear selects all (Command+A) and deletes.
modifiers: shift, control, option, command apply to key/key-sequence events.
key and keySequence accept letters, digits and named keys; sequences send individual HID events.
Parameters
Required
operation (string): "text" | "key" | "key-sequence"
Operation-specific parameters
text (string, required for text operation): String to type into focused field
key (string, required for key operation): Special key name (home, return, delete, tab, arrows, etc.)
keySequence (string[], required for key-sequence operation): Array of key names to press in order
Optional
udid (string): Target identifier - auto-detects if omitted
actionName (string): Semantic action name (e.g., "Enter Email")
fieldContext (string): Field name for context (e.g., "Email TextField")
expectedOutcome (string): Expected result (e.g., "Email field populated")
isSensitive (boolean): Mark as sensitive to redact from output
Returns
Input execution status with operation details (redacted if sensitive), duration, input context metadata for test tracking, error details if failed, and troubleshooting guidance specific to text vs. key operations.
Examples
Type email into focused field
const result = await idbUiInputTool({
operation: 'text',
text: 'user@example.com',
actionName: 'Enter Email',
fieldContext: 'Email TextField'
});Press return to submit
await idbUiInputTool({ operation: 'key', key: 'return' });Related Tools
idb-ui-tap: Tap to focus text fields before typing
idb-ui-describe: Find text field coordinates
Inputs: operation (required), key, text, udid, +6 more.
idb-ui-tapTap UI ElementA
idb-ui-tap
🎯 Tap at coordinates on iOS screen - core UI automation primitive with screenshot coordinate transformation
What it does
Sends precise tap events to iOS targets at specified screen coordinates with automatic coordinate transformation from screenshot space to device space. Supports single tap, double tap, and long press gestures. Validates coordinates against device screen bounds and provides semantic action tracking for test documentation. Works on both simulators and physical devices over USB/WiFi.
Why you'd use it
Automate UI interactions from screenshot analysis - tap elements identified visually
Transform screenshot coordinates automatically when screenshots are resized for token efficiency
Validate tap coordinates against device bounds before execution to prevent out-of-range errors
Track test scenarios with semantic metadata (actionName, expectedOutcome, testScenario, step)
Parameters
Required
x (number): X coordinate (device coords or screenshot coords with applyScreenshotScale)
y (number): Y coordinate (device coords or screenshot coords with applyScreenshotScale)
Optional
udid (string): Target identifier - auto-detects if omitted
numberOfTaps (number, default: 1): Number of taps (set 2 for double-tap)
duration (number): Long press duration in milliseconds
applyScreenshotScale (boolean): Transform screenshot coords to device coords
screenshotScaleX (number): Scale factor for X axis from screenshot-inline
screenshotScaleY (number): Scale factor for Y axis from screenshot-inline
actionName (string): Semantic action name (e.g., "Login Button Tap")
screenContext (string): Screen name for context (e.g., "LoginScreen")
expectedOutcome (string): Expected result (e.g., "Navigate to HomeScreen")
testScenario (string): Test scenario name (e.g., "Happy Path Login")
step (number): Step number in test workflow
Returns
Tap execution status with transformed coordinates, input coordinate details (if transformed), action context metadata for test tracking, error details if failed, and verification guidance.
Examples
Tap from screenshot coordinates (auto-transformed)
const result = await idbUiTapTool({
x: 150, y: 300,
applyScreenshotScale: true,
screenshotScaleX: 2.0, screenshotScaleY: 2.0,
actionName: "Login Button Tap",
expectedOutcome: "Navigate to HomeScreen"
});Related Tools
idb-ui-describe: Discover tappable elements and their coordinates
screenshot: Capture screenshot to identify tap targets
idb-ui-gesture: For swipes and hardware buttons
Inputs: x (required), y (required), step, udid, +9 more.
idb-uninstallUninstall App (IDB)ADestructiveIdempotent
idb-uninstall
Uninstall application from iOS target - remove apps with complete data deletion for clean installs.
Overview
Removes installed applications by bundle ID with complete data and preferences deletion. Automatically terminates running apps before uninstall. Cannot remove system apps (user-installed only). Provides detailed error guidance for common failures (app not found, system app protection, uninstall errors).
Confirmation
confirm: true is required before permanently deleting simulator or app data.
Parameters
Required
bundleId (string): App bundle identifier to uninstall
Optional
udid (string): Target identifier - auto-detects if omitted
Returns
Uninstallation status with success indicator, bundle ID, command output, error details if failed, and troubleshooting guidance (app not found, system app protection, termination advice, alternative tools).
Examples
Uninstall app for clean reinstall
const result = await idbUninstallTool({
bundleId: 'com.example.MyApp'
});Uninstall from specific device
await idbUninstallTool({
bundleId: 'com.example.MyApp',
udid: 'DEVICE-UDID-123'
});Related Tools
idb-install: Reinstall app after uninstall
idb-terminate: Stop app before uninstall (auto-handled)
idb-list-apps: Verify app is removed after uninstall
Notes
Removes app from target system completely
Deletes all app data and preferences
Automatically terminates app if running
Only user-installed apps can be uninstalled (system apps protected)
Clean install testing workflow: uninstall -> install -> test
Inputs: bundleId (required), udid, confirm.
idb-xctest-listList XCTest BundlesARead-onlyIdempotent
idb-xctest-list
List xctest bundles installed on a target, or the tests inside one.
Overview
This is NOT a replacement for xcodebuild-test. It does not build anything: it inspects test
bundles that are already installed on the simulator (put there by idb install of a
.xctest bundle, typically produced by xcodebuild build-for-testing).
Use it to discover what is installed before running tests through idb, or to confirm an install
succeeded. If you just want to run a project's tests, use xcodebuild-test.
Parameters
Optional
udid (string): Target identifier - auto-detects if omitted
testBundleId (string): List the tests inside this bundle instead of listing bundles
Returns
bundles (or tests when testBundleId is given) plus a count. An empty list is normal and means
no test bundle is installed — it is not an error.
Examples
What test bundles are installed?
await idbXctestListTool({});What tests are in one bundle?
await idbXctestListTool({ testBundleId: 'com.example.MyAppUITests.xctrunner' });Related Tools
xcodebuild-test: Build and run a project's tests — the usual choice
idb-install: Install a .xctest bundle so it appears here
idb-list-apps: List regular apps rather than test bundles
Notes
Output parsing is deliberately tolerant: idb has emitted both JSON and plain lines across versions, so both are handled and unrecognised lines are preserved as raw text.
An empty result on a simulator with no installed test bundle is expected.
Inputs: udid, testBundleId.
localization-auditAudit Localization CatalogARead-onlyIdempotent
localization-audit
Audit .xcstrings, .strings, or .stringsdict catalogs for localization gaps, placeholder mismatches, and unused or missing keys relative to Swift source code.
What it does
Pure file analysis — no simulator required. Parses localization catalogs and reports:
Per-locale missing/untranslated keys
Keys with needs_review, new, or stale states
Format-specifier placeholder count mismatches across locales
Keys in Swift source but absent from catalog (missing_from_catalog)
Keys in catalog but absent from Swift source (unused_in_source)
Parameters
catalogPath (string, required): Path to .xcstrings, .strings, or .stringsdict catalog file
sourceDir (string, optional): Swift source root for unused/missing key cross-reference
strict (boolean, optional): Set isError:true in response if any findings are present
verbose (boolean, optional): Include detailed per-key breakdown in summary text
Supported Catalog Formats
.xcstrings: Xcode 15+ JSON catalog with multi-locale support
.strings: Legacy single-locale plist (binary/XML/text format)
.stringsdict: Pluralization rules plist
Returns
JSON response with:
catalogPath,sourceLanguage,totalKeys,localesgaps: array of { key, locale, reason } objectsmissingFromCatalog: keys in Swift source not in catalogunusedInSource: keys in catalog not referenced in Swift sourceplaceholderMismatches: keys where placeholder counts differ across localessummary: compact human-readable summary text
structuredContent: { totalKeys, localeCount, gapCount, placeholderMismatchCount }
Examples
Audit .xcstrings catalog
await localizationAuditTool({
catalogPath: '/path/to/Localizable.xcstrings'
})Full audit with source cross-reference
await localizationAuditTool({
catalogPath: '/path/to/Localizable.xcstrings',
sourceDir: './MyApp',
verbose: true
})Strict mode (error on any findings)
await localizationAuditTool({
catalogPath: '/path/to/Localizable.xcstrings',
strict: true
})Gap Reasons
missing: Key has no translation for that locale
needs_review: Translation exists but marked for review
new: Translation is new and unverified
stale: Translation is outdated relative to source
Placeholder Matching
Extracts printf-style format specifiers (%@, %d, %s, %lld, positional %1$@, etc.) and reports keys where the count differs between source and a target locale. Empty-value locales are skipped (gaps reported separately).
Inputs: catalogPath (required), strict, verbose, sourceDir. Returns: gapCount, totalKeys, localeCount, placeholderMismatchCount
persistence-disableDisable Disk PersistenceAIdempotent
persistence-disable
🔌 Disable persistent state management and return to in-memory-only caching - Turn off persistence.
Safely deactivates file-based persistence and optionally deletes existing cache data files. After disabling, XC-MCP operates with in-memory caching only, losing all learned state on server restart. Useful for privacy requirements, disk space constraints, or troubleshooting cache-related issues.
Advantages
• Meet privacy requirements that prohibit persistent storage • Free up disk space when storage is limited • Switch to CI/CD mode where persistence isn't beneficial • Troubleshoot issues potentially caused by stale cached data
Parameters
Required
(None)
Optional
clearData (boolean): Whether to delete existing cache files when disabling. Defaults to false
Returns
Tool execution results with persistence deactivation confirmation
Confirmation of whether cache files were cleared
Previous storage information (if clearData was true)
Operational effect description
Related Tools
persistence-enable: Turn on persistence
persistence-status: View persistence system status
Notes
Tool is auto-registered with MCP server
Defaults to keeping cache files (just stopping writes)
Set clearData: true to delete all cache files
Operation is immediate and irreversible
Inputs: clearData.
persistence-enableEnable Disk PersistenceAIdempotent
persistence-enable
🔋 Enable opt-in persistent state management for learning across server restarts - Activate persistence.
Activates file-based persistence for XC-MCP's intelligent caching systems. Stores usage patterns, build preferences, simulator performance metrics, and cached responses to disk. Enables the system to learn and improve over time, remembering successful configurations across server restarts. Privacy-first design: NO source code, credentials, or personal information is persisted.
Advantages
• Retain learned build configurations and simulator preferences across restarts • Accelerate repeated workflows by persisting successful operation patterns • Enable team collaboration with shared project-local cache optimizations • Maintain performance insights across CI/CD pipeline runs
Parameters
Required
(None)
Optional
cacheDir (string): Custom directory for cache storage. If omitted, uses intelligent location selection
Returns
Tool execution results with persistence activation confirmation
Cache directory location (resolved or custom)
Storage information and writability status
Privacy notice and next steps
Related Tools
persistence-disable: Turn off persistence
persistence-status: View persistence system status
Notes
Tool is auto-registered with MCP server
Privacy-first design - only patterns and preferences stored
Enables team sharing via project-local cache
Automatically selects best cache location if not specified
Inputs: cacheDir.
persistence-statusPersistence StatusARead-onlyIdempotent
persistence-status
📊 Get comprehensive persistence system status with storage metrics and recommendations - Monitor persistence.
Provides detailed information about the persistence system's current state. Shows whether persistence is enabled, cache directory location, disk usage statistics, file counts, last save timestamps, and intelligent recommendations based on storage health. Essential for monitoring and troubleshooting persistent storage.
Advantages
• Monitor disk space usage and cache file growth over time • Verify persistence is working correctly (check last save timestamps) • Troubleshoot persistence issues (check writability, file counts) • Get actionable recommendations for cache maintenance and optimization
Parameters
Required
(None)
Optional
includeStorageInfo (boolean): Whether to include detailed disk usage and file information. Defaults to true
Returns
Tool execution results with comprehensive persistence status
Enabled/disabled state and schema version
Cache directory location (if enabled)
Storage usage, file count, last save time, writability
Actionable recommendations based on storage state
Related Tools
persistence-enable: Turn on persistence
persistence-disable: Turn off persistence
Notes
Tool is auto-registered with MCP server
Provides intelligent recommendations for health
Set includeStorageInfo: false for lightweight check
Use regularly to monitor cache growth and health
Inputs: includeStorageInfo.
rtfmRead The Manual (Tool Docs)ARead-onlyIdempotent
rtfm
📖 Read The Manual - Progressive disclosure documentation system for all XC-MCP tools.
Overview
The rtfm tool provides access to comprehensive documentation for any of the discrete tools in this MCP server. This implements progressive disclosure: run the server with --mini to reduce every tool description to a one-liner, then call rtfm for full parameters, examples and related tools on demand.
Version History:
v1.x: 51 individual tools; v1.3.2 introduced rtfm
v2.0-v3.x: 28-30 tools behind operation-enum routers
v4.x: routers dissolved; discrete tools with per-tool annotations and outputSchema
Why rtfm?
Problem Solved: Tool documentation was originally stored in .md files within the src/ directory, which wouldn't be available in the published npm package (only dist/ is included in package.json "files" field).
Solution: Documentation is now embedded as TypeScript constants in each tool file, bundled into the compiled JavaScript, and accessible via this rtfm tool. This ensures documentation is always available, whether in development or in the published npm package.
Parameters
toolName (optional): Name of specific tool to get documentation for
Examples: "xcodebuild-build", "simctl-boot", "idb-ui-tap", "cache-get-stats"
Case-sensitive, must match exact tool registration name
categoryName (optional): Browse tools in a specific category
Examples: "build", "simulator", "app", "idb", "cache", "system"
Omit both parameters to see all categories
Examples
// Get documentation for a specific tool
rtfm({ toolName: "simctl-boot" })
// Removed router names still fuzzy-match to their replacements
rtfm({ toolName: "simctl-device" })
// Browse all tools in the cache category
rtfm({ categoryName: "cache" })
// View all categories (no parameters)
rtfm({})Migration to v4.0 (routers removed)
v2/v3 consolidated routers were dissolved back into discrete tools. Annotations and
outputSchema are per-tool, so each operation is now its own tool. Drop the operation field and
call the matching tool name — operation-specific parameters are unchanged:
simctl-device(operation) →
simctl-boot,simctl-shutdown,simctl-create,simctl-delete,simctl-erase,simctl-clone,simctl-renamesimctl-app(operation) →
simctl-install,simctl-uninstall,simctl-launch,simctl-terminateidb-app(operation) →
idb-install,idb-uninstall,idb-launch,idb-terminatecache(operation) →
cache-get-stats,cache-get-config,cache-set-config,cache-clearpersistence(operation) →
persistence-enable,persistence-disable,persistence-status
idb-targets keeps its operation enum (list/describe/focus/connect/disconnect). Passing a removed
router name to this tool returns fuzzy suggestions for its replacements.
Response Format
Success Response
Returns full markdown documentation including:
Tool description and purpose
Advantages over direct CLI usage
Parameter specifications with types and descriptions
Usage examples
Related tools
Common patterns and best practices
Tool Not Found Response
If toolName doesn't match any registered tool:
Error message with the attempted tool name
Suggestions based on partial matches (up to 5)
Complete list of all available tools
Example:
No documentation found for tool: "simctl-boo"
Did you mean one of these?
- simctl-boot
- simctl-shutdown
Available tools (28 total):
- xcodebuild-*
- simctl-*
- idb-*
- cache
- persistence
- rtfmAvailable Tool Categories (v2.0)
Xcodebuild Tools (7)
xcodebuild-version, xcodebuild-list, xcodebuild-showsdks
xcodebuild-build, xcodebuild-clean, xcodebuild-test
xcodebuild-get-details
Simctl Lifecycle Tools
simctl-list, simctl-get-details, simctl-boot, simctl-shutdown, simctl-create, simctl-delete, simctl-erase, simctl-clone, simctl-rename
simctl-suggest, simctl-health-check
Simctl App Management Tools
simctl-install, simctl-uninstall, simctl-launch, simctl-terminate
simctl-get-app-container, simctl-container, simctl-openurl
Simctl I/O & Testing Tools (7)
simctl-io, simctl-addmedia, simctl-privacy, simctl-push
simctl-pbcopy, simctl-status-bar, screenshot
IDB Tools
idb-targets (list/describe/focus/connect/disconnect)
idb-ui-tap, idb-ui-input, idb-ui-gesture, idb-ui-describe, idb-ui-find-element, idb-list-apps
idb-install, idb-uninstall, idb-launch, idb-terminate
Cache Management Tools (4)
cache-get-stats, cache-get-config, cache-set-config, cache-clear
Persistence Tools (3)
persistence-enable, persistence-disable, persistence-status
Documentation Tool (1)
rtfm (this tool!)
Implementation Details
Documentation Storage
Each tool file exports a TOOL_NAME_DOCS constant containing its full documentation in markdown format:
// Example from src/tools/simctl/boot.ts
export const SIMCTL_BOOT_DOCS = `
# simctl-boot
...
`;Central Registry
All documentation constants are imported and mapped in src/tools/docs-registry.ts:
export const TOOL_DOCS: Record<string, string> = {
'simctl-boot': SIMCTL_BOOT_DOCS,
'xcodebuild-build': XCODEBUILD_BUILD_DOCS,
// ... 49 more tools
};Progressive Disclosure Pattern
Tool list shows concise descriptions (~300-400 tokens)
Each description ends with: "📖 Use rtfm with toolName: '{name}' for full documentation."
Full documentation accessed only when explicitly requested via rtfm
Prevents token overflow while maintaining comprehensive documentation access
Benefits
✅ Self-contained: No external file dependencies ✅ NPM package ready: Documentation bundled in compiled JavaScript ✅ Token efficient: Progressive disclosure keeps default views concise ✅ Always available: Works in development and production ✅ Type-safe: TypeScript constants with proper typing ✅ Searchable: Fuzzy matching with suggestions for typos ✅ Comprehensive: Full documentation including examples and parameters
Common Use Cases
Explore available tools:
// Intentionally use invalid tool name to see full list
rtfm({ toolName: "help" })Learn specific tool usage:
rtfm({ toolName: "simctl-boot" })Understand tool parameters:
rtfm({ toolName: "xcodebuild-build" })Find related tools:
// Search by category prefix
rtfm({ toolName: "simctl" }) // Shows simctl-* suggestionsRelated Tools
cache-get-stats: Monitor cache performance and usage
Notes
Tool names are case-sensitive and must match exact registration names
Fuzzy matching provides suggestions for close matches
Documentation format is consistent markdown across all tools
Each tool's documentation is independently maintained in its source file
The TOOL_DOCS registry is automatically updated when tools are added/removed
Inputs: toolName, categoryName.
screenshotInline Simulator ScreenshotARead-onlyIdempotent
simctl-screenshot-inline
Capture optimized screenshots with inline base64 encoding for direct MCP response transmission.
What it does
Captures simulator screenshots and returns them as base64-encoded images directly in the MCP response. Automatically optimizes images for token efficiency with tile-aligned resizing and WebP/JPEG compression. Includes interactive element detection and coordinate transforms.
Parameters
udid (string, optional): Simulator UDID (auto-detects booted device if omitted)
size (string, optional): Screenshot size - half, full, quarter, thumb (default: half)
appName (string, optional): App name for semantic context
screenName (string, optional): Screen/view name for semantic context
state (string, optional): UI state for semantic context
enableCoordinateCaching (boolean, optional): Enable view fingerprinting for coordinate caching
Screenshot Size Optimization
Automatically optimizes screenshots for token efficiency:
half (default): 256×512 pixels, 1 tile, ~170 tokens (50% savings)
full: Native resolution, 2 tiles, ~340 tokens
quarter: 128×256 pixels, 1 tile, ~170 tokens
thumb: 128×128 pixels, 1 tile, ~170 tokens
Automatic Optimization Process
Capture: Screenshot taken at native resolution
Resize: Automatically resized to tile-aligned dimensions (unless size='full')
Compress: Converted to WebP format at 60% quality (falls back to JPEG if unavailable)
Encode: Base64-encoded for inline MCP response transmission
Extract: Interactive elements detected from accessibility tree
Transform: Coordinate mapping provided for resized screenshots
Returns
MCP response with:
Base64-encoded optimized image (inline)
Screenshot optimization metadata (dimensions, tokens, savings)
Interactive elements with coordinates and properties
Coordinate transform for mapping screenshot to device coordinates
View fingerprint (if enableCoordinateCaching is true)
Semantic metadata (if provided)
Examples
Simple optimized screenshot (256×512)
await simctlScreenshotInlineTool({
udid: 'device-123'
})Full resolution screenshot
await simctlScreenshotInlineTool({
udid: 'device-123',
size: 'full'
})Screenshot with semantic context
await simctlScreenshotInlineTool({
udid: 'device-123',
appName: 'MyApp',
screenName: 'LoginScreen',
state: 'Empty'
})Screenshot with coordinate caching enabled
await simctlScreenshotInlineTool({
udid: 'device-123',
enableCoordinateCaching: true
})Interactive Element Detection
Automatically extracts interactive elements from the accessibility tree:
Element type (Button, TextField, etc.)
Label and identifier
Bounds (x, y, width, height)
Tappability status
Limited to top 20 elements to avoid token overflow. Elements are filtered to only include those with bounds and hittable status.
Coordinate Transform
When screenshots are resized (size ≠ 'full'), provides automatic coordinate transformation:
Automatic Transformation (Recommended for Agents)
Use the coordinateTransformHelper field in the response with idb-ui-tap:
Identify element coordinates visually from the screenshot
Call idb-ui-tap with applyScreenshotScale: true plus scale factors
The tool automatically transforms screenshot coordinates to device coordinates
Example:
idb-ui-tap {
x: 256, // Screenshot coordinate
y: 512, // Screenshot coordinate
applyScreenshotScale: true,
screenshotScaleX: 1.67,
screenshotScaleY: 1.66
}
// Tool automatically calculates: deviceX = 256 * 1.67, deviceY = 512 * 1.66Manual Transformation (For Reference)
If not using automatic transformation:
scaleX: Multiply screenshot X coordinates by this to get device coordinates
scaleY: Multiply screenshot Y coordinates by this to get device coordinates
coordinateTransform.guidance: Human-readable instructions
Important: Most agents should use the automatic transformation via idb-ui-tap's applyScreenshotScale parameter. Manual calculation is provided for reference only.
View Fingerprinting (Opt-in)
When enableCoordinateCaching is true, computes a structural hash of the view:
elementStructureHash: SHA-256 hash of element hierarchy
cacheable: Whether view is stable enough to cache coordinates
elementCount: Number of elements in hierarchy
orientation: Device orientation
Excludes loading states, animations, and dynamic content from caching.
Common Use Cases
Visual analysis: LLM-based screenshot analysis with token optimization
UI automation: Detect interactive elements and get tap coordinates
Bug reporting: Capture and transmit screenshots inline
Test documentation: Screenshot with semantic context for test tracking
Coordinate caching: Store element coordinates for repeated interactions
Token Efficiency
Screenshots are optimized for minimal token usage:
Default (half): ~170 tokens (50% savings vs full)
Full: ~340 tokens (native resolution)
Quarter: ~170 tokens (75% savings vs full)
Thumb: ~170 tokens (smallest, for thumbnails)
Token counts are estimates based on Claude's image processing (170 tokens per 512×512 tile).
Important Notes
Auto-detection: If udid is omitted, uses the currently booted device
Temp files: Uses temp directory for processing, auto-cleans up
WebP fallback: Attempts WebP compression, falls back to JPEG if unavailable
Element extraction: Requires app to be running with accessibility enabled
Coordinate accuracy: Transform provides pixel-perfect coordinate mapping
Error Handling
Simulator not found: Validates simulator exists in cache
Simulator not booted: Indicates simulator must be booted first
Capture failure: Reports if screenshot capture fails
Optimization failure: Falls back to original if optimization fails
Element extraction: Gracefully degrades if accessibility is unavailable
Next Steps After Screenshot
Analyze visually: LLM processes inline image for visual analysis
Interact with elements: Use coordinates from interactiveElements
Tap elements: Apply coordinate transform if resized, then use simctl-tap
Query specific elements: Use simctl-query-ui for targeted element discovery
Cache coordinates: Store fingerprint for reuse on identical views
Comparison with simctl-io
Feature | screenshot-inline | simctl-io |
Returns | Base64 inline | File path |
Optimization | Automatic | Manual |
Elements | Auto-detected | Not included |
Transform | Included | Included |
Use case | MCP responses | File storage |
Token usage | Optimized | Depends on size |
Inputs: size, udid, state, appName, +2 more.
simctl-addmediaAdd Media to SimulatorA
simctl-addmedia
Add media files (photos and videos) to a simulator's photo library for testing.
What it does
Adds image or video files to the simulator's Photos app, making them available for apps to access via PHPhotoLibrary or UIImagePickerController APIs.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
mediaPaths (string array, optional): Add multiple existing files in one invocation; all paths checked before mutation
mediaPath (string, required unless mediaPaths provided): Path to image or video file
Supported Formats
Images: jpg, jpeg, png, heic, gif, bmp Videos: mp4, mov, avi, mkv
Returns
JSON response with:
Media addition status
Media type and format detected
Guidance for viewing in Photos app and adding more media
Examples
Add image to photo library
await simctlAddmediaTool({
udid: 'device-123',
mediaPath: '/path/to/photo.jpg'
})Add video to photo library
await simctlAddmediaTool({
udid: 'device-123',
mediaPath: '/path/to/video.mp4'
})Common Use Cases
Photo picker testing: Add test images for UIImagePickerController testing
PHPhotoLibrary testing: Populate library for photo access API testing
Image processing: Add images to test filters, crops, and transformations
Video playback: Add videos to test AVPlayer integration
Camera roll simulation: Populate library to simulate real user photo collection
Important Notes
File must exist: Validates file exists before attempting to add
Format validation: Only supported image/video formats are accepted
Simulator state: Works on both booted and shutdown simulators
Photos app: Media appears in simulator's Photos app immediately
Metadata: Original file metadata (EXIF, date, etc.) is preserved
Error Handling
File not found: Error if media file path doesn't exist
Unsupported format: Error if file extension is not in supported list
Simulator not found: Validates simulator exists in cache
Addition failure: Reports simctl errors if media cannot be added
Next Steps After Adding Media
View in Photos app:
simctl-launch <udid> com.apple.mobileslideshowTest photo picker: Launch your app and open UIImagePickerController
Add more media: Repeat with different images/videos
Test PHPhotoLibrary: Use PHPhotoLibrary.requestAuthorization() in your app
Testing Workflow
Grant photo permissions:
simctl-privacy <udid> <bundleId> grant photosAdd test media:
simctl-addmedia <udid> /path/to/photo.jpgLaunch app:
simctl-launch <udid> <bundleId>Test photo access: Verify app can read from photo library
Take screenshot:
simctl-io <udid> screenshotto verify UI
Tips
Test image formats: Add different image formats (JPEG, PNG, HEIC) to test compatibility
Test video formats: Add various video formats (MP4, MOV) to test playback
Large files: Be aware that adding large video files may take time
Batch addition: Add multiple files to simulate realistic photo library
Inputs: udid (required), mediaPath, mediaPaths.
simctl-appearanceSet Simulator Appearance/LocaleAIdempotent
simctl-appearance
Control iOS simulator appearance: theme (light/dark), dynamic type size, locale, and region.
What it does
Wraps xcrun simctl ui and xcrun simctl spawn defaults write to let you switch
appearance settings on a running simulator without leaving your terminal or MCP session.
Contrast
contrast: high or normal sets increase_contrast and verifies it by reading the setting back. reset also restores normal contrast.
Parameters
udid (string, optional): Simulator UDID. Auto-detects booted simulator if omitted.
theme ('light' | 'dark', optional): Switch light/dark appearance.
textSize (string, optional): Dynamic type size alias (XS–AX5, see table below).
locale (string, optional): BCP-47 language code (e.g.
en,ar,de).region (string, optional): ISO 3166-1 alpha-2 region code (e.g.
US,SA). Requireslocale.bundleId (string, optional): App bundle ID — terminate + relaunch after locale change. Requires
locale.reset (boolean, optional): Reset theme, text size, and locale to system defaults (light / M / en_US). Incompatible with other flags.
Text Size Aliases
Alias | xcrun token |
XS | extra-small |
S | small |
M | medium (default) |
L | large |
XL | extra-large |
XXL | extra-extra-large |
XXXL | extra-extra-extra-large |
AX1 | accessibility-medium |
AX2 | accessibility-large |
AX3 | accessibility-extra-large |
AX4 | accessibility-extra-extra-large |
AX5 | accessibility-extra-extra-extra-large |
RTL Locales
Locales starting with ar, he, fa, ur, or yi are flagged as RTL.
The response includes a [RTL layout] note and guidance to verify RTL support.
Returns
JSON response with:
success: overall operation successudid: resolved simulator UDIDresults: per-operation{ success, message }objects (theme, textSize, locale, or reset)guidance: next-step suggestions
Examples
Switch to dark mode
await simctlAppearanceTool({ theme: 'dark' })Set large dynamic type
await simctlAppearanceTool({ textSize: 'AX3' })Set Arabic locale (Saudi Arabia) and restart app
await simctlAppearanceTool({
locale: 'ar',
region: 'SA',
bundleId: 'com.myapp.ios',
})Combine theme and text size
await simctlAppearanceTool({ theme: 'dark', textSize: 'XL' })Reset all appearance to defaults
await simctlAppearanceTool({ reset: true })Validation Rules
At least one of
theme,textSize,locale, orresetmust be provided.resetcannot be combined withtheme,textSize, orlocale.regionrequireslocale.bundleIdrequireslocale.
Important Notes
The simulator must be booted for commands to succeed.
Locale changes apply on the next cold app launch unless
bundleIdis provided.Multiple operations can be combined in a single call (e.g.,
theme+textSize).
Inputs: udid, reset, theme, locale, +4 more.
simctl-bootBoot SimulatorAIdempotent
simctl-boot
⚡ Prefer this over 'xcrun simctl boot' - Intelligent boot with performance tracking and learning.
Advantages over direct CLI
• 📊 Performance tracking - Records boot times for optimization insights • 🧠 Learning system - Tracks which devices work best for your projects • 🎯 Smart recommendations - Future builds suggest fastest/most reliable devices • 🛡️ Better error handling - Clear feedback vs cryptic CLI errors • ⏱️ Wait management - Intelligent waiting for complete boot vs guessing
Automatically tracks boot times and device performance metrics for optimization. Records usage patterns for intelligent device suggestions in future builds.
Batch selection
Use all:true or deviceType/runtime filters instead of deviceId. Batch operations target available simulators; erase/delete require confirm:true. Results report each attempted device independently.
Parameters
Required
deviceId(string): Device UDID (from simctl-list) or "booted" for any currently booted device
Optional
waitForBoot(boolean, default: true): Wait for device to finish booting completelyopenGui(boolean, default: true): Open Simulator.app GUI automatically
Returns
Success response includes:
Boot status (success/failure)
Device information
Boot time in milliseconds
Performance metrics
Guidance for next steps
Examples
Boot a specific device
{
"deviceId": "ABC123DEF-GHIJ-KLMN-OPQR-STUVWXYZ1234",
"waitForBoot": true
}Boot any available device quickly
{
"deviceId": "booted",
"waitForBoot": false,
"openGui": false
}Related Tools
simctl-list- Discover available simulators and their UDIDssimctl-suggest- Get intelligent device recommendations based on historysimctl-shutdown- Shut down booted devicessimctl-health-check- Verify simulator environment health
Device Support
Simulators: Full support ✅
Physical Devices: Not applicable (devices don't have simctl boot)
Notes
Handles "already booted" case gracefully (treats as success)
Tracks boot performance for future optimization recommendations
First boot of a device type may take longer than subsequent boots
Opening GUI with
openGui: trueprovides visual feedback but increases boot time slightly
Inputs: all, openGui, runtime, deviceId, +2 more.
simctl-cloneClone SimulatorA
simctl-clone
Clone iOS simulator devices with complete state preservation.
Overview
Creates an exact duplicate of an existing simulator including all settings, installed apps, and current state. The cloned simulator gets a new UDID but preserves all configuration. Useful for creating backups of configured simulators before experiments or maintaining multiple test variants.
Parameters
Required
deviceId (string): Source device UDID to clone (from simctl-list)
newName (string): Display name for the cloned simulator
Returns
Clone status with both source and new device information, including new UDID, success indicator, command output, and guidance for managing the cloned device.
Examples
Clone simulator for testing
await simctlCloneTool({
deviceId: 'ABC-123-DEF',
newName: 'TestDevice-Snapshot'
});Create backup before experiments
await simctlCloneTool({
deviceId: 'PRODUCTION-UDID',
newName: 'Production Test Backup'
});Related Tools
simctl-list: Find source device UDID to clone
simctl-boot: Boot cloned device after creation
simctl-delete: Remove cloned device when no longer needed
Notes
Cloned device includes all apps and data from source
New UDID is generated automatically
Cloning can take 1-2 minutes depending on data size
Source device name and configuration are preserved
Device can be in any state (booted, shutdown) during clone
Inputs: newName (required), deviceId (required).
simctl-containerInspect App Sandbox ContainerARead-onlyIdempotent
simctl-container
App sandbox inspector — list files, read file contents, inspect UserDefaults, and locate Core Data stores inside an iOS simulator app's data container.
What it does
Resolves the app data container via xcrun simctl get_app_container, then performs semantic
file operations within that sandbox without needing to know the raw CoreSimulator path.
Parameters
bundleId (string, required): App bundle identifier (e.g. com.example.MyApp)
mode (string, required): Operation —
ls|cat|userdefaults|coredata-pathudid (string, optional): Simulator UDID. Defaults to booted device.
path (string, optional): Sub-path for
ls(subdir) or file path forcatdepth (number, optional): Recursion depth for
ls(default: 3)
Modes
ls
Lists files in the container (or a sub-path) up to depth levels deep.
Returns entries with path, kind (file/dir/symlink), and sizeBytes.
Path traversal outside the container root is rejected.
cat
Reads a file at path (relative to container root).
Attempts plist decode first (binary and XML plists via
plutil)Falls back to UTF-8 text, then binary detection
Returns
contentType:plist|text|binaryFiles > 8 KB (text/plist) are stored in responseCache; returns
cacheId+resourceLink
export
Copies the data container to destination/BUNDLE_ID. Requires destination; refuses to overwrite an existing export.
userdefaults
Reads Library/Preferences/<bundleId>.plist and returns decoded key/value pairs.
Handles both binary and XML plist formats via plutil.
coredata-path
Searches Library/Application Support/ and Documents/ recursively for
.sqlite, .sqlite-wal, and .sqlite-shm files.
Returns { path, absolutePath, sizeBytes, type } for each store found.
Returns
JSON response with { mode, bundleId, success, ... } plus mode-specific fields and guidance.
Examples
List container root
await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'ls' })List a sub-directory
await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'ls', path: 'Library/Caches' })Read a JSON config file
await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'cat', path: 'Documents/config.json' })Inspect UserDefaults
await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'userdefaults' })Find Core Data stores
await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'coredata-path' })Error Handling
bundleId required: Rejects empty or missing bundleId
mode required: Rejects unknown or missing mode
path required for cat: Rejects cat without a path
container not found: InternalError with install suggestion
path escapes container: InvalidRequest with clear message
plist unreadable: InternalError with path context
Notes
Keychain is explicitly out of scope
Binary plist decoding uses
plutil -convert json(macOS built-in)Large text/plist files (> 8 KB) are cached; retrieve via
cacheIdusing the cache tool
Inputs: mode (required), bundleId (required), path, udid, +2 more.
simctl-createCreate SimulatorA
simctl-create
Create new iOS simulator devices dynamically.
Overview
Creates a new iOS simulator device with specified device type and runtime version. Automatically validates device types and runtimes against available options, defaulting to the latest iOS version if no runtime is specified. Supports all device types including iPhone, iPad, Apple Watch, and Apple TV.
Parameters
Required
name (string): Display name for the new simulator (e.g., "MyTestDevice")
deviceType (string): Device type identifier (e.g., "iPhone 16 Pro", "iPad Pro")
Optional
runtime (string): iOS/runtime version (e.g., "17.0") - defaults to latest available
Returns
Creation status with new device UDID, device type, runtime version, success indicator, command output, and guidance for next steps (boot, delete, erase).
Examples
Create iPhone with latest iOS
await simctlCreateTool({
name: "TestiPhone",
deviceType: "iPhone 16 Pro"
});Create iPad with specific iOS version
await simctlCreateTool({
name: "TestiPad",
deviceType: "iPad Pro (12.9-inch)",
runtime: "17.0"
});Related Tools
simctl-list: See available device types and runtimes
simctl-boot: Boot newly created device
simctl-delete: Remove created device when done
Notes
Device types: iPhone, iPad, Apple Watch, Apple TV
Runtime defaults to latest available iOS version
Created device persists until explicitly deleted
UDID is auto-generated and returned in response
Useful for CI/CD pipelines and automated testing
Device type can be partial match (e.g., "iPhone 16" matches "iPhone 16 Pro")
Inputs: name (required), deviceType (required), runtime.
simctl-deleteDelete SimulatorADestructiveIdempotent
simctl-delete
Permanently delete iOS simulator devices.
Overview
Permanently removes a simulator device and all its data from the system. This action cannot be undone. The simulator must be shut down before deletion. Useful for cleaning up unused simulators to save disk space (simulators can be 5-10GB each).
Confirmation
confirm: true is required before permanently deleting simulator or app data.
Batch selection
Use all:true or deviceType/runtime filters instead of deviceId. Batch operations target available simulators; erase/delete require confirm:true. Results report each attempted device independently.
Parameters
Required
deviceId (string): Device UDID to delete (from simctl-list)
Returns
Deletion status with device information, confirmation that action is permanent, success indicator, command output, and guidance emphasizing permanent nature of deletion.
Examples
Delete specific simulator
await simctlDeleteTool({ deviceId: 'ABC-123-DEF' });Clean up old test device
await simctlDeleteTool({ deviceId: 'OLD-TEST-DEVICE-UDID' });Related Tools
simctl-list: Find device UDID to delete
simctl-shutdown: Shutdown device before deletion (required)
simctl-create: Create new simulator after deletion
Notes
This action cannot be undone - device and all data permanently removed
Device must be shut down before deletion (safety check)
Simulators can be 5-10GB each - deletion frees significant disk space
Use simctl-erase instead if you want to keep device but reset state
Fast operation - completes in seconds
Inputs: all, confirm, runtime, deviceId, +1 more.
simctl-eraseErase Simulator (Factory Reset)ADestructiveIdempotent
simctl-erase
Reset iOS simulator devices to factory settings.
Overview
Resets a simulator to clean factory state without deleting the device itself. All apps and data are removed, but the simulator persists and can be immediately reused. Useful for clean state testing and fresh app installation workflows.
Confirmation
confirm: true is required before permanently deleting simulator or app data.
Batch selection
Use all:true or deviceType/runtime filters instead of deviceId. Batch operations target available simulators; erase/delete require confirm:true. Results report each attempted device independently.
Parameters
Required
deviceId (string): Device UDID to erase (from simctl-list)
Optional
force (boolean, default: false): Force erase even if device is booted
Returns
Erase status with device information, confirmation that device persists, wasBooted flag indicating if device was running during erase, success indicator, and guidance for next steps.
Examples
Erase simulator to clean state
await simctlEraseTool({ deviceId: 'ABC-123-DEF' });Force erase booted device
await simctlEraseTool({
deviceId: 'ABC-123-DEF',
force: true
});Related Tools
simctl-list: Find device UDID to erase
simctl-shutdown: Shutdown device before erase (if not using force)
simctl-boot: Boot device after erase to continue testing
Notes
Device persists after erase - only data is removed
All apps, preferences, and user data are deleted
Device returns to factory settings
Use force: true to erase booted device (otherwise must shutdown first)
Perfect for repeatable clean state testing
Faster than delete + create for reset workflows
Inputs: all, force, confirm, runtime, +2 more.
simctl-get-app-containerGet App Container PathARead-onlyIdempotent
simctl-get-app-container
Access iOS app file system containers for inspection and debugging.
What it does
Retrieves the file system path to an app's container directories on a simulator, enabling direct access to app bundle, data directories, and shared group containers for debugging and testing.
Why you'd use it
Debug data access: Inspect app Documents and Library folders
File inspection: View database files, preferences, and cached data
Testing validation: Confirm app writes data to correct locations
Container types: Access bundle (app binary), data (Documents/Library), and group (shared) containers
Parameters
udid (string, required): Simulator UDID (from simctl-list)
bundleId (string, required): App bundle ID (e.g., com.example.MyApp)
containerType (string, optional): Container type - bundle, data, or group (default: data)
Container Types
bundle: App binary and resources (read-only)
data: App's Documents and Library directories (read-write)
group: Shared containers for app groups (read-write)
Returns
JSON response with:
Container path for file system access
Container type information
Guidance for accessing and inspecting files
Simulator state and validation
Examples
Get app data container path
await simctlGetAppContainerTool({
udid: 'ABC-123-DEF',
bundleId: 'com.example.MyApp'
})Get app bundle path
await simctlGetAppContainerTool({
udid: 'ABC-123-DEF',
bundleId: 'com.example.MyApp',
containerType: 'bundle'
})Common Use Cases
Debugging data persistence: Access app's Documents folder to inspect saved files
Database inspection: View SQLite database files and validate schema
Preferences debugging: Check UserDefaults plist files
Cache validation: Verify cached data is stored correctly
Bundle inspection: Access app binary and embedded resources
Error Handling
App not installed: Returns error if app is not installed on simulator
Invalid bundle ID: Validates bundle ID format (must contain '.')
Simulator not found: Validates simulator exists in cache
Container access failure: Reports if container cannot be accessed
Next Steps After Getting Container Path
View files:
cd "<container-path>" && ls -laOpen in Finder:
open "<container-path>/Documents"Find files:
find "<container-path>" -type f | head -20Inspect specific file:
cat "<container-path>/Documents/data.json"
Inputs: udid (required), bundleId (required), containerType.
simctl-get-detailsGet Simulator List DetailsARead-onlyIdempotent
simctl-get-details
🔍 Get detailed simulator information from cached list results - Progressive disclosure for devices.
Retrieves on-demand access to full simulator and runtime lists that were cached during simctl-list execution. Implements progressive disclosure pattern: initial simctl-list responses return concise summaries to prevent token overflow, while this tool allows drilling down into full device lists, filtered by device type or runtime when needed.
Advantages
• Access full device lists without cluttering initial responses • Filter to specific device types (iPhone, iPad, etc.) • Filter to specific runtime versions • Get only available (booted) devices or all devices • Paginate results to manage token consumption
Parameters
Required
cacheId (string): Cache ID from simctl-list response
Optional
detailType (string): Type of details to retrieve
"full-list": Complete device and runtime information
"devices-only": Just device information
"runtimes-only": Just available runtimes
"available-only": Only booted devices
deviceType (string): Filter by device type (iPhone, iPad, etc.)
runtime (string): Filter by iOS runtime version
maxDevices (number): Maximum number of devices to return (default: 20)
Returns
Tool execution results with detailed simulator information
Complete device lists with full state and capabilities
Available devices and compatible runtimes
Related Tools
simctl-list: List available simulators and runtimes
xcodebuild-get-details: Get build or test details
Notes
Tool is auto-registered with MCP server
Requires valid cache ID from recent simctl-list
Cache IDs expire after 1 hour
Use for discovering available devices and runtimes
Inputs: cacheId (required), detailType (required), runtime, deviceType, +1 more.
simctl-health-checkSimulator Environment Health CheckARead-onlyIdempotent
simctl-health-check
Comprehensive iOS simulator environment health check.
Overview
Performs a complete diagnostic check of your iOS development environment, validating Xcode tools, simulators, runtimes, and disk space. Returns actionable recommendations for any issues found. Checks 6 critical areas in seconds: Xcode Command Line Tools, simctl availability, available simulators, booted simulators, available runtimes, and disk space.
Parameters
None - performs complete environment check automatically.
Returns
Health report with pass/fail status for each check, specific guidance for failures, summary of passed/failed checks, and overall healthy status indicator.
Examples
Run complete health check
await simctlHealthCheckTool();Check before CI/CD pipeline
// Validate environment before running test suite
const health = await simctlHealthCheckTool();
if (!health.healthy) {
console.error('Environment issues detected');
}Related Tools
simctl-list: See available simulators after health check passes
simctl-create: Create simulators if none found
simctl-suggest: Get intelligent simulator recommendations
Notes
Checks 6 critical areas: Xcode tools, simctl, simulators, booted devices, runtimes, disk space
Provides specific solutions for each failed check
Validates entire toolchain in seconds
Warns if disk usage over 80% (simulators require significant space)
Perfect for troubleshooting when operations fail unexpectedly
Use before CI/CD pipeline execution to ensure environment health
Inputs: no named parameters.
simctl-installInstall App on SimulatorAIdempotent
simctl-install
Install iOS apps to simulators for testing.
Overview
Installs a built .app bundle to a simulator device, making it available for launching and testing. Validates the app bundle format and simulator state before installation. Fast installation completes in seconds for quick test iterations.
Parameters
Required
udid (string): Simulator UDID (from simctl-list)
appPath (string): Path to .app bundle (e.g., /path/to/MyApp.app)
Returns
Installation status with app name, simulator info (name, state, availability), success indicator, command output, and guidance for next steps (launch, get container, uninstall).
Examples
Install from Xcode build output
await simctlInstallTool({
udid: 'ABC-123-DEF',
appPath: '/Users/dev/Library/Developer/Xcode/DerivedData/MyApp-xxx/Build/Products/Debug-iphonesimulator/MyApp.app'
});Install to specific simulator
await simctlInstallTool({
udid: 'TEST-DEVICE-UDID',
appPath: '/path/to/MyApp.app'
});Related Tools
simctl-launch: Launch installed app
simctl-uninstall: Remove app from simulator
simctl-get-app-container: Get app filesystem container path
Notes
App path must point to .app bundle (not .ipa)
Fast installation - completes in seconds
Validates app bundle format and simulator state
Extracts app name from bundle path automatically
Deploys built apps directly from Xcode DerivedData
Use for quick test iterations and automated test pipelines
Inputs: udid (required), appPath (required).
simctl-ioSimulator Screenshot/Video CaptureA
simctl-io
Capture screenshots or record videos from iOS simulators with automatic optimization.
What it does
Captures simulator screen as optimized PNG images or records video with configurable codecs. Screenshots are automatically resized to tile-aligned dimensions for token efficiency and support semantic naming for AI agent reasoning.
Parameters
udid (string, optional): Simulator UDID (auto-detects booted device if omitted)
operation (string, required): "screenshot" or "video"
outputPath (string, optional): Custom file path (auto-generated if omitted)
codec (string, optional): Video codec - h264, hevc, or prores (default: h264)
size (string, optional): Screenshot size - half, full, quarter, thumb (default: half)
appName (string, optional): App name for semantic naming
screenName (string, optional): Screen/view name for semantic naming
state (string, optional): UI state for semantic naming
Screenshot Size Optimization
Screenshots are automatically optimized for token efficiency:
half (default): 256×512 pixels, 1 tile, 170 tokens (50% savings)
full: Native resolution, 2 tiles, 340 tokens
quarter: 128×256 pixels, 1 tile, 170 tokens
thumb: 128×128 pixels, 1 tile, 170 tokens
Semantic Naming (LLM Optimization)
Provide appName, screenName, and state to generate semantic filenames:
Format:
{appName}_{screenName}_{state}_{date}.pngExample:
MyApp_LoginScreen_Empty_2025-01-23.pngEnables AI agents to reason about screen context and track state progression
Returns
JSON response with:
File path and size information
Screenshot optimization metadata (dimensions, token count, savings)
Coordinate transform for mapping resized coordinates to device
Semantic metadata when provided
Guidance for viewing and using the capture
Examples
Capture optimized screenshot (default 256×512)
await simctlIoTool({
udid: 'device-123',
operation: 'screenshot'
})Capture full-size screenshot
await simctlIoTool({
udid: 'device-123',
operation: 'screenshot',
size: 'full'
})Capture with semantic naming
await simctlIoTool({
udid: 'device-123',
operation: 'screenshot',
appName: 'MyApp',
screenName: 'LoginScreen',
state: 'Empty'
})Record video with custom codec
await simctlIoTool({
udid: 'device-123',
operation: 'video',
codec: 'hevc'
})Common Use Cases
UI testing: Capture screenshots for visual regression testing
Bug reporting: Record videos demonstrating issues
Documentation: Create screenshots for app documentation
State tracking: Use semantic naming to track UI state progression
Token optimization: Use half/quarter sizes for LLM-based analysis
Coordinate Transform
When screenshots are resized (size ≠ 'full'), a coordinate transform is provided:
scaleX: Multiply screenshot X coordinates by this to get device coordinates
scaleY: Multiply screenshot Y coordinates by this to get device coordinates
guidance: Human-readable scaling instructions
This enables accurate element tapping even with optimized screenshots.
Important Notes
Auto-detection: If udid is omitted, automatically uses the booted device
Temp files: Screenshots saved to /tmp unless custom path specified
Video recording: Press Ctrl+C to stop video recording
Simulator must be booted: Operations require running simulator
File permissions: Ensure output path is writable
Error Handling
Simulator not booted: Indicates simulator must be booted first
Simulator not found: Validates simulator exists in cache
File path errors: Reports if output path is not writable
Invalid operation: Validates operation is "screenshot" or "video"
Next Steps After Capture
View screenshot:
open "<file-path>"Copy to clipboard:
pbcopy < "<file-path>"Analyze with LLM: Use optimized size for token-efficient analysis
Use coordinates: Apply transform to map screenshot coords to device
Inputs: udid (required), operation (required), size, codec, +4 more.
simctl-launchLaunch App on SimulatorA
simctl-launch
Launch an iOS app on a simulator with support for custom arguments and environment variables.
What it does
Starts an iOS app on a booted simulator, optionally passing command-line arguments and environment variables. Returns the process ID of the launched app for tracking.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
bundleId (string, required): App bundle ID (e.g., com.example.MyApp)
arguments (string[], optional): Command-line arguments to pass to the app
environment (object, optional): Environment variables to set (automatically prefixed with SIMCTL_CHILD_)
Returns
JSON response with:
Process ID of the launched app
Launch status and command executed
Guidance for next steps (terminating, opening URLs, checking container)
Examples
Simple app launch
await simctlLaunchTool({
udid: 'device-123',
bundleId: 'com.example.MyApp'
})Launch with debug arguments
await simctlLaunchTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
arguments: ['--verbose', '--debug']
})Launch with environment variables
await simctlLaunchTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
environment: { DEBUG: '1', API_URL: 'https://staging.example.com' }
})Common Use Cases
Debug launches: Start app with debug flags enabled
API environment switching: Set staging/production API URLs
Feature flags: Enable experimental features via environment
Test scenarios: Configure app behavior for specific test cases
Deep link testing: Launch app then open URLs with simctl-openurl
Important Notes
Simulator must be booted: Use simctl-boot first if simulator is not running
App must be installed: Use simctl-install to install app first
Environment variables: Automatically prefixed with SIMCTL_CHILD_ for simctl compatibility
Process ID tracking: Returned PID can be used to monitor or terminate the app
Error Handling
App not installed: Returns error if app bundle is not found
Simulator not booted: Indicates simulator must be booted first
Invalid bundle ID: Validates bundle ID format (must contain '.')
Simulator not found: Validates simulator exists in cache
Next Steps After Launch
Terminate app:
simctl-terminate <udid> <bundleId>Open URL/deep link:
simctl-openurl <udid> myapp://deeplinkCheck app container:
simctl-get-app-container <udid> <bundleId>Send push notification:
simctl-push <udid> <bundleId> <payload>
Inputs: udid (required), bundleId (required), arguments, environment.
simctl-listList SimulatorsARead-onlyIdempotent
simctl-list
List iOS simulators with intelligent progressive disclosure and caching.
Overview
Retrieves comprehensive simulator information including devices, runtimes, and device types. Returns concise summaries by default with cache IDs for progressive access to full details, preventing token overflow while maintaining complete functionality. Shows booted devices and recently used simulators first for faster workflows. Full output mode limits results to the most recently used devices for efficient browsing.
Parameters
Required
None - all parameters are optional
Optional
deviceType (string): Filter by device type (e.g., "iPhone", "iPad")
runtime (string): Filter by iOS runtime version (e.g., "17", "iOS 17.0")
availability (string, default: "available"): Filter by availability ("available", "unavailable", "all")
outputFormat (string, default: "json"): Output format ("json" or "text")
concise (boolean, default: true): Return concise summary with cache ID
max (number, default: 5): Maximum devices to return in full mode, sorted by lastUsed date (most recent first)
Returns
Concise mode: Summary with cacheId for detailed retrieval via simctl-get-details
Full mode: Limited device list (default 5 most recently used) with metadata showing total available and limit applied
Device Limiting in Full Mode
When concise: false, the response includes:
devices: Top N devices across all runtimes, sorted by lastUsed date (most recent first)
metadata: Shows total devices in cache, devices returned, and limit applied
Devices without lastUsed date are placed at the end
Total limit applies across all runtimes, not per-runtime
Examples
Get concise summary (default - prevents token overflow)
await simctlListTool({});Get full list for iPhone devices (limited to 5 most recent)
await simctlListTool({
deviceType: "iPhone",
concise: false
});Get full list with custom device limit
await simctlListTool({
concise: false,
max: 10
});Filter by iOS version
await simctlListTool({ runtime: "17.0" });Related Tools
simctl-get-details: Retrieve full device list using cache ID (bypasses max limit)
simctl-boot / simctl-shutdown: Boot, shutdown, or manage specific simulators
simctl-install / simctl-launch: Install and launch apps on simulators
Notes
Prevents token overflow (raw output = 10k+ tokens) via concise summaries and device limiting
Default max=5 limits output to ~2.5k tokens (90% reduction from full 50-device list)
1-hour intelligent caching eliminates redundant queries
Shows booted devices and recently used simulators first in concise mode
Use simctl-get-details with cacheId for progressive access to full data (ignores max limit)
Device sorting: mostRecent (with lastUsed) → oldest (with lastUsed) → unknown (no lastUsed)
Smart filtering by device type, runtime, and availability
Essential: Use this instead of 'xcrun simctl list' for better performance
Inputs: max, concise, runtime, deviceType, +2 more.
simctl-locationSimulate LocationAIdempotent
simctl-location
Simulate GPS location on an iOS simulator — set fixed coordinates, use city presets, play back GPX routes, animate along waypoints, or clear the override.
What it does
Wraps xcrun simctl location <udid> set/clear/start/run/list to give full control
over the simulated GPS position. Exactly one action must be specified per call.
Parameters
udid (string, optional): Simulator UDID. Defaults to the booted simulator if omitted.
Actions (exactly one required)
Action | Params | Description |
Coordinate |
| Set fixed lat/lng |
City preset |
| Named city from built-in list |
GPX scenario |
| Run a built-in scenario by name |
Waypoints |
| Animate route |
Clear |
| Remove location override |
List scenarios |
| List available GPX scenario names |
City Presets
dublin, london, newyork, sanfrancisco, tokyo, sydney, paris, berlin, beijing, mumbai, cairo, saopaulo, losangeles
Aliases also accepted: nyc (→ newyork), sf (→ sanfrancisco), la (→ losangeles)
Coordinate Validation
Latitude: -90 to 90
Longitude: -180 to 180
Waypoints Format
Whitespace-separated lat,lng pairs. At least 2 required.
"53.34,-6.26 51.50,-0.12 48.85,2.35"Returns
JSON response with action, udid, success, message, action-specific fields, and guidance.
Examples
Set coordinates
await simctlLocationTool({ lat: 53.3498, lng: -6.2603 })City preset
await simctlLocationTool({ city: 'Dublin' })
await simctlLocationTool({ city: 'nyc' })GPX scenario
await simctlLocationTool({ gpx: 'FreewayDrive' })Waypoint animation
await simctlLocationTool({ waypoints: '53.34,-6.26 51.50,-0.12', speed: 10 })Clear override
await simctlLocationTool({ clear: true })List scenarios
await simctlLocationTool({ listScenarios: true })Inputs: gpx, lat, lng, city, +5 more.
simctl-openurlOpen URL on SimulatorA
simctl-openurl
Open URLs in a simulator, including web URLs, deep links, and special URL schemes.
What it does
Opens a URL in the simulator, which can be a web URL (http/https), custom app deep link (myapp://), or special URL scheme (mailto:, tel:, sms:). The system will route the URL to the appropriate app handler.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
url (string, required): URL to open (e.g., https://example.com or myapp://deeplink?id=123)
Supported URL Schemes
HTTP/HTTPS: Web URLs (opens in Safari)
Custom schemes: Deep links to your app (myapp://, yourapp://)
mailto: Email composition (opens Mail app)
tel: Phone dialer (opens Phone app on iPhone)
sms: SMS composition (opens Messages app)
facetime: FaceTime calls
maps: Apple Maps URLs
Returns
JSON response with:
URL open status
Detected URL scheme
Guidance for testing URL handling and deep links
Examples
Open web URL
await simctlOpenUrlTool({
udid: 'device-123',
url: 'https://example.com'
})Open deep link with parameters
await simctlOpenUrlTool({
udid: 'device-123',
url: 'myapp://open?id=123&action=view'
})Open mailto link
await simctlOpenUrlTool({
udid: 'device-123',
url: 'mailto:test@example.com?subject=Hello'
})Open tel link
await simctlOpenUrlTool({
udid: 'device-123',
url: 'tel:+1234567890'
})Common Use Cases
Deep link testing: Verify app handles custom URL schemes correctly
Universal links: Test https:// URLs that open your app
Navigation testing: Confirm deep links navigate to correct screens
Parameter parsing: Verify URL parameters are parsed correctly
Fallback handling: Test behavior when no handler is registered
Important Notes
Simulator must be booted: URLs can only be opened on running simulators
Handler registration: Custom schemes require an app that handles them
URL encoding: Ensure URL parameters are properly encoded
Timing: Consider launching app first if testing immediate URL handling
Error Handling
No handler registered: Error if no app handles the URL scheme
Simulator not booted: Indicates simulator must be booted first
Invalid URL format: Validates URL has proper scheme and format
Simulator not found: Validates simulator exists in cache
Deep Link Testing Workflow
Install app:
simctl-install <udid> /path/to/App.appLaunch app:
simctl-launch <udid> <bundleId>Open deep link:
simctl-openurl <udid> myapp://route?param=valueTake screenshot:
simctl-io <udid> screenshotto verify navigationCheck logs: Monitor console for URL handling logs
Testing Strategies
Parameter variations: Test different query parameters
Invalid URLs: Verify error handling for malformed URLs
Background handling: Test URLs when app is backgrounded
Fresh launch: Test URLs when app is not running
State preservation: Verify app state is maintained after URL handling
Inputs: url (required), udid (required).
simctl-pbcopyCopy Text to Simulator ClipboardAIdempotent
simctl-pbcopy
Copy text to simulator's clipboard for testing paste operations and UIPasteboard APIs.
What it does
Copies text to the simulator's pasteboard (UIPasteboard.general), making it available for apps to access via standard pasteboard APIs. Useful for testing paste functionality without manual interaction.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
text (string, required): Text to copy to clipboard
Returns
JSON response with:
Copy operation status
Text length and preview
Guidance for accessing pasteboard in app
Examples
Copy simple text
await simctlPbcopyTool({
udid: 'device-123',
text: 'Hello World'
})Copy URL
await simctlPbcopyTool({
udid: 'device-123',
text: 'https://example.com/path?param=value'
})Copy JSON data
await simctlPbcopyTool({
udid: 'device-123',
text: JSON.stringify({ key: 'value', number: 123 })
})Common Use Cases
Paste testing: Test text field paste functionality
URL handling: Test app URL detection from clipboard
Data import: Test importing data via clipboard
Share functionality: Test receiving shared text content
Clipboard monitoring: Test apps that monitor pasteboard changes
How Apps Access the Text
Apps can access the clipboard text using:
if let text = UIPasteboard.general.string {
// Use the pasted text
}Or for URLs:
if let url = UIPasteboard.general.url {
// Handle the URL
}Important Notes
Immediate availability: Text is available on pasteboard immediately
Simulator-specific: Each simulator has its own separate pasteboard
String only: Only supports string data (no images, files, or custom types)
Persistent: Clipboard content persists until overwritten or simulator resets
Error Handling
Empty text: Error if text string is empty
Simulator not found: Validates simulator exists in cache
Write failure: Reports if clipboard operation fails
Testing Workflow
Copy text:
simctl-pbcopy <udid> "Test text to paste"Launch app:
simctl-launch <udid> <bundleId>Navigate to input: Use app to navigate to text field
Test paste: App should detect clipboard content
Take screenshot:
simctl-io <udid> screenshotto verify paste
Use Cases by Category
Authentication Testing
Copy and paste email addresses
Copy and paste passwords (for test accounts only!)
Copy verification codes from clipboard
URL Handling
Copy URLs and test app deep link detection
Test universal link handling from clipboard
Verify URL parameter parsing
Data Import
Copy JSON/CSV data for import testing
Test clipboard-based data transfer
Verify data format validation
UX Testing
Test long-press paste menu appearance
Verify paste button states
Test clipboard change notifications
Clipboard Monitoring
Some apps monitor clipboard changes. To test this:
Launch app first
Copy text to clipboard
App should detect and respond to clipboard change
Take screenshot to verify UI update
Limitations
String data only: Cannot copy images, files, or custom types
No rich text: Only plain text is supported
No pasteboard metadata: Cannot set pasteboard change count or other metadata
Simulator scope: Clipboard is not shared with host macOS clipboard
Inputs: text (required), udid (required).
simctl-privacyManage App Privacy PermissionsAIdempotent
simctl-privacy
Manage app privacy permissions on simulators with structured audit trail support.
What it does
Grants, revokes, or resets privacy permissions for apps without requiring user interaction. Supports audit trail tracking for test scenario documentation and verification.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
bundleId (string, required): App bundle ID (e.g., com.example.MyApp)
action (string, required): "grant", "revoke", or "reset"
service (string, required): Permission service to modify
scenario (string, optional): Test scenario name for audit trail
step (number, optional): Step number in test scenario
Supported Services
camera, microphone, location, contacts, photos
calendar, health, reminders, motion, keyboard
mediaLibrary, calls, siri, all (for reset)
LLM Optimization
The scenario and step parameters enable structured permission audit trail tracking. This allows AI agents to track permission state changes across test scenarios and verify permissions at each step of a test workflow.
Returns
JSON response with:
Permission modification status
Audit entry with timestamp and test context
Guidance for verification and next steps
Examples
Grant camera permission
await simctlPrivacyTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
action: 'grant',
service: 'camera'
})Revoke microphone permission
await simctlPrivacyTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
action: 'revoke',
service: 'microphone'
})Reset all permissions
await simctlPrivacyTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
action: 'reset',
service: 'all'
})Grant with audit trail tracking
await simctlPrivacyTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
action: 'grant',
service: 'location',
scenario: 'LocationTest',
step: 1
})Common Use Cases
Permission testing: Verify app behavior with different permission states
Onboarding flows: Test permission request flows without manual interaction
Denied permission handling: Test app behavior when permissions are denied
Permission combinations: Test apps with various permission combinations
Audit trail: Track permission changes across automated test scenarios
Important Notes
No user prompts: Permissions are changed without showing system alerts
Immediate effect: Changes take effect immediately for running apps
App restart: Some permissions may require app restart to take effect
Reset behavior: "reset" with "all" service clears all permissions
Audit trail: scenario/step parameters create structured test documentation
Error Handling
App not installed: Error if app is not installed on simulator
Invalid service: Error if service name is not recognized
Invalid action: Error if action is not "grant", "revoke", or "reset"
Invalid bundle ID: Validates bundle ID format (must contain '.')
Testing Workflow
Reset permissions: Start with clean slate
Grant permission:
simctl-privacy <udid> <bundleId> grant camera scenario:"CameraTest" step:1Launch app:
simctl-launch <udid> <bundleId>Test feature: Use camera feature in app
Take screenshot:
simctl-io <udid> screenshotto verify UIRevoke permission: Test denied permission handling
Verify behavior: Screenshot and check error handling
Permission Testing Strategies
Happy path: Grant all permissions, test full functionality
Denial path: Deny permissions, verify error handling
Mixed state: Some granted, some denied, test partial functionality
Reset testing: Test permission request flows from clean state
Background permissions: Test location "always" vs "when in use"
Audit Trail Usage
The auditEntry in the response includes:
timestamp: When permission was changed
action, service, bundleId: What was changed
success: Whether change succeeded
testContext: scenario and step for test tracking
This enables agents to maintain a complete history of permission changes during testing.
Inputs: udid (required), action (required), service (required), bundleId (required), +2 more.
simctl-pushSend Push NotificationA
simctl-push
Send simulated push notifications to apps on simulators with test context tracking.
What it does
Sends push notifications with custom JSON payloads to apps, simulating remote notifications from APNS. Supports test tracking to verify push delivery and validate app behavior.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
bundleId (string, required): App bundle ID (e.g., com.example.MyApp)
payload (string, required): JSON payload with APS dictionary
testName (string, optional): Test name for tracking
expectedBehavior (string, optional): Expected app behavior description
Payload Format
Must be valid JSON with an "aps" dictionary:
{
"aps": {
"alert": "Notification text",
"badge": 1,
"sound": "default"
},
"custom": "Additional data"
}LLM Optimization
The testName and expectedBehavior parameters enable structured test tracking. This allows AI agents to verify push notification delivery and validate that app behavior matches expectations (e.g., navigation, UI updates, data refresh).
Returns
JSON response with:
Push delivery status
Delivery information (sent timestamp)
Test context with expected vs actual behavior
Guidance for verifying notification handling
Examples
Simple alert notification
await simctlPushTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
payload: JSON.stringify({
aps: { alert: 'Test notification' }
})
})Notification with badge and sound
await simctlPushTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
payload: JSON.stringify({
aps: {
alert: 'New message',
badge: 5,
sound: 'default'
}
})
})Rich notification with custom data
await simctlPushTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
payload: JSON.stringify({
aps: {
alert: {
title: 'New Order',
body: 'Order #1234 has been placed'
},
badge: 1
},
orderId: '1234',
action: 'view_order'
})
})Push with test context tracking
await simctlPushTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
payload: JSON.stringify({
aps: { alert: 'Product available' },
productId: '567'
}),
testName: 'PushNotification_DeepLinkTest',
expectedBehavior: 'App navigates to ProductDetail view for product 567'
})Common Use Cases
Notification delivery testing: Verify app receives and displays notifications
Deep link navigation: Test notification taps navigate to correct screens
Badge updates: Verify badge count is updated correctly
Custom data handling: Test app processes custom payload data
Background behavior: Test app behavior when notification arrives in background
Important Notes
App must be running: Launch app first or test background notification handling
Payload validation: JSON must be valid and include "aps" dictionary
Immediate delivery: Notification is delivered immediately (no delay)
No user interaction: Notification appears automatically without tapping
Visual verification: Use simctl-io screenshot to confirm notification display
Error Handling
Invalid JSON: Error if payload is not valid JSON
App not running: May fail if app is not running (test background handling)
Simulator not booted: Indicates simulator must be booted first
Invalid bundle ID: Validates bundle ID format (must contain '.')
Testing Workflow
Launch app:
simctl-launch <udid> <bundleId>Send push:
simctl-push <udid> <bundleId> <payload>Take screenshot:
simctl-io <udid> screenshotto verify deliveryCheck navigation: Verify app navigated to expected screen
Validate data: Confirm app processed custom payload data
Test Context Tracking
The testContext in the response includes:
testName: Identifier for this push notification test
expectedBehavior: What should happen when notification is received
actualBehavior: What actually happened (delivery success/failure)
passed: Whether test passed
This enables agents to track push notification tests and verify expected behavior.
Advanced Testing
Multiple notifications: Send sequential pushes to test badge accumulation
Different payload types: Test alert, sound-only, silent notifications
Content extensions: Test notification service extensions with custom content
Action buttons: Test notification actions and user responses
Notification grouping: Test thread-id for notification grouping
Inputs: udid (required), payload (required), bundleId (required), testName, +1 more.
simctl-renameRename SimulatorAIdempotent
simctl-rename
Rename iOS simulator devices for better organization.
Overview
Changes the display name of a simulator without affecting its UDID or any data. Useful for organizing and identifying simulators with descriptive names. Quick operation completes instantly with no side effects.
Parameters
Required
deviceId (string): Device UDID to rename (from simctl-list)
newName (string): New display name for the simulator
Returns
Rename status showing old name, new name, confirmation that UDID is unchanged, success indicator, command output, and guidance emphasizing data preservation.
Examples
Rename simulator for clarity
await simctlRenameTool({
deviceId: 'ABC-123-DEF',
newName: 'Production Test Device'
});Organize test devices
await simctlRenameTool({
deviceId: 'TEST-UDID',
newName: 'UI Tests - iPhone 16 Pro'
});Related Tools
simctl-list: Find device UDID to rename
simctl-create: Create new simulator with specific name
simctl-clone: Clone simulator with new name
Notes
UDID remains unchanged - only display name is modified
All data and configuration preserved
Quick operation - completes instantly
New name must be unique - cannot duplicate existing names
Use descriptive names for better organization and identification
Perfect for organizing test devices by purpose or team
Inputs: newName (required), deviceId (required).
simctl-shutdownShutdown SimulatorAIdempotent
simctl-shutdown
Shutdown iOS simulator devices with intelligent device management.
Overview
Gracefully shuts down one or more iOS simulator devices. Supports shutting down specific devices, all currently booted devices, or all devices at once with smart targeting options. Better error handling with clear feedback when devices cannot be shut down.
Batch selection
Use all:true or deviceType/runtime filters instead of deviceId. Batch operations target available simulators; erase/delete require confirm:true. Results report each attempted device independently.
Parameters
Required
deviceId (string): Device UDID, "booted" for all booted devices, or "all" for all devices
Returns
Shutdown status with device information, duration, success indicator, command output, and next step guidance. Handles common scenarios like device already shutdown gracefully.
Examples
Shutdown specific device
await simctlShutdownTool({ deviceId: 'ABC-123-DEF' });Shutdown all booted devices
await simctlShutdownTool({ deviceId: 'booted' });Shutdown all devices
await simctlShutdownTool({ deviceId: 'all' });Related Tools
simctl-boot: Boot device after shutdown
simctl-list: Find device UDID to shutdown
simctl-delete: Delete device after shutdown (required for deletion)
Notes
Smart device targeting: "booted", "all", or specific UDID
Graceful shutdown operation
Handles "already shutdown" scenario without error
State tracking updates internal device state for better recommendations
Batch operations efficiently handle multiple device shutdowns
Required before device deletion (safety check)
Use "booted" to quickly shutdown all running simulators
Inputs: all, runtime, deviceId, deviceType.
simctl-status-barOverride Simulator Status BarAIdempotent
simctl-status-bar
Override or clear simulator status bar appearance for consistent screenshots and UI testing.
What it does
Controls the simulator's status bar appearance, allowing you to set specific time, network status, battery level, and WiFi state. Useful for creating consistent screenshots and testing app behavior under different device conditions.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
operation (string, required): "override" or "clear"
time (string, optional): Time in 24-hour format (e.g., "9:41", "23:59")
dataNetwork (string, optional): Network type - none, 1x, 3g, 4g, 5g, lte, lte-a
wifiMode (string, optional): WiFi state - active, searching, failed
batteryState (string, optional): Battery state - charging, charged, discharging
batteryLevel (number, optional): Battery percentage 0-100
Returns
JSON response with:
Status bar modification status
Applied parameters (for override operation)
Guidance for verification and testing
Examples
Override with classic Apple time
await simctlStatusBarTool({
udid: 'device-123',
operation: 'override',
time: '9:41',
batteryLevel: 100
})Simulate poor network conditions
await simctlStatusBarTool({
udid: 'device-123',
operation: 'override',
dataNetwork: 'none',
wifiMode: 'failed'
})Simulate low battery
await simctlStatusBarTool({
udid: 'device-123',
operation: 'override',
batteryState: 'discharging',
batteryLevel: 15
})Clear all overrides
await simctlStatusBarTool({
udid: 'device-123',
operation: 'clear'
})Common Use Cases
Consistent screenshots: Set time to 9:41 and battery to 100% for app store screenshots
Network condition testing: Test app behavior with different network types
Low battery testing: Verify app handles low battery warnings correctly
UI testing: Ensure status bar doesn't interfere with visual regression tests
Demo mode: Clean status bar for presentations and demos
Status Bar Parameters
Time
Format: 24-hour "HH:MM" (e.g., "9:41", "14:30", "23:59")
Apple default: "9:41" (time of original iPhone announcement)
Data Network
none: No cellular data
1x: 2G network
3g: 3G network
4g: 4G network
5g: 5G network
lte: LTE network
lte-a: LTE Advanced
WiFi Mode
active: Connected and active
searching: Searching for network
failed: Connection failed
Battery State
charging: Device is charging
charged: Fully charged
discharging: Running on battery
Battery Level
Range: 0-100
Shows percentage in status bar
Important Notes
Screenshot consistency: Apply overrides before taking screenshots for consistent results
Demo mode: Apple often uses 9:41 time and 100% battery for marketing materials
Simulator only: Status bar overrides only work on simulators, not real devices
Persistent: Overrides persist until cleared or simulator is reset
Version compatibility: Some parameters may not work on older iOS versions
Error Handling
Invalid time format: Error if time is not in HH:MM format
Invalid network type: Error if dataNetwork is not in allowed list
Invalid battery level: Error if batteryLevel is not 0-100
Simulator not found: Validates simulator exists in cache
App Store Screenshot Best Practices
For app store screenshots, Apple recommends:
Time: "9:41" (Apple's standard)
Battery: 100% (shows full battery icon)
Signal: Full bars (use "lte" or "5g")
WiFi: Active (shows connected)
No notifications or indicators
await simctlStatusBarTool({
udid: 'device-123',
operation: 'override',
time: '9:41',
dataNetwork: '5g',
wifiMode: 'active',
batteryState: 'charged',
batteryLevel: 100
})Testing Workflow
Apply overrides: Set desired status bar state
Take screenshot:
simctl-io <udid> screenshotto verifyTest app: Launch app and verify it handles the conditions
Clear overrides: Reset to normal state when done
Visual Verification
After applying overrides, always take a screenshot to verify the status bar appears correctly:
simctl-io <udid> screenshotThe status bar changes are visible immediately and affect all screenshots taken while overrides are active.
When to Clear Overrides
After taking app store screenshots
Before testing features that depend on actual device state
When switching between different test scenarios
At the end of automated test runs
Inputs: udid (required), operation (required), time, wifiMode, +3 more.
simctl-stream-logsStream Simulator LogsARead-onlyIdempotent
simctl-stream-logs
outputPath optionally saves the complete captured log before response truncation.
Stream real-time console logs from iOS simulator with filtering, severity classification, deduplication, and statistics summary.
What it does
Streams console logs from a simulator in real-time, with support for filtering by process or custom predicates. Captures logs for a specified duration and returns:
Structured log entries with timestamps, process names, and per-line severity
Statistics summary (totalLines, errors, warnings, info, debug)
Top errors and warnings (deduplicated, capped at 15 each)
Sample tail of raw log output
Parameters
udid (string, required): Simulator UDID (from simctl-list)
bundleId (string, optional): Filter logs to specific app bundle ID
predicate (string, optional): Custom NSPredicate for log filtering
duration (number, optional): Capture duration in seconds (default: 10)
capture (boolean, optional): Whether to capture logs (default: true)
severity (string | string[], optional): Comma-separated or array of severity levels to include in the returned items. Allowed values:
error,warning,info,debug. Default: all four. Statistics always count all severities regardless of this filter.
Severity Classification
Each log line is classified by case-insensitive pattern matching:
Severity | Patterns |
error | \berror\b, \bfault\b, \bfailed\b, \bexception\b, \bcrash\b, ❌ |
warning | \bwarning\b, \bwarn\b, \bdeprecated\b, ⚠️ |
info | \binfo\b, \bnotice\b, ℹ️ |
debug | anything that does not match the above |
Deduplication
Error and warning lines are deduplicated before appearing in topErrors / topWarnings.
The deduplication signature is computed by stripping timestamps (YYYY-MM-DD HH:MM:SS)
and process IDs ([1234]) then collapsing whitespace. Duplicate occurrences are collapsed
into a single entry with a count field.
Returns
JSON response with:
logs: Filtered log entries (severity-filtered, first 100 items)
count, predicate, bundleId, duration, severityFilter, items[]
statistics:
{ totalLines, errors, warnings, info, debug }topErrors: Deduplicated error lines, up to 15, each with
messageandcounttopWarnings: Deduplicated warning lines, up to 15, each with
messageandcountsampleTail: Last 20 raw log lines
guidance: Human-readable summary strings
Examples
Stream all logs for 10 seconds
await streamLogsTool({ udid: 'device-123' })Stream errors and warnings only for specific app
await streamLogsTool({
udid: 'device-123',
bundleId: 'com.example.MyApp',
duration: 30,
severity: 'error,warning',
})Stream with custom predicate
await streamLogsTool({
udid: 'device-123',
predicate: 'eventMessage CONTAINS "Error" OR eventMessage CONTAINS "Warning"',
duration: 20,
})Predicate Syntax
Supports NSPredicate syntax for filtering:
Process filtering:
process == "MyApp"Content filtering:
eventMessage CONTAINS "keyword"Severity filtering:
messageType == "Error"Combined filters:
process == "MyApp" AND eventMessage CONTAINS "network"
Common predicates:
process == "com.example.MyApp"- Filter by bundle IDeventMessage CONTAINS "Error"- Show only errorssubsystem == "com.example.networking"- Filter by subsystemmessageType IN {"Error", "Fault"}- Show errors and faults
Common Use Cases
App debugging: Stream logs for specific app during testing
Error monitoring: Filter for errors and warnings via severity param
Network debugging: Monitor network-related log messages
Performance tracking: Capture logs during performance tests
Integration testing: Verify expected log output during test runs
Important Notes
Timeout buffer: Command timeout is duration + 5 seconds for safety
Buffer size: 10MB buffer for log capture to prevent overflow
First 100 logs: Returns first 100 severity-filtered log entries to avoid token overflow
Statistics always complete: Counts cover all lines regardless of severity filter
Dedup on errors/warnings: topErrors and topWarnings collapse repeated messages
Error Handling
Missing udid: Error if udid is not provided
Simulator not found: Validates simulator exists
Command timeout: Times out if duration exceeds limit
Buffer overflow: May lose logs if output exceeds 10MB buffer
Duration Guidelines
Quick check: 5-10 seconds for basic log verification
Feature testing: 15-30 seconds for testing specific features
Integration tests: 30-60 seconds for full test scenarios
Debug sessions: 60+ seconds for deep debugging sessions
Inputs: udid (required), capture, bundleId, duration, +2 more.
simctl-suggestSuggest Best SimulatorARead-onlyIdempotent
simctl-suggest
Intelligent simulator suggestion tool.
Overview
Suggests the best simulators for your project based on project preferences (remembered from previous successful builds), recently used simulators, device popularity (iPhone 16 > iPhone 15), and boot performance metrics. Transparent scoring algorithm shows reasoning for each recommendation.
Parameters
Required
None - all parameters are optional
Optional
projectPath (string): Project directory for project-specific ranking
deviceType (string): Filter suggestions by device type
maxSuggestions (number, default: 4): Maximum number of suggestions to return
autoBootTopSuggestion (boolean, default: false): Automatically boot top suggestion
Returns
Ranked suggestions with scores, reasoning, boot history, performance metrics, summary of scoring criteria, and guidance for next steps. Each suggestion includes simulator name, UDID, state, availability, score breakdown, and boot performance data.
Examples
Get project-specific suggestions
await simctlSuggestTool({
projectPath: '/path/to/project'
});Auto-boot top suggestion
await simctlSuggestTool({
projectPath: '/path/to/project',
autoBootTopSuggestion: true
});Filter by device type
await simctlSuggestTool({
deviceType: 'iPhone',
maxSuggestions: 3
});Related Tools
simctl-boot: Boot suggested simulator
simctl-list: See all available simulators
simctl-health-check: Validate environment health
Notes
Scoring algorithm (100 point scale): Project preference (40), Recent usage (40), iOS version (30), Popular model (20), Boot performance (10)
Project-aware: Remembers preferred simulator per project
Performance metrics: Learns boot times and reliability from usage
Popularity ranking: Suggests popular models (iPhone 16 Pro > iPhone 15)
Transparent scoring: Shows reasoning for each recommendation
Auto-boot option: Optionally boots top suggestion immediately
Inputs: deviceType, projectPath, maxSuggestions, autoBootTopSuggestion.
simctl-terminateTerminate App on SimulatorAIdempotent
simctl-terminate
Gracefully terminate a running iOS app on a simulator.
What it does
Stops a running app by sending a termination signal. The app's lifecycle methods (applicationWillTerminate:) will be called, allowing clean shutdown.
Parameters
udid (string, required): Simulator UDID (from simctl-list)
bundleId (string, required): App bundle ID (e.g., com.example.MyApp)
Returns
JSON response with:
Termination status
Command executed
Guidance for next steps (relaunching, uninstalling, checking container)
Examples
Terminate running app
await simctlTerminateTool({
udid: 'device-123',
bundleId: 'com.example.MyApp'
})Common Use Cases
Clean app restart: Terminate then relaunch to reset app state
Test lifecycle: Verify app handles termination correctly
Memory cleanup: Stop app before running memory-intensive tests
State reset: Terminate app to clear runtime state between test runs
Background testing: Stop foreground app to test background behavior
Important Notes
Graceful termination: App lifecycle methods are called for clean shutdown
Not running OK: Returns error if app is not running, but can be safely ignored
Simulator state: Works on both booted and shutdown simulators
No force kill: This is a graceful termination, not a force kill
Error Handling
App not running: Error returned but operation is safe to ignore
App not installed: Indicates app must be installed first
Simulator not booted: Warning shown but termination may still succeed
Invalid bundle ID: Validates bundle ID format (must contain '.')
Next Steps After Termination
Launch app again:
simctl-launch <udid> <bundleId>Uninstall app:
simctl-uninstall <udid> <bundleId>Check app container:
simctl-get-app-container <udid> <bundleId>Install new build:
simctl-install <udid> /path/to/App.app
Difference from Force Kill
Terminate (this tool): Graceful shutdown with lifecycle callbacks
Force kill: Immediate termination without cleanup (use system kill command)
Inputs: udid (required), bundleId (required).
simctl-uninstallUninstall App from SimulatorADestructiveIdempotent
simctl-uninstall
Uninstall iOS apps from simulators.
Overview
Removes an installed app from a simulator by its bundle ID. This cleans up all app data, preferences, and the app bundle itself from the simulator. Useful for clean testing, data removal, space management, and workflow automation.
Confirmation
confirm: true is required before permanently deleting simulator or app data.
Parameters
Required
udid (string): Simulator UDID (from simctl-list)
bundleId (string): App bundle ID (e.g., com.example.MyApp)
Returns
Uninstall status with bundle ID, simulator info (name, state, availability), success indicator, command output, and guidance for reinstallation or app management.
Examples
Uninstall app from simulator
await simctlUninstallTool({
udid: 'ABC-123-DEF',
bundleId: 'com.example.MyApp'
});Clean install workflow
// Uninstall old version
await simctlUninstallTool({
udid: 'TEST-DEVICE',
bundleId: 'com.example.MyApp'
});
// Then reinstall
await simctlInstallTool({
udid: 'TEST-DEVICE',
appPath: '/path/to/MyApp.app'
});Related Tools
simctl-install: Reinstall app after uninstall
simctl-list: Find simulator UDID
simctl-get-app-container: Check app container before uninstall
Notes
Bundle ID must follow format: com.company.appname
Removes app and all associated data/preferences
Validates simulator exists before attempting uninstall
Useful for clean testing workflows
Frees simulator disk space by removing unused apps
Test cycles requiring clean app installs benefit from uninstall automation
Inputs: udid (required), bundleId (required), confirm.
test-record-reportGenerate Test Recording ReportAIdempotent
test-record-report
Generate a markdown report from a recorded test session created by test-record-step.
What it does
Reads the session's steps.json and produces a structured report.md file:
Header with test name, date, step count, and duration
Per-step sections with screenshot image links, assertions, metadata, and element counts
Summary section with totals
The report is written to <recordingsRoot>/<sessionName>/report.md and also returned
in the response for immediate consumption.
Parameters
sessionName (string, required): Session name matching prior test-record-step calls
testName (string, optional): Title for the report (defaults to sessionName)
Returns
JSON with { sessionName, testName, reportPath, stepCount, markdown }
plus guidance. Throws McpError InvalidRequest if session or steps are missing.
Examples
Basic report
await testRecordReportTool({ sessionName: "login-flow" })Named report
await testRecordReportTool({
sessionName: "login-flow",
testName: "Login Flow — Happy Path"
})Typical Workflow
test-record-step({ sessionName: "my-test", label: "App launched" })test-record-step({ sessionName: "my-test", label: "Login tapped", assertion: "Login form visible" })test-record-step({ sessionName: "my-test", label: "Logged in", metadata: { user: "test@example.com" } })test-record-report({ sessionName: "my-test", testName: "Login Flow" })
Inputs: sessionName (required), testName.
test-record-stepRecord Test StepA
test-record-step
Record a single named step in a test session, capturing a screenshot and accessibility tree snapshot.
What it does
Maintains a persistent session directory under ~/.xc-mcp/test-recordings/<sessionName>/
(override root with env var XC_MCP_RECORDINGS_DIR). Each call:
Creates the session directory + steps.json on first call
Captures a screenshot via
xcrun simctl io <udid|booted> screenshotCaptures an accessibility tree via
idb ui describe-all(tolerates idb absence)Appends a step record to steps.json with sequential index (001, 002, …)
Session layout:
~/.xc-mcp/test-recordings/<sessionName>/
steps.json – session metadata + all step records
screenshots/ – NNN-<label>.png per step
accessibility/ – NNN-<label>.json per step (idb NDJSON or error stub)
report.md – generated by test-record-reportParameters
sessionName (string, required): Unique session identifier (used as directory name)
label (string, required): Human-readable description of this step
udid (string, optional): Simulator UDID — defaults to
bootedmetadata (object, optional): Arbitrary key-value pairs attached to step record
assertion (string, optional): Assertion description recorded with step
Returns
JSON with { sessionName, stepIndex, label, screenshot, accessibilityFile, elementCount, timestampMs }
plus guidance for next steps.
Examples
Record first step
await testRecordStepTool({ sessionName: "login-flow", label: "App launched" })Step with assertion and metadata
await testRecordStepTool({
sessionName: "login-flow",
label: "Login succeeded",
assertion: "Home screen is visible",
metadata: { user: "test@example.com", env: "staging" }
})Specific simulator
await testRecordStepTool({
sessionName: "login-flow",
label: "Credentials entered",
udid: "device-123"
})Inputs: label (required), sessionName (required), udid, metadata, +2 more.
visual-diffCompare Screenshots (Pixel Diff)AIdempotent
visual-diff
algorithm: skill uses the reference script’s grayscale noise cutoff (>10); pixelmatch is the default. Both write diff.png, side-by-side.png, and the JSON report.
Compare two PNG screenshots pixel-by-pixel using pixelmatch to detect visual regressions. Writes a highlighted diff image and a JSON report to the output directory.
What it does
Reads two PNG files, compares them pixel-by-pixel, and:
Reports the number and percentage of differing pixels
Determines pass/fail against a configurable threshold
Writes
diff.pngwith highlighted differences (red pixels where images differ)Writes
diff-report.jsonwith full metrics
Parameters
baselinePath (string, required): Path to the baseline (reference) PNG
currentPath (string, required): Path to the current (test) PNG
outputDir (string, optional): Directory for diff.png and diff-report.json. Defaults to the directory containing currentPath
threshold (number, optional): Maximum acceptable ratio of different pixels (0.01 = 1%). Default: 0.01
Returns
Text summary and structuredContent:
differentPixels: Count of pixels that differdifferencePercentage: Ratio of different pixels to total pixels (0–1)passed: true if differencePercentage <= threshold
Artifacts Written
diff.png: Diff image highlighting changed pixels (pixelmatch output)diff-report.json: JSON with baseline, current, dimensions, totalPixels, differentPixels, differencePercentage, thresholdPercentage, passed
Errors
Throws McpError(InvalidRequest) for:
Missing baseline or current file
Dimension mismatch between images
PNG read failures
Examples
Basic diff
await visualDiffTool({
baselinePath: '/tmp/before.png',
currentPath: '/tmp/after.png'
})Custom output directory and strict threshold
await visualDiffTool({
baselinePath: '/tmp/before.png',
currentPath: '/tmp/after.png',
outputDir: '/tmp/diffs',
threshold: 0.001
})Zero-tolerance regression check
await visualDiffTool({
baselinePath: '/snapshots/login-baseline.png',
currentPath: '/snapshots/login-current.png',
threshold: 0
})Inputs: currentPath (required), baselinePath (required), algorithm, outputDir, +1 more. Returns: passed, differentPixels, differencePercentage
workflow-build-and-runBuild & Run (Workflow)A
workflow-build-and-run
Build and run an Xcode project on a simulator in a single orchestrated workflow.
Overview
Combines build, simulator selection, installation, and launch into one call:
Build - Compile the Xcode project with xcodebuild
Select Simulator - Auto-detect or use specified device
Boot - Start the simulator
Install - Install the built .app bundle
Launch - Launch the app
Screenshot (optional) - Capture initial app state
Parameters
Required
projectPath (string): Path to .xcodeproj or .xcworkspace
scheme (string): Build scheme name
Optional
configuration (string): Build configuration (default: "Debug")
simulatorUdid (string): Target simulator UDID - auto-detected if omitted
launchArguments (string[]): App launch arguments
environmentVariables (Record<string, string>): App environment variables
takeScreenshot (boolean): Capture screenshot after launch (default: false)
Inputs: scheme (required), projectPath (required), configuration, simulatorUdid, +3 more.
workflow-fresh-installFresh Install (Workflow)ADestructive
workflow-fresh-install
Clean slate app installation - build, install, and launch with fresh simulator state.
Overview
Orchestrates a complete clean installation cycle in a single call:
Select Simulator - Auto-detect or use specified device
Shutdown - Ensure simulator is stopped
Erase (optional) - Wipe all simulator data
Boot - Start fresh simulator
Build - Compile the Xcode project
Install - Install the built app
Launch - Start the app
This workflow keeps intermediate results internal, reducing agent context usage by ~70% compared to calling each tool manually.
Parameters
Required
projectPath (string): Path to .xcodeproj or .xcworkspace
scheme (string): Build scheme name
Optional
simulatorUdid (string): Target simulator - auto-detected if omitted
eraseSimulator (boolean): Wipe simulator data before install (default: false)
configuration ("Debug" | "Release"): Build configuration (default: Debug)
launchArguments (string[]): App launch arguments
environmentVariables (Record<string, string>): App environment variables
Returns
Consolidated result with:
success: Overall workflow success
project: Build configuration details
simulator: Target simulator info
app: Installed app details (bundleId, path, launched)
totalDuration: Total workflow time
guidance: Next steps
Examples
Basic Fresh Install
{
"projectPath": "/path/to/MyApp.xcodeproj",
"scheme": "MyApp"
}Auto-selects simulator, builds, installs, and launches.
Clean Install with Erased Simulator
{
"projectPath": "/path/to/MyApp.xcworkspace",
"scheme": "MyApp",
"eraseSimulator": true,
"configuration": "Debug"
}Erases all simulator data for truly fresh state.
Specific Simulator with Launch Arguments
{
"projectPath": "/path/to/MyApp.xcodeproj",
"scheme": "MyApp",
"simulatorUdid": "ABC123-DEF456",
"launchArguments": ["-UITesting", "-ResetState"],
"environmentVariables": {"DEBUG_MODE": "1"}
}Targets specific simulator with custom launch configuration.
Why Use This Workflow?
Token Efficiency
Manual approach: 6-7 tool calls × ~100 tokens each = ~600+ tokens in responses
Workflow approach: 1 call with consolidated response = ~150 tokens
Reduced Context Pollution
Build logs not exposed (only success/failure)
Intermediate states summarized
Only actionable outcome returned
Consistent State
Shutdown ensures clean starting point
Optional erase for truly fresh state
Proper boot sequencing
Related Tools
workflow-tap-element: UI interaction after install
xcodebuild-build: Direct build (used internally)
simctl-boot / simctl-shutdown / simctl-erase: Direct simulator control (used internally)
simctl-install / simctl-launch: Direct app management (used internally)
Notes
Shutdown failures are non-fatal (simulator may already be off)
Auto-suggests best simulator based on project requirements
Build artifacts are located automatically
Bundle ID is discovered from build settings
Inputs: scheme (required), projectPath (required), configuration, simulatorUdid, +3 more.
workflow-tap-elementTap Element (Workflow)A
workflow-tap-element
High-level semantic UI interaction - find and tap elements by name without coordinate hunting.
Overview
Orchestrates accessibility-first UI automation in a single call:
Check Accessibility - Assess UI richness for automation approach
Find Element - Semantic search by label/identifier
Tap Element - Press a uniquely matched control through accessibility; otherwise tap discovered coordinates
Input Text (optional) - Type into tapped field
Verify Result (optional) - Screenshot for confirmation
This workflow keeps intermediate results internal, reducing agent context usage by ~80% compared to calling each tool manually.
Parameters
Required
elementQuery (string): Search term for element (e.g., "Login", "Submit", "Email")
Case-insensitive partial matching ("log" matches "Login")
Optional
inputText (string): Text to type after tapping (for text fields)
verifyResult (boolean): Take screenshot after action (default: false)
udid (string): Target device - auto-detected if omitted
screenContext (string): Screen name for tracking (e.g., "LoginScreen")
Returns
Consolidated result with:
success: Overall workflow success
tappedElement: Found element details (type, label, coordinates)
inputText: Text entry status (if requested)
verified: Screenshot status (if requested)
accessibilityQuality: UI richness assessment
totalDuration: Total workflow time
guidance: Next steps
Examples
Tap Login Button
{"elementQuery": "Login"}Finds and taps the Login button.
Tap Email Field and Enter Text
{
"elementQuery": "Email",
"inputText": "user@example.com",
"screenContext": "LoginScreen"
}Finds email field, taps it, enters text.
Full Verification Workflow
{
"elementQuery": "Submit",
"verifyResult": true,
"screenContext": "SignupForm"
}Taps Submit button and captures verification screenshot.
Why Use This Workflow?
Token Efficiency
Manual approach: 4-5 tool calls × ~50 tokens each = ~200+ tokens in responses
Workflow approach: 1 call with consolidated response = ~80 tokens
Reduced Context Pollution
Intermediate accessibility data not exposed
Element search results summarized
Only actionable outcome returned
Error Handling
Graceful degradation on partial failures
Helpful guidance when element not found
Clear troubleshooting steps
Related Tools
idb-ui-find-element: Direct element search (used internally)
idb-semantic-action: Accessibility press with uniqueness checks (used internally)
idb-ui-tap: Coordinate tap (used internally)
accessibility-quality-check: Direct quality check (used internally)
workflow-fresh-install: Clean app installation workflow
Notes
Falls back gracefully if accessibility is minimal
Non-fatal errors (input, screenshot) don't fail the workflow
Element matching uses partial, case-insensitive search
A single Button/Link/Switch/CheckBox/Tab match uses an accessibility press with coordinate fallback in the action tool
A rejected semantic action fails the workflow; it is never retried with an unguarded coordinate tap
Small delay between tap and input for keyboard appearance
Inputs: elementQuery (required), udid, inputText, verifyResult, +1 more.
xcodebuild-buildBuild Xcode SchemeA
xcodebuild-build
⚡ Build Xcode projects with intelligent defaults and performance tracking
What it does
Builds Xcode projects and workspaces with advanced learning capabilities that remember successful configurations and suggest optimal simulators per project. Uses progressive disclosure to provide concise summaries by default, with full build logs available on demand. Tracks build performance metrics (duration, errors, warnings) and learns from successful builds to improve future build suggestions.
Why you'd use it
Automatic smart defaults: remembers which simulator and config worked last time
Progressive disclosure: concise summaries prevent token overflow, full logs on demand
Performance tracking: measures build times and provides optimization insights
Structured errors: clear error messages instead of raw CLI stderr
Parameters
Required
projectPath (string): Path to .xcodeproj or .xcworkspace file
scheme (string): Build scheme name (use xcodebuild-list to discover)
Optional
configuration (string, default: 'Debug'): Build configuration (Debug/Release, defaults to cached or "Debug")
destination (string): Build destination (e.g., "platform=iOS Simulator,id=")
sdk (string): SDK to build against (e.g., "iphonesimulator", "iphoneos")
derivedDataPath (string): Custom derived data path for build artifacts
Returns
Structured JSON response with buildId (for progressive disclosure), success status, build summary (errors, warnings, duration), and intelligence metadata showing which smart defaults were applied. Use xcodebuild-get-details with buildId to retrieve full logs.
Examples
Minimal build with smart defaults
const result = await xcodebuildBuildTool({
projectPath: "/path/to/MyApp.xcodeproj",
scheme: "MyApp"
});Explicit configuration
const release = await xcodebuildBuildTool({
projectPath: "/path/to/MyApp.xcworkspace",
scheme: "MyApp",
configuration: "Release",
destination: "platform=iOS Simulator,id=ABC-123"
});Related Tools
xcodebuild-test: Run tests after building
xcodebuild-clean: Clean build artifacts
xcodebuild-get-details: Get full build logs (use with buildId)
Inputs: scheme (required), projectPath (required), sdk, destination, +2 more. Returns: scheme, buildId, success, durationMs, +3 more
xcodebuild-cleanClean Xcode BuildADestructiveIdempotent
xcodebuild-clean
⚡ Clean build artifacts with validation and structured output
What it does
Removes build artifacts and intermediate files for an Xcode project or workspace. Pre-validates that the project exists and Xcode is properly installed before executing, providing clear error messages if something is misconfigured. Returns structured JSON responses with execution status, duration, and any errors encountered during the clean operation.
Why you'd use it
Resolve build issues by removing stale or corrupted build artifacts
Free up disk space occupied by intermediate build files
Ensure clean builds from scratch without cached compilation results
Get structured feedback with execution time and success status
Parameters
Required
projectPath (string): Path to .xcodeproj or .xcworkspace file
scheme (string): Build scheme name to clean
Optional
configuration (string): Build configuration to clean (e.g., "Debug", "Release")
Returns
Structured JSON response containing success status, command executed, execution duration, output messages, and exit code. Includes both stdout and stderr for comprehensive debugging. Operation typically completes in under 3 minutes.
Examples
Clean default configuration
const result = await xcodebuildCleanTool({
projectPath: "/path/to/MyApp.xcodeproj",
scheme: "MyApp"
});Clean specific configuration
const cleanRelease = await xcodebuildCleanTool({
projectPath: "/path/to/MyApp.xcworkspace",
scheme: "MyApp",
configuration: "Release"
});Related Tools
xcodebuild-build: Build after cleaning
xcodebuild-list: Discover available schemes
Inputs: scheme (required), projectPath (required), configuration.
xcodebuild-get-detailsGet Build/Test DetailsARead-onlyIdempotent
xcodebuild-get-details
🔍 Retrieve detailed build or test output from cached results - Progressive disclosure for logs.
Provides on-demand access to full build and test logs that were cached during xcodebuild-build or xcodebuild-test execution. Implements progressive disclosure pattern: initial build/test responses return concise summaries to prevent token overflow, while this tool allows drilling down into full logs, filtered errors, warnings, or metadata when needed for debugging.
Advantages
• Access full build logs without cluttering initial responses • Filter to just errors or warnings for faster debugging • Retrieve exact command executed and exit code • Inspect build metadata and cache information
Parameters
Required
buildId (string): Cache ID from xcodebuild-build or xcodebuild-test response
detailType (string): Type of details to retrieve
"full-log": Complete stdout and stderr output
"errors-only": Lines containing errors or build failures
"warnings-only": Lines containing warnings
"summary": Build metadata and configuration used
"command": Exact xcodebuild command executed
"metadata": Cache info and output sizes
Optional
maxLines (number): Maximum lines to return (default: 100)
Returns
Tool execution results with requested build or test details
Full logs or filtered errors/warnings with line counts
Build metadata and execution information
Related Tools
xcodebuild-build: Build iOS projects (returns buildId)
xcodebuild-test: Run tests (returns testId)
simctl-get-details: Get simulator list details
Notes
Tool is auto-registered with MCP server
Requires valid cache ID from recent build/test
Cache IDs expire after 30 minutes
Use for debugging build failures and test issues
Inputs: buildId (required), detailType (required), maxLines.
xcodebuild-inspect-schemeInspect Xcode SchemeARead-onlyIdempotent
xcodebuild-inspect-scheme
Parse and display an Xcode scheme's build, run, and test configurations from its
.xcscheme file.
Parameters
projectPath(required): Path to the .xcodeproj or .xcworkspacescheme(required): Scheme name to inspect
Returns
Parsed scheme information: build targets, run configuration, test configuration, and environment/launch arguments where present.
Inputs: scheme (required), projectPath (required).
xcodebuild-listList Xcode Schemes & TargetsARead-onlyIdempotent
xcodebuild-list
⚡ List project targets, schemes, and configurations with intelligent caching
What it does
Discovers and returns all available build targets, schemes, and configurations for an Xcode project or workspace. Uses 1-hour intelligent caching to remember results and avoid expensive re-runs of project discovery. Validates both Xcode installation and project path before execution to provide clear error messages if something is misconfigured.
Why you'd use it
Discover available schemes before building or testing (essential for automation)
Validate project structure and configuration
Get structured project metadata for CI/CD pipelines
Avoid expensive repeated queries with 1-hour caching
Parameters
Required
projectPath (string): Path to .xcodeproj or .xcworkspace file
Optional
outputFormat (string, default: 'json'): "json" or "text" output format
Returns
Structured JSON containing all targets, schemes, configurations, and project information. Consistent format across .xcodeproj and .xcworkspace project types. Results are cached for 1 hour to speed up subsequent queries.
Examples
List schemes for a project
const info = await xcodebuildListTool({
projectPath: "/path/to/MyApp.xcodeproj"
});List with text output
const textInfo = await xcodebuildListTool({
projectPath: "/path/to/MyApp.xcworkspace",
outputFormat: "text"
});Related Tools
xcodebuild-build: Build discovered schemes
xcodebuild-test: Test discovered schemes
Inputs: projectPath (required), outputFormat.
xcodebuild-showsdksList Available SDKsARead-onlyIdempotent
xcodebuild-showsdks
⚡ Show available SDKs for iOS, macOS, watchOS, and tvOS
What it does
Lists all SDKs available in your Xcode installation for building apps across Apple platforms. Returns structured JSON data instead of raw CLI text, making it easy to parse and validate SDK availability. Smart caching prevents redundant SDK queries, improving performance for repeated lookups. Validates Xcode installation before execution.
Why you'd use it
Verify SDK availability before starting builds (prevent build failures)
Discover which platform versions are supported by your Xcode installation
Validate CI/CD environment has required SDKs installed
Get structured SDK data for automated build configuration
Parameters
Optional
outputFormat (string, default: 'json'): "json" or "text" output format
Returns
Structured JSON containing all available SDKs organized by platform (iOS, macOS, watchOS, tvOS). Each SDK entry includes platform name, version, and SDK identifier. Smart caching reduces query overhead for repeated lookups.
Examples
Get available SDKs as JSON
const sdks = await xcodebuildShowSDKsTool({ outputFormat: "json" });Get raw text output
const sdksText = await xcodebuildShowSDKsTool({ outputFormat: "text" });Related Tools
xcodebuild-version: Get Xcode version information
xcodebuild-build: Build with specific SDK
Inputs: outputFormat.
xcodebuild-testRun Xcode TestsA
xcodebuild-test
⚡ Run Xcode tests with intelligent defaults and progressive disclosure
What it does
Executes unit and UI tests for Xcode projects with advanced learning that remembers successful test configurations and suggests optimal simulators per project. Provides detailed test metrics (passed/failed/skipped) with progressive disclosure to prevent token overflow. Supports test filtering (-only-testing, -skip-testing), test plans, and test-without-building mode for faster iteration. Learns from successful test runs to improve future suggestions.
Why you'd use it
Automatic smart defaults: remembers which simulator and config worked for tests
Detailed test metrics: structured pass/fail/skip counts instead of raw output
Progressive disclosure: concise summaries with full logs available via testId
Test filtering: run specific tests or skip problematic ones with -only-testing/-skip-testing
Execution status
parallelTesting: false disables parallel testing; true enables it; omitted preserves xcodebuild defaults. Zero executed tests return status NOT RUN and success false. A nonzero runner exit always fails.
Parameters
Required
projectPath (string): Path to .xcodeproj or .xcworkspace file
scheme (string): Test scheme name (use xcodebuild-list to discover)
Optional
configuration (string, default: 'Debug'): Build configuration (Debug/Release, defaults to cached or "Debug")
destination (string): Test destination (e.g., "platform=iOS Simulator,id=")
sdk (string): SDK to test against (e.g., "iphonesimulator")
derivedDataPath (string): Custom derived data path
testPlan (string): Test plan name to execute
onlyTesting (string[]): Array of test identifiers to run exclusively
skipTesting (string[]): Array of test identifiers to skip
testWithoutBuilding (boolean): Run tests without building (requires prior build)
Returns
Structured JSON with testId (for progressive disclosure), success status, test summary (total/passed/failed/skipped counts), failure details (first 3 failures), and cache metadata showing which smart defaults were applied. Use xcodebuild-get-details with testId for full logs.
Examples
Run all tests with smart defaults
const result = await xcodebuildTestTool({
projectPath: "/path/to/MyApp.xcodeproj",
scheme: "MyApp"
});Run specific tests only
const filtered = await xcodebuildTestTool({
projectPath: "/path/to/MyApp.xcworkspace",
scheme: "MyApp",
onlyTesting: ["MyAppTests/testLogin", "MyAppTests/testLogout"]
});Fast iteration with test-without-building
const quick = await xcodebuildTestTool({
projectPath: "/path/to/MyApp.xcodeproj",
scheme: "MyApp",
testWithoutBuilding: true
});Complete JSON Examples
Run All Tests
{"projectPath": "/path/to/MyApp.xcodeproj", "scheme": "MyApp"}Run Specific Test Plan
{"projectPath": "/path/to/MyApp.xcodeproj", "scheme": "MyApp", "testPlan": "IntegrationTests"}Run Only Specific Tests
{"projectPath": "/path/to/MyApp.xcodeproj", "scheme": "MyApp", "onlyTesting": ["MyAppTests/LoginTests", "MyAppTests/AuthTests/testLogin"]}Skip Specific Tests
{"projectPath": "/path/to/MyApp.xcodeproj", "scheme": "MyApp", "skipTesting": ["MyAppTests/SlowTests", "MyAppUITests"]}Test Without Building (Using Previous Build)
{"projectPath": "/path/to/MyApp.xcodeproj", "scheme": "MyApp", "testWithoutBuilding": true}Test with Specific Destination
{"projectPath": "/path/to/MyApp.xcodeproj", "scheme": "MyApp", "destination": "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.0"}Release Configuration Testing
{"projectPath": "/path/to/MyApp.xcodeproj", "scheme": "MyApp", "configuration": "Release"}Related Tools
xcodebuild-build: Build before testing
xcodebuild-get-details: Get full test logs (use with testId)
simctl-list: See available test simulators
Inputs: scheme (required), projectPath (required), sdk, testPlan, +7 more. Returns: failed, passed, scheme, testId, +4 more
xcodebuild-validate-capabilitiesValidate App CapabilitiesARead-onlyIdempotent
xcodebuild-validate-capabilities
Compare an app's Info.plist required permissions/capabilities against the permissions actually granted on a simulator, surfacing mismatches.
Parameters
projectPath(required): Path to the .xcodeproj or .xcworkspacescheme(required): Scheme nameudid(optional): Simulator UDID to validate granted permissions against
Returns
A capabilities validation report listing required vs granted permissions and any gaps.
Inputs: scheme (required), projectPath (required), udid.
xcodebuild-versionXcode Version InfoARead-onlyIdempotent
xcodebuild-version
⚡ Get Xcode and SDK version information with structured output
What it does
Retrieves comprehensive version information about your Xcode installation and available SDKs. Returns structured JSON data that's easy to parse and validate, eliminating the need to parse raw command-line output. Validates Xcode installation before execution to provide clear error messages if Xcode is not properly configured.
Why you'd use it
Validate environment before running builds or tests (CI/CD validation)
Check SDK availability for specific platform versions
Ensure consistent Xcode versions across team or build environments
Get structured version data for automated tooling and scripts
Parameters
Optional
sdk (string): Query specific SDK version (e.g., "iphoneos", "iphonesimulator")
outputFormat (string, default: 'json'): "json" or "text" output format
Returns
Structured JSON response containing Xcode version, build number, and SDK information. Falls back gracefully to text format for older Xcode versions that don't support JSON output.
Examples
Get Xcode version as JSON
const result = await xcodebuildVersionTool({ outputFormat: "json" });Query specific SDK
const sdkInfo = await xcodebuildVersionTool({ sdk: "iphoneos" });Related Tools
xcodebuild-showsdks: Show all available SDKs
xcodebuild-list: List project information
Inputs: sdk, outputFormat.
xcode-model-inspectInspect Core Data / SwiftData ModelsARead-onlyIdempotent
xcode-model-inspect
Inspect Core Data .xcdatamodeld packages and SwiftData @Model classes from project source files. Pure file analysis — no simulator, no build required.
What it does
Recursively walks the project path and extracts:
Core Data (.xcdatamodeld)
Reads .xccurrentversion to determine the active model version
Parses entity XML: names, isAbstract, parentEntity, representedClass
Attributes: name, attributeType, optional, defaultValueString
Relationships: name, destinationEntity, toMany, inverseName, optional
Fetch requests: name, predicateString
SwiftData (@Model classes)
Detects @Model-decorated classes via regex
Extracts stored properties (var/let) excluding computed and @Relationship
Extracts @Relationship declarations with toMany detection ([] or Array<>)
Parameters
projectPath (string, optional): Root of Xcode project to inspect (default: '.')
coreDataOnly (boolean, optional): Skip SwiftData scanning
swiftDataOnly (boolean, optional): Skip Core Data scanning
showVersions (boolean, optional): Include all .xcdatamodel version entries with current flagged
raw (string, optional): Dump raw source for a named model (Swift class body or Core Data entity XML)
verbose (boolean, optional): Include per-entity/property breakdown in summary text
Returns
JSON response with:
coreData: array of parsed .xcdatamodeld packages with entities, attributes, and relationshipsswiftData: array of @Model classes with properties and relationshipssummary: compact human-readable summary textnote: present when no models are found (not an error)
structuredContent: { coreDataModels, swiftDataModels, totalEntities }
Examples
Inspect all models
await xcodeModelInspectTool({ projectPath: '/path/to/MyApp' })Core Data only with version history
await xcodeModelInspectTool({ projectPath: '/path/to/MyApp', coreDataOnly: true, showVersions: true })Dump raw source for a specific model
await xcodeModelInspectTool({ projectPath: '/path/to/MyApp', raw: 'Task' })Verbose output
await xcodeModelInspectTool({ projectPath: '/path/to/MyApp', verbose: true })Skipped Directories
node_modules, DerivedData, Pods, Carthage, .git, and any directory starting with '.'
Inputs: raw, verbose, projectPath, coreDataOnly, +2 more. Returns: totalEntities, coreDataModels, swiftDataModels
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 80 tools
Many tools overlap: simctl-install/launch/terminate/uninstall mirror idb-install/launch/terminate/uninstall, and screenshots are covered by screenshot, simctl-io, and app-state-capture. UI interaction is split across idb-ui-tap, idb-ui-gesture, idb-ui-input, idb-semantic-action, and workflow-tap-element, so an agent must decide between low-level and orchestrated paths.
Nearly all names use category-prefixed kebab-case (xcodebuild-build, simctl-boot, idb-ui-tap) with action-oriented suffixes, making the set predictable. Exceptions like screenshot, rtfm, and noun-phrase tools such as visual-diff and app-state-capture prevent a perfect score.
80 tools is extreme for a CLI wrapper; even with broad Xcode, simulator, and IDB scope, the surface is far beyond the 3-15 well-scoped range. The count is inflated by duplicate simulator/IDB app-management tools and workflow wrappers that could be operations or omitted.
Coverage is broad across build/test, simulator lifecycle, app install/launch, UI automation, screenshots, logs, crashes, permissions, and workflows. Minor gaps remain around build archive/export and consolidated test-result handling, but there are no major dead ends for the stated domain.
Maintenance
Related MCP Connectors
Agent Token Budget MCP — hard per-session token + spend cap with signed budget-exhausted
Single-connection meta-router indexing 500+ MCP servers & A2A tools with 85% token compression and
Remote MCP for Copilot CLI switch gate MCP, structured receipts, audit logs, and reviewer-ready evid
MCP-Native LLM Orchestration Agent
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables AI assistants to parse Xcode and Swift build outputs into structured, token-efficient formats like JSON or TOON. It provides tools for executing build commands and extracting detailed diagnostic information such as errors, warnings, and test failures.8MIT
- AlicenseNot gradedqualityBmaintenanceMCP server and CLI for iOS development — build, test, automate, and diagnose from any AI agent or terminal.2MIT
- AlicenseNot gradedqualityCmaintenanceToken-efficient MCP reimplementation with progressive tool discovery, result handling, and compact wire encoding, reducing token usage by up to 89% on tool definitions.1MIT
- AlicenseNot gradedqualityCmaintenanceFirst-party MCP server and CLI for Xcode and iOS Simulator automation. Enables control of Xcode and iOS Simulator via MCP tools for tasks like building, testing, and automation.7 npm1MIT