{"name":"io.github.rmathew1973/ios-sim-mcp","slug":"rmathew1973-ios-sim-mcp","title":null,"description":"Drive the iOS Simulator via semantic accessibility-tree snapshots. Sub-200ms, no WebDriverAgent.","url":"https://mcp.market/server/rmathew1973-ios-sim-mcp","rating":null,"grade":"A","score":88,"certified":false,"status":"active","category":"productivity","tags":["productivity"],"presence":{"score":18,"stars":0,"forks":0,"downloads_week":32,"last_push_at":"2026-08-03T03:13:26.000Z","license":"MIT"},"uptime":null,"claimed":false,"transport":"npm","callable_via_gateway":false,"default_price_micros":0,"repository":"https://github.com/rmathew1973/ios-sim-mcp","website":null,"version":"0.4.2","remotes":[],"packages":[{"registryType":"npm","identifier":"ios-sim-mcp","version":"0.4.2","transport":{"type":"stdio"}}],"tools":[{"name":"await_quiescent","description":"Block until the accessibility tree stops changing (UI settles). Returns when the tree hash is identical for 'stable_ms' (default 250) consecutive ms, or 'timeout_ms' elapses (default 5000). Use after launch_app, navigation, or async loads instead of sleep.","write_action":false,"price_micros":0,"input_schema":null},{"name":"button","description":"Press a hardware button: HOME, LOCK, SIDE_BUTTON, SIRI, APPLE_PAY.","write_action":false,"price_micros":0,"input_schema":null},{"name":"dylib_call","description":"Generic escape hatch: invoke an arbitrary method on the Layer 2 dylib. Use dylib_info first to see available methods. Passes 'params' through verbatim. Future phases (2c view_tree, 2d network_*, 2e eval_js) add methods this can reach.","write_action":false,"price_micros":0,"input_schema":null},{"name":"dylib_health","description":"Lightweight liveness probe for the Layer 2 dylib. Returns {available, ...stats} when reachable, {available: false, reason} when not. Does NOT throw — safe to call as a feature-detection precheck before reaching for dylib-only tools. Stats include: bundle_id, pid, uptime_s, phase, whether network capture is running, record/stub counts, JS context status, method count.","write_action":false,"price_micros":0,"input_schema":null},{"name":"dylib_info","description":"Ask the Layer 2 dylib to describe its host process: pid, bundle id, process name, bundle path, uptime, and the list of RPC methods it exposes.","write_action":false,"price_micros":0,"input_schema":null},{"name":"dylib_ping","description":"Round-trip a ping to the Layer 2 dylib inside an injected app. Returns the response plus measured RTT in ms. Use this first to verify the dylib is loaded and reachable.","write_action":false,"price_micros":0,"input_schema":null},{"name":"eval_js","description":"Run arbitrary JavaScript inside the injected app via JavaScriptCore. Bridged globals: `app` (UIApplication), `key_window()`, `all_windows()`, `defaults` (NSUserDefaults), `pasteboard` (UIPasteboard), `bundle`, `process`, `notif_center`, `first_responder()`, `find_view_by_ax_id(id)`, `find_view_by_class(name)`, `find_vc_by_class(name)`, `post_notification(name, userInfo?)`, `cls(name)` (NSClassFrom","write_action":true,"price_micros":0,"input_schema":null},{"name":"eval_js_reset","description":"Drop the persistent JSContext inside the injected app. Variables and helper functions you defined via eval_js are forgotten; bridged globals are reinstalled on the next eval_js call.","write_action":true,"price_micros":0,"input_schema":null},{"name":"find","description":"Search the most recent snapshot for elements. Combine fields with AND. 'id' matches AXUniqueId exactly. 'label' is exact match; 'labelContains' is case-insensitive substring across label/value/title. 'role' accepts 'Button', 'TextField' etc (with or without AX prefix). Auto-snapshots if none cached.","write_action":false,"price_micros":0,"input_schema":null},{"name":"key","description":"Press a single key. Pass either {name} (RETURN, ESCAPE, DELETE, TAB, SPACE, F1-F12, UP/DOWN/LEFT/RIGHT) or {code} (raw HID usage code).","write_action":false,"price_micros":0,"input_schema":null},{"name":"launch_app","description":"Launch an app by bundle id (com.example.App). 'foreground_if_running' terminates first. 'inject' loads the Layer 2 dylib (default path: dylib/build/libios-sim-mcp.dylib relative to the server) via SIMCTL_CHILD_DYLD_INSERT_LIBRARIES — currently just emits a lifecycle log line; future phases add a Unix socket. 'inject_dylib' overrides the dylib path. Inject requires the dylib to be built (run dylib/","write_action":false,"price_micros":0,"input_schema":null},{"name":"list_simulators","description":"List iOS simulators (booted and shutdown). Returns udid, name, state, os_version.","write_action":false,"price_micros":0,"input_schema":null},{"name":"log_clear","description":"Clear the in-memory log buffer.","write_action":false,"price_micros":0,"input_schema":null},{"name":"log_start","description":"Start streaming os_log from the simulator into an in-memory buffer (5000 lines max). Optional bundle_id filters by subsystem substring. Level: default|info|debug.","write_action":false,"price_micros":0,"input_schema":null},{"name":"log_stop","description":"Stop the log stream subprocess. Buffer is preserved until log_clear or log_start.","write_action":false,"price_micros":0,"input_schema":null},{"name":"log_tail","description":"Return the last N lines from the log buffer (default 100). Requires log_start first.","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_clear","description":"Drop all captured records and their bodies. Does not change running state.","write_action":true,"price_micros":0,"input_schema":null},{"name":"network_get_body","description":"Fetch the full request or response body for a captured record. Bodies up to max_body_bytes (default 256KB) are retained per record; larger bodies were truncated at capture time and the response will mark truncated=true. Returns base64 plus a UTF-8 decode when the body is text.","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_self_test","description":"Fire a real HTTP request from inside the injected app to validate the capture path end-to-end. Useful when the host app makes no network calls of its own during a smoke test. Requires network_start first.","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_start","description":"Start capturing HTTP traffic from the injected app's URLSession-based code. Installs an URLProtocol subclass + swizzles +defaultSessionConfiguration / +ephemeralSessionConfiguration so requests made via Alamofire, URLRequest, SwiftUI AsyncImage, or any URLSession-based client are recorded into an in-process ring buffer. Existing URLSessions constructed before start are NOT retro-fitted. Requires d","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_status","description":"Report whether capture is running, how many records are held, and current config (max_records, max_body_bytes, filter).","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_stop","description":"Stop capturing HTTP traffic. The ring buffer is preserved until network_clear; you can keep calling network_tail on captured records after stopping.","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_stub","description":"Register an HTTP stub. When an outgoing request's URL contains `url_substring` (and matches `method` if given), the dylib synthesizes a canned response (status, headers, body) instead of forwarding. Stubbed requests still appear in network_tail with `stubbed:true` and `stub_id`. First-match-wins by insertion order. `body` is a UTF-8 string; pass `body_base64` for binary. `delay_ms` simulates slow ","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_stubs","description":"List currently registered HTTP stubs (id, url_substring, method filter, status, body preview, delay, when added). Raw body bytes are not returned — call network_get_body on a captured record if you need the actual body delivered.","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_tail","description":"Return the most recent N captured records (default 50). Each record shows id, method, status, timing, sizes, URL. Pass full=true to include headers + body previews inline; otherwise call network_get_body({id}) to fetch a specific full body. Use since_id to page forward from a previous tail.","write_action":false,"price_micros":0,"input_schema":null},{"name":"network_unstub","description":"Remove a single HTTP stub by id (as returned from network_stub / network_stubs).","write_action":true,"price_micros":0,"input_schema":null},{"name":"network_unstub_all","description":"Remove all HTTP stubs.","write_action":true,"price_micros":0,"input_schema":null},{"name":"paste_text","description":"Byte-perfect text input via UIPasteboard + first-responder paste:. Requires the Layer 2 dylib injected and a text field already focused (call tap first). No iOS autocorrect, no capitalization, no smart-quote replacement — what you pass is exactly what the field receives. Use for emails, passwords, OAuth tokens, anything case-sensitive.","write_action":false,"price_micros":0,"input_schema":null},{"name":"screenshot","description":"Capture a screenshot. If 'path' is provided, saves PNG and returns the path. Otherwise saves to a temp file and returns both the path and the image inline. Use sparingly — the AX tree is faster and richer for control flow.","write_action":false,"price_micros":0,"input_schema":null},{"name":"scroll","description":"Scroll a scrollable view. Direction is reader-perspective: 'down' reveals content below (finger drags up); 'up' reveals content above. Optional 'ref' or 'id' to anchor the gesture on a specific scrollable; otherwise uses screen center. 'distance' px (default 300). Default 0.4s duration ensures iOS treats it as a pan, not a tap.","write_action":false,"price_micros":0,"input_schema":null},{"name":"snapshot","description":"Capture the simulator's accessibility tree and return it with stable refs (e1, e2, ...). Subsequent tap/type/swipe accept refs. Default filter 'interactive' hides decorative containers; use 'all' for everything, 'actionable' for only tappable controls. Always call this before acting on UI.","write_action":false,"price_micros":0,"input_schema":null},{"name":"swipe","description":"Swipe from one point to another. Pass from_ref/from_id or from_x+from_y AND to_ref/to_id or to_x+to_y. Optional duration (seconds) and delta (px step).","write_action":false,"price_micros":0,"input_schema":null},{"name":"tap","description":"Tap an element. Pass one of: {ref} from latest snapshot, {id} for AXUniqueId, or {x,y} for raw coordinates. Optional 'duration' (seconds) makes it a long-press.","write_action":false,"price_micros":0,"input_schema":null},{"name":"terminate_app","description":"Terminate an app by bundle id.","write_action":false,"price_micros":0,"input_schema":null},{"name":"type_text","description":"Type text into the focused field. Pass ref/id to tap a field first. Newlines/tabs aren't interpreted — use the key tool for RETURN/TAB. via='paste' (default 'auto') routes through the Layer 2 dylib's UIPasteboard so input arrives byte-perfect: no iOS autocorrect, no first-letter capitalization, no shifted-symbol translation — critical for emails, passwords, anything case-sensitive. 'auto' uses pas","write_action":false,"price_micros":0,"input_schema":null},{"name":"use_simulator","description":"Select a specific simulator by UDID for subsequent calls. If only one is booted, auto-selection happens on first action — you only need this when multiple are booted.","write_action":false,"price_micros":0,"input_schema":null},{"name":"view_get_text","description":"Look up a view by AXUniqueId or class name and return its text content (UILabel.text / UIButton.currentTitle / UITextField.text / UITextView.text), plus accessibility label/value as fallback context. Faster than view_tree when you just need 'what does this control say right now?'. Requires the dylib injected.","write_action":false,"price_micros":0,"input_schema":null},{"name":"view_hit_test","description":"Ask the running app what view sits topmost at (x,y) in window coords, plus the full responder chain up to UIApplication. The right tool for 'tap at (201,406) isn't doing what I expect' — you see exactly which view receives the hit, whether it's userInteractionEnabled, and what view controllers are in the chain. Requires the dylib injected.","write_action":false,"price_micros":0,"input_schema":null},{"name":"view_set_text","description":"Set the text on a UILabel / UITextField / UITextView / any view that responds to setText:. Bypasses focus + keyboard entirely. Use to seed test data directly into a non-focused field, or to programmatically change a label's text mid-test. Requires the dylib injected.","write_action":false,"price_micros":0,"input_schema":null},{"name":"view_tree","description":"Walk the running app's UIView hierarchy on the main thread and return a compact text rendering. Strictly richer than snapshot: catches custom-drawn views, transient overlays, things SwiftUI synthesizes that AX flattens; reports actual class names (UIButton vs _UIRoundedRectButton), exact frames in window coords, alpha/hidden/userInteractionEnabled, and annotates which views are a UIViewController'","write_action":false,"price_micros":0,"input_schema":null}],"scan":{"score":88,"grade":"A","scanned_at":"2026-09-27T21:27:57.434Z","report":{"scannerVersion":"0.1.9","scannedAt":"2026-09-27T21:27:57.433Z","components":{"code":{"score":25,"max":25,"notes":["11 source files scanned"]},"reliability":{"score":-1,"max":20,"notes":["no gateway calls yet and no remote to probe"]},"poisoning":{"score":-1,"max":15,"notes":["tools not inspected (local package is not executed); not counted"]},"auth":{"score":12,"max":15,"notes":["local package, no credentials required"]},"maintenance":{"score":12,"max":15,"notes":["last push 56 days ago"]},"identity":{"score":8,"max":10,"notes":["registry namespace matches repository owner","GitHub account older than a year"]}},"findings":[],"inputs":{"packages":[{"registryType":"npm","identifier":"ios-sim-mcp","version":"0.4.2","found":true,"license":"MIT","hasInstallScripts":false,"dependencyCount":2,"publishedAt":"2026-05-18T17:52:54.834Z","repositoryUrl":"git+https://github.com/rmathew1973/ios-sim-mcp.git","weeklyDownloads":32}],"repo":{"found":true,"owner":"rmathew1973","repo":"ios-sim-mcp","archived":false,"pushedAt":"2026-08-03T03:13:26Z","stars":0,"forks":0,"openIssues":0,"ownerType":"User","ownerAvatarUrl":"https://avatars.githubusercontent.com/u/10277046?v=4","ownerCreatedAt":"2014-12-23T05:43:59Z","license":"MIT"},"icon":{"url":"https://avatars.githubusercontent.com/u/10277046?v=4&s=128","source":"github"},"presence":{"stars":0,"forks":0,"downloadsWeek":32,"license":"MIT","lastPushAt":"2026-08-03T03:13:26.000Z","score":18}}}},"grade_history":[],"reviews":[]}