ios-agent
PYPI · IOS-MCP
Drive a real iPhone or an iOS Simulator with an AI agent, through XCUIAutomation.
Available components
Last scanned (18 hours ago)
Scores higher than 96% of PyPI servers
Category Browser Automation
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security100
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- Runs hatchling.build at install time, a recognised build step with no custom scripting around it. View diagnostics → Pass
- 1 of 22 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency100
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Cryptographically verified build provenance (signed, bound to emazaheri/ios-agent). View diagnostics → Pass
- Clear OSI-approved license (MIT).Pass
- Actively maintained (last published 28 days ago).Pass
- Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability84
- 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
- AI-judged instruction clarity (good).Pass
- Tool/resource definitions use about 3359 tokens (~93/item across 36 items; 31 tools + 5 resources), lean.Pass
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management70
- Stability observed for 21 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
- Structured output schemas are declared (97% of tools); any adoption earns full credit.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 33 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a current MCP spec version (2026-07-28).Pass
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 3 Nov 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 63 to 67. That category is still filling its 30-day observation window: 19 days of observed history at the previous scan, 20 at this one. The score rises as the window fills, whether or not the server changes.
- 1 Nov 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 57 to 60. That category is still filling its 30-day observation window: 17 days of observed history at the previous scan, 18 at this one. The score rises as the window fills, whether or not the server changes.
- 31 Oct 26 +15
- Malware scan: unverified → pass ▲ security
- 30 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 50 to 53. That category is still filling its 30-day observation window: 15 days of observed history at the previous scan, 16 at this one. The score rises as the window fills, whether or not the server changes.
- 28 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 43 to 47. That category is still filling its 30-day observation window: 13 days of observed history at the previous scan, 14 at this one. The score rises as the window fills, whether or not the server changes.
- 26 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 37 to 40. That category is still filling its 30-day observation window: 11 days of observed history at the previous scan, 12 at this one. The score rises as the window fills, whether or not the server changes.
- 25 Oct 26 −15
- Malware scan: pass → unverified ▼ security
- 24 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 30 to 33. That category is still filling its 30-day observation window: 9 days of observed history at the previous scan, 10 at this one. The score rises as the window fills, whether or not the server changes.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 4 Nov 2026 · Analysed pypi/ios-mcp@0.6.0
Provenance Verified
A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.
| Result | Verified |
|---|---|
| Ecosystem | pypi |
| Reason | Verified |
| Discovered via | Registry attestation endpoint |
| Source repo | emazaheri/ios-agent |
| Certificate issuer | https://token.actions.githubusercontent.com |
| Certificate SAN | https://github.com/emazaheri/ios-agent/.github/workflows/release.yml@refs/tags/v0.6.0 |
| Rekor log index | 3124145979 |
| Predicate type | PyPI publish attestation https://docs.pypi.org/attestations/publish/v1 |
| Subject digest | sha256:f0c8ffc90b478ab2fcd977e2e1c4b0b3dadc895e34171cf797ca8116261ccb81 |
Background: How many MCP packages publish verified provenance →
Install scripts 1 script
| Hook | Tier | Command |
|---|---|---|
| build_backend | allowlisted | hatchling.build |
Background: Why install scripts are a supply-chain risk →
Dependencies 22 packages
| Packages resolved | 22 |
|---|---|
| Stale | 1 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
ios_clipboard Ios Clipboard ~67
Read or write the device clipboard. Writing is often faster and more reliable than typing a long string, which the on-screen keyboard can mangle with autocorrect.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | – | 'get' or 'set'. |
| text | – | – | Text to write when action is 'set'. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_close_session Ios Close Session ~21
Release the device and shut down its WebDriverAgent runner.
Input schema present but exposes no named parameters.
Structured output declared, but exposes no named fields.
No examples provided.
ios_doctor Ios Doctor ~67
Check that this machine can drive an iOS device, and say how to fix what it can't. Run this first when a session fails to start, when a device does not appear, or after an Xcode or iOS upgrade. Every failing check comes with a concrete remedy.
Input schema present but exposes no named parameters.
Structured output declared, but exposes no named fields.
No examples provided.
ios_drag Ios Drag ~88
Drag one element onto another, for reordering lists and moving items.
| Name | Type | Req | Description |
|---|---|---|---|
| duration_s | number | – | Gesture duration. |
| from_ref | string | yes | Ref of the element to drag. |
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| to_ref | string | yes | Ref of the element to drop onto. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_export_trace Ios Export Trace ~38
Return the ordered record of everything this session has done. Useful for explaining what happened, and for turning a successful run into a regression test.
Input schema present but exposes no named parameters.
Structured output declared, but exposes no named fields.
No examples provided.
ios_find Ios Find ~208
Search the screen's accessibility tree, including what the digest hides. Prefer `ios_observe` with a `query` when you want a usable digest you can tap from: what it returns carries refs. Use this when `ios_observe` shows nothing matching but the text is on the device, or when a tap keeps missing. It reads the tree before compaction, so it reports matches the digest dropped, which `ios_observe` by construction cannot, and each one says whether it is `shown` or `hidden`. A hidden match is the diagnosis: the words are on screen and perception is why you cannot reach them. Name it by the `id` reported here.
| Name | Type | Req | Description |
|---|---|---|---|
| budget | – | – | The budget you observed with. It decides `shown`, so pass it whenever you set one on ios_observe. |
| limit | integer | – | Most matches to return. |
| text | string | yes | Text to look for, matched case-insensitively. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_get_logs Ios Get Logs ~70
Read recent device logs. Useful when an app misbehaves and the UI does not say why.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Maximum lines to return. |
| predicate | – | – | Filter: an NSPredicate on a Simulator, else a substring. |
| since_s | number | – | How far back to read. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_halt Ios Halt ~30
Stop this session from taking further action.
| Name | Type | Req | Description |
|---|---|---|---|
| reason | string | – | Why the session is being stopped. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_handle_alert Ios Handle Alert ~67
Answer a system alert. Read the alert text before choosing. Accepting blindly is how an agent grants a permission or confirms a deletion nobody wanted.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | 'accept' or 'dismiss'. |
| button | – | – | Exact button label, when the alert has several. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_install_app Ios Install App ~38
Install an app from a local .app or .ipa.
| Name | Type | Req | Description |
|---|---|---|---|
| path | string | yes | Path to a .app bundle or .ipa file. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_launch_app Ios Launch App ~52
Bring an app to the foreground and return its screen.
| Name | Type | Req | Description |
|---|---|---|---|
| bundle_id | string | yes | e.g. com.apple.Preferences |
| fresh | boolean | – | Restart the app instead of resuming where it was. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_list_apps Ios List Apps ~37
List apps installed on the device, with their bundle identifiers.
| Name | Type | Req | Description |
|---|---|---|---|
| kind | string | – | 'user', 'system', or 'all'. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_list_devices Ios List Devices ~62
List iOS Simulators and attached physical iPhones available for automation. `ready` is false when something blocks automation; `blockers` says what.
| Name | Type | Req | Description |
|---|---|---|---|
| kind | string | – | Filter by device kind: 'simulator', 'device', or 'all'. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_observe Ios Observe ~171
Read the screen as a compact list of elements with short refs. Each line is one element: `e7 button "Send" @(340,70)`. Pass those refs to the action tools rather than coordinates. If the result says elements were omitted, narrow with `query` or `region` instead of raising `budget`; a smaller answer is usually the more useful one.
| Name | Type | Req | Description |
|---|---|---|---|
| budget | – | – | Token budget for the digest. Default 1500. |
| include_elements | boolean | – | Also return each element as structured JSON. Roughly doubles the cost and duplicates the text form; only useful programmatically. |
| query | – | – | Keep only elements whose text contains this. Use when truncated. |
| region | – | – | Restrict to a screen area as [x, y, width, height]. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_open_session Ios Open Session ~131
Attach to a device and start driving it. Boots the simulator or verifies the phone, starts WebDriverAgent, and opens a tuned session. Omitting `device` prefers an already-booted simulator over a connected iPhone, so acting on a real device is always a deliberate choice.
| Name | Type | Req | Description |
|---|---|---|---|
| app | – | – | Bundle id to open, e.g. com.apple.Preferences. |
| device | – | – | UDID, exact name, or part of a name. Omit to pick the best default. |
| fresh | boolean | – | Relaunch the app from scratch rather than resuming it. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_open_url Ios Open Url ~85
Open a URL or deep link. Usually the cheapest way to reach a screen: a deep link skips the navigation an agent would otherwise have to tap through.
| Name | Type | Req | Description |
|---|---|---|---|
| url | string | yes | A URL or deep link, e.g. maps://?q=coffee or https://example.com. From iOS 26 a Settings link opens Settings but not the pane it names. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_press_button Ios Press Button ~76
Press a hardware button or a keyboard key.
| Name | Type | Req | Description |
|---|---|---|---|
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| name | string | yes | Hardware: home, volumeUp, volumeDown, siri. Keyboard: enter, tab, delete, space, dismiss_keyboard. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_read_text Ios Read Text ~70
Read the text of the screen, or of one element and everything inside it. Use this to extract content, rather than `ios_observe`, which is shaped for deciding what to tap.
| Name | Type | Req | Description |
|---|---|---|---|
| ref | – | – | Read only inside this element. |
| target | – | – | Read inside the element matching this description. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_resume Ios Resume ~22
Clear a halt after a human has decided it is safe to continue.
Input schema present but exposes no named parameters.
Structured output declared, but exposes no named fields.
No examples provided.
ios_screenshot Ios Screenshot ~142
Capture the screen as an image. Use this when an element has no accessibility label, when the layout matters, or when `ios_observe` cannot find something you can plainly see. With `annotate_refs` each element is boxed and labelled with its ref, so you can pick one by eye and pass it to an action tool. Annotating re-reads the screen first, so the refs on the image are the current ones rather than whatever was observed last. That costs a tree fetch, and needs the `vision` extra installed.
| Name | Type | Req | Description |
|---|---|---|---|
| annotate_refs | boolean | – | Draw labelled boxes over the elements, using fresh refs. |
No output schema declared.
No examples provided.
ios_scroll Ios Scroll ~165
Scroll, optionally until some text comes into view. With `until`, this stops as soon as the text appears and gives up when the content stops moving, so it will not spin at the end of a list.
| Name | Type | Req | Description |
|---|---|---|---|
| direction | string | – | up, down, left, or right. |
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| max_scrolls | integer | – | Cap on repeats when `until` is set. |
| ref | – | – | A ref from the last observation, such as 'e7'. Preferred. |
| target | – | – | Plain description of the element, e.g. 'the Send button'. Used if no ref. |
| until | – | – | Keep scrolling until this text appears. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_session_status Ios Session Status ~23
Report the current session: device, foreground app, and safety state.
Input schema present but exposes no named parameters.
Structured output declared, but exposes no named fields.
No examples provided.
ios_set_device_state Ios Set Device State ~83
Change device-level state. Appearance, location, and status bar are Simulator only.
| Name | Type | Req | Description |
|---|---|---|---|
| appearance | – | – | 'light' or 'dark'. |
| clean_status_bar | boolean | – | Freeze the status bar so screenshots are reproducible. |
| latitude | – | – | Simulated latitude. |
| longitude | – | – | Simulated longitude. |
| orientation | – | – | 'portrait' or 'landscape'. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_set_permission Ios Set Permission ~98
Set a privacy permission without going through the alert. Simulator only. On a real phone there is no API for this: drive the Settings app, or answer the permission alert with ios_handle_alert.
| Name | Type | Req | Description |
|---|---|---|---|
| bundle_id | string | yes | App to grant or revoke for. |
| grant | boolean | – | True to grant, False to revoke. |
| service | string | yes | location, photos, camera, microphone, contacts, calendar, or all. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_set_value Ios Set Value ~270
Set a switch, slider, or picker wheel to a value. 'on' or 'off' for a switch, a percentage such as '40%' or a fraction for a slider, and the option spelled the way the wheel spells it for a picker. A wheel is turned a row at a time and read back after each one, so an option it does not contain fails listing what it does. Prefer this over tapping a switch: it checks the current state first, so asking for 'on' when it is already on does nothing rather than turning it off. Steppers and segmented controls are not set this way. iOS reports their parts and the digest shows them, so tap 'Increment', 'Decrement', or the segment by its own label.
| Name | Type | Req | Description |
|---|---|---|---|
| approve | – | – | Signature returned by a previous action_requires_approval error. |
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| ref | – | – | A ref from the last observation, such as 'e7'. Preferred. |
| target | – | – | Plain description of the element, e.g. 'the Send button'. Used if no ref. |
| value | string | yes | 'on'/'off' for switches, otherwise the value. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_swipe Ios Swipe ~111
Swipe once, for carousels, page views, and swipe-to-reveal rows.
| Name | Type | Req | Description |
|---|---|---|---|
| direction | string | yes | up, down, left, or right. |
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| ref | – | – | A ref from the last observation, such as 'e7'. Preferred. |
| target | – | – | Plain description of the element, e.g. 'the Send button'. Used if no ref. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_tap Ios Tap ~178
Tap an element and return the resulting screen. Prefer `ref` over `target`; it is exact and cannot be misread. Taps on things like Send, Pay, or Delete need approval first.
| Name | Type | Req | Description |
|---|---|---|---|
| approve | – | – | Signature returned by a previous action_requires_approval error. |
| double | boolean | – | Double tap. |
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| long_press_s | – | – | Press and hold for this many seconds. |
| ref | – | – | A ref from the last observation, such as 'e7'. Preferred. |
| role | – | – | Narrow by role, e.g. 'button', 'cell', 'switch'. |
| target | – | – | Plain description of the element, e.g. 'the Send button'. Used if no ref. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_terminate_app Ios Terminate App ~31
Force-quit an app.
| Name | Type | Req | Description |
|---|---|---|---|
| bundle_id | string | yes | Bundle id of the app to kill. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_type Ios Type ~197
Type into a field, focusing it first when a ref or target is given. The field is read back afterwards. If the text did not land, the call fails with `typed.shown` saying what the field holds; `reformatted` means it landed with the app's own capitalisation or formatting.
| Name | Type | Req | Description |
|---|---|---|---|
| approve | – | – | Signature returned by a previous action_requires_approval error. |
| clear_first | boolean | – | Replace the field's contents. |
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| ref | – | – | A ref from the last observation, such as 'e7'. Preferred. |
| submit | boolean | – | Press return afterwards. |
| target | – | – | Plain description of the element, e.g. 'the Send button'. Used if no ref. |
| text | string | yes | Text to type. Never a password; see ios_type_secret. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_type_secret Ios Type Secret ~167
Type a stored secret without ever seeing its value. The value is read from the host keychain and sent straight to the device. Use this for every password and one-time code; never put a real credential into `ios_type`, where it would enter the transcript.
| Name | Type | Req | Description |
|---|---|---|---|
| idem_key | – | – | Optional key making a retry a no-op. Pass the same key when repeating an action you are unsure completed. |
| ref | – | – | A ref from the last observation, such as 'e7'. Preferred. |
| secret_ref | string | yes | Name of a stored secret, e.g. 'icloud-password'. Not the value. |
| submit | boolean | – | Press return afterwards. |
| target | – | – | Plain description of the element, e.g. 'the Send button'. Used if no ref. |
Structured output declared, but exposes no named fields.
No examples provided.
ios_wait_for Ios Wait For ~98
Wait for something to appear or disappear. Prefer this over guessing a sleep. It returns as soon as the condition holds, and reports failure rather than raising, so a timeout is something you can reason about.
| Name | Type | Req | Description |
|---|---|---|---|
| absent | boolean | – | Wait for the text to disappear instead of appear. |
| text | string | yes | Text to wait for, matched case-insensitively. |
| timeout_s | number | – | How long to wait. |
Structured output declared, but exposes no named fields.
No examples provided.
How do I install the ios-agent MCP server?
ios-agent runs locally as a PyPI package, launched with uvx ios-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
pypi · ios-mcp
claude mcp add emazaheri-ios-agent -- uvx ios-mcp
What is the ios-agent MCP server?
ios-agent is an MCP server listed in the public MCP registry as io.github.emazaheri/ios-agent. Drive a real iPhone or an iOS Simulator with an AI agent, through XCUIAutomation. This page covers its PyPI package (ios-mcp).
Is the ios-agent MCP server safe to use?
ios-agent scores 93 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 4 November 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the ios-agent MCP server expose?
ios-agent exposes 31 tools: ios_doctor, ios_list_devices, ios_open_session, ios_session_status, ios_close_session, and 26 more. Their descriptions and schemas cost roughly 2,963 tokens of context every time the server is loaded.
Is the ios-agent MCP server still maintained?
ios-agent is still listed as active in the MCP registry. We last reached this channel on 4 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the ios-agent MCP server under?
ios-agent declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.