ios-safari-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| HACKIOS_DIR | No | Path to the HackiOS kernel/userland tree (default is ../hackios next to a checkout, then ~/hackios). |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| guest_processB | Is a process running in the guest (by name, e.g. MobileSafari, wi_relay)? Returns pid and thread count. |
| log_tailC | Last lines of the guest console log, optionally filtered by a regex. |
| waitA | Sleep up to 60 s (the guest is slow; animations take time). |
| tapA | Tap. x and y are fractions of the screen, 0,0 top left. For a page element use tap_element. |
| holdC | Touch and hold. |
| swipeB | Swipe. Swipe up from y=0.985 to open or leave an app; from the left edge for back. |
| keyC | Press a hardware button: lock, home, volup, voldown. |
| tap_pxC | Tap a point given in pixels of a screenshot you took (set scale to the same value as the screenshot). |
| type_textA | Type by tapping the keys of the on-screen keyboard, which must be showing: slow (about 2.5 s a key) but real key events. Lower-case letters, digits, space and . - / : ( ) ; $ & @ " are known; set submit to press go. For fast input use fill. |
| scrollC | Scroll the page (direction up/down/left/right, amount as a fraction of the screen, default 0.4). |
| backA | Back in Safari: taps the toolbar back arrow (the toolbar must be showing; scroll up a little or tap the bottom bar first). method=swipe uses the left-edge gesture, which did not navigate in testing. |
| home_screenC | Leave the app: swipe up from the bottom edge. |
| wakeC | Wake the display (it turns off after boot): a tap and then the home key. |
| inspector_pagesB | List the pages that Safari offers to the Web Inspector (title, url). Safari must be running with a page open; safari_ready makes sure of that. |
| jsC | Run a JavaScript expression in the page and return its value as JSON. Milliseconds, no screenshot or typing. |
| domB | Query the DOM by CSS selector. what=info (default: tag, text, attributes, rect in CSS px, visible), html (outerHTML) or text. |
| open_urlA | Open an address in Safari: through the inspector when a page exists (about 3 s), else by asking SpringBoard (starts Safari too). No typing. typing=true types it on the keyboard instead (minutes). |
| navigateC | Same as open_url (no typing): load an address. |
| reloadC | Reload the page. |
| console_messagesC | Console messages of the page since the inspector attached (level, text, url). |
| network_logC | Requests of the page since the inspector attached: url, method, status, mime type, failures. |
| inspector_rawC | Send any Web Inspector protocol command to the page (e.g. Page.getCookies, DOM.getDocument, Debugger.enable) and return the result. |
| inspector_closeA | End the inspector connection (a page takes one frontend at a time). The next inspector call reconnects. |
| safari_readyB | Get Safari running with a page the inspector lists, without a tap or typing: asks SpringBoard to open |
| keyboard_stateA | Is the keyboard up, how tall is it, and what does it cover? Returns the layout and visual viewport, the focused field and whether it is visible above the keyboard, the interactive elements and popups that reach under the keyboard, and the fixed or sticky elements (with behindKeyboard set when a bar is hidden by it). Heights are CSS px. |
| keyboard_showA | Open the keyboard on a field with a real tap (script focus() does not open it on iOS): scrolls the field into view, finds where it is on the screen, taps it, and waits until the visual viewport has shrunk. Returns the state with the keyboard up. |
| keyboard_hideA | Close the keyboard and wait for the viewport to recover. method=blur (default) blurs the field, as a page does; done taps Safari's Done button above the keyboard (what a user presses); return taps the keyboard's bottom right key (it may submit a form); tap_outside taps a point of the page outside the field (x and y in CSS px; default the left edge). |
| keyboard_eventsA | Record what the page sees around the keyboard: focusin/focusout, keydown/keyup, beforeinput/input, composition events and every window and visualViewport resize or scroll, each with the viewport numbers at that moment. action=start installs the recorder (a navigation removes it), read returns the events (since = how many to skip), stop removes it. |
| tap_elementB | Tap the middle of a page element by CSS selector, with a real touch at the right screen position (measured, so it is right whatever Safari's bars and the keyboard are doing). |
| tap_cssB | Tap a point given in CSS pixels of the layout viewport (what getBoundingClientRect returns). |
| fillA | Set the value of a field the way a framework notices (native setter, then input and change events). Fast, but synthetic: no key events, no keyboard, no autocorrect or composition. Use keyboard_show and type_text for those. |
| scroll_into_viewC | Scroll an element into view (block: start, center, end or nearest). |
| keyboard_checkA | Open the keyboard on a field and report whether it covers anything important: the field itself, fixed bars, suggestion popups. Optionally puts a value in the field first, to bring up suggestions. Returns the report and a screenshot with the keyboard up, then closes the keyboard and checks that the viewport recovers. |
| screenshotA | PNG of the phone screen (1125x2436, scaled down by |
| settleA | Wait until the screen stops changing (two frames equal for stable_for seconds) or the timeout ends. |
| vm_startA | Boot HackiOS in QEMU in the background. Takes 9 to 14 minutes under software emulation; restoring a snapshot takes about 30 s. Then call safari_ready. |
| vm_saveA | Save the whole machine state to a named snapshot (takes a minute or more, files are GB). Restore with vm_start(snapshot=name). Only works for a VM started with saveable=true. |
| vm_snapshotsB | List saved snapshots. |
| vm_stopB | Stop QEMU. |
| vm_statusB | Is QEMU running, did it panic, did the guest accept the touchscreen, and which boot phase was reached. |
| wait_forA | Block until a boot phase is reached (kernel, launchd, backboardd_ready, springboard_owns_screen, or running for a restored snapshot) or the timeout (max 280 s) ends. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 41 tools
Several tools have overlapping boundaries: open_url and navigate are explicitly the same operation, and tap, tap_px, tap_css, and tap_element differ mainly by coordinate system, while fill versus keyboard_show/type_text represent competing input paths. Descriptions do a good job explaining when to use each variant, but the set still requires careful reading to avoid misselection.
All names use a consistent snake_case convention with no camelCase mixing, and related tools are grouped by prefix (keyboard_*, vm_*, inspector_*). The only minor inconsistency is that some names are imperative verbs while others are nouns or bare operations (js, dom, screenshot, settle), but all remain readable and predictable.
At 41 tools, the surface is very heavy for a single MCP server, even accounting for the complex VM, touch, inspector, and keyboard domains. Several tools could be collapsed or made modes of existing tools, such as open_url/navigate and the multiple tap and keyboard entry points.
Coverage is broad: VM lifecycle, touch input, text entry, navigation, Web Inspector access, console/network logs, keyboard diagnostics, screenshots, and settling. Minor gaps remain around app lifecycle beyond Safari, accessibility-tree-style element discovery, and other device interactions, but core Safari automation workflows are well supported.