Hand your iOS simulator to your agent. Claude-native MCP driver for iOS simulator testing — vision, taps, recordings.
Project description
simdrive
Hand your iOS simulator to your agent.
Claude-native MCP server for driving iOS simulators. Vision-first. No XCTest, no accessibility-tree query, no daemons. Your agent looks at a screenshot, picks a pixel, and simdrive taps it.
Why
You stay in your editor. Your agent drives the sim in the background. Taps don't steal focus, your keyboard doesn't get hijacked.
Automating an iOS simulator from inside an LLM session has historically required:
- A Swift XCTest runner that breaks every Xcode release
- An accessibility tree your agent has to mentally reconstruct from JSON dumps
- Bespoke selectors (
label:"Sign in") that drift with every UI change - Watchdogs killing your runner mid-test
simdrive replaces all of that with: screenshot in, click out. Your agent already understands screenshots — the LLM is the selector engine.
Install
pip install simdrive
Requirements:
- macOS with Xcode + iOS Simulator (for native HID input)
- A booted simulator. simdrive will use a running one or boot one for you.
simdrive runs in the background by default — taps and keystrokes go straight to the simulator without raising its window or stealing your keyboard focus. Verify via session_status (mode: "background").
Wire into Claude
Add to your .mcp.json:
{
"mcpServers": {
"simdrive": { "command": "simdrive" }
}
}
Restart Claude Code. The 12 simdrive tools are now available.
Quickstart
You: open Settings on iPhone 17 Pro and turn on Airplane Mode.
Claude (using simdrive):
→ session_start({device: "iPhone 17 Pro", app_bundle_id: "com.apple.Preferences"})
→ observe() # screenshot + annotated copy with numbered marks
→ tap({text: "Airplane Mode"}) # by visible text
→ observe() # sees the toggle
→ tap({mark: 12}) # by mark number from the annotation
→ observe() # confirms it's green
You can also tap({x, y}) if you have specific pixel coords (great for replay). Pick whichever is lowest-friction per call:
| Form | Use it for |
|---|---|
{text: "..."} |
Buttons, labels, anything with visible text |
{mark: N} |
When the agent has just looked at the annotated screenshot |
{x, y} |
Replays, deterministic UI tests, icons without text |
That's the whole loop. No selectors. No waits. No XCTest.
Tool surface (12 tools)
| Tool | Purpose |
|---|---|
session_start |
Boot/find a sim, optionally launch an app |
session_end |
End session (sim stays booted) |
session_status |
Inspect active session(s) |
observe |
Capture screenshot (returns file path), optional log tail |
tap |
Click at screenshot pixel coordinate |
swipe |
Drag from (x1,y1)→(x2,y2) |
type_text |
Send keyboard input |
press_key |
Hardware buttons (home, lock, siri, shake, return, etc.) |
record_start |
Begin recording every action |
record_stop |
Finalize recording.yaml |
replay |
Re-execute a recording with SSIM drift detection |
logs |
Tail simulator logs (NSPredicate filterable) |
Coordinates are always in screenshot pixel space — same pixels the agent sees in the most recent observe.
Recording + replay
record_start({name: "checkout-flow"})
... agent does the flow naturally, calling tap/swipe/type_text ...
record_stop() # writes ~/.simdrive/recordings/checkout-flow/recording.yaml
Later:
replay({name: "checkout-flow", on_drift: "halt"})
Each step is gated on visual similarity: if the live screen has drifted from the recorded pre-screenshot, the replay halts (halt), warns and continues (warn), or proceeds blind (force). The recording is a self-contained YAML+PNG bundle you can commit to your repo.
Testing
pip install simdrive[dev]
pytest # 22 unit tests, no sim required
pytest -m live # 26 live tests against TestKitApp
Live tests boot a fresh TestKitApp session per test and exercise every tool: tap by text/mark/coords, type into focused fields, swipe-to-scroll, alert-while-focused dismissal (the iOS 26 case that defeated v15), record + replay with drift detection.
What this isn't
- Not a real-device tool. v0.1 is simulator-only. Real device support via
idb/devicectlis on the roadmap. - Not a CI replacement (yet). Designed for interactive Claude sessions; CI integration is a follow-up.
- Not a fork of XCTest. We deliberately avoid Apple's testing stack to stay durable across Xcode releases.
License
MIT. Built by SyncTek.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file simdrive-0.3.0a1.tar.gz.
File metadata
- Download URL: simdrive-0.3.0a1.tar.gz
- Upload date:
- Size: 71.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4edf4f690b5768000484025ac3052dec76db4a597c461aaf593be4081e3bef5
|
|
| MD5 |
7d07e7ac9ed8ec624428c586baa84f6d
|
|
| BLAKE2b-256 |
a0781fd9ce522f7a3c60765ddd8fc00903afe7c2510d2abbfbc32ef6c92033a7
|
Provenance
The following attestation bundles were made for simdrive-0.3.0a1.tar.gz:
Publisher:
simdrive-publish.yml on SyncTek-LLC/specterqa-ios
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
simdrive-0.3.0a1.tar.gz -
Subject digest:
b4edf4f690b5768000484025ac3052dec76db4a597c461aaf593be4081e3bef5 - Sigstore transparency entry: 1410943345
- Sigstore integration time:
-
Permalink:
SyncTek-LLC/specterqa-ios@e994c289777b5db612224dde64ce744d18b87fc4 -
Branch / Tag:
refs/tags/simdrive-v0.3.0a1 - Owner: https://github.com/SyncTek-LLC
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
simdrive-publish.yml@e994c289777b5db612224dde64ce744d18b87fc4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file simdrive-0.3.0a1-py3-none-any.whl.
File metadata
- Download URL: simdrive-0.3.0a1-py3-none-any.whl
- Upload date:
- Size: 57.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16e6e61bb9fc4084a31814ff922076975cfe9a4a5781a0083b5fe55e426181c2
|
|
| MD5 |
26930fa474730126582b8232976d7dad
|
|
| BLAKE2b-256 |
1eae40d38cd75c485be251edcba8875b09975105555a1f46c78057b72d4c827a
|
Provenance
The following attestation bundles were made for simdrive-0.3.0a1-py3-none-any.whl:
Publisher:
simdrive-publish.yml on SyncTek-LLC/specterqa-ios
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
simdrive-0.3.0a1-py3-none-any.whl -
Subject digest:
16e6e61bb9fc4084a31814ff922076975cfe9a4a5781a0083b5fe55e426181c2 - Sigstore transparency entry: 1410943483
- Sigstore integration time:
-
Permalink:
SyncTek-LLC/specterqa-ios@e994c289777b5db612224dde64ce744d18b87fc4 -
Branch / Tag:
refs/tags/simdrive-v0.3.0a1 - Owner: https://github.com/SyncTek-LLC
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
simdrive-publish.yml@e994c289777b5db612224dde64ce744d18b87fc4 -
Trigger Event:
push
-
Statement type: