Skip to content

Launch week: lifetime is was $67 $34.99 until 15 October. CodeWas $67 $34.99 lifetime until 15 Oct. takes another 10% off.for 10% off. Get it

Test your iOS app with Codex

Add Mobster's MCP server to OpenAI's Codex so it checks the iOS screens it writes on a headless simulator, with pass or fail from accessibility assertions.

(updated )5 min readThe Mobster team

Codex writes Swift well and builds it with xcodebuild without complaint. It can’t look at the result: “the paywall works” means “the paywall compiles”. Mobster gives Codex a headless iOS simulator, an outline of every screen, and a verdict it didn’t write, through one local MCP server.

Add Mobster to Codex

Install Mobster CLI on a Mac with Apple silicon, macOS 15 or later, and Xcode with an iOS Simulator runtime, then add the server:

curl -fsSL https://mobster.dev/install.sh | sh
mobster mcp install codex

The second line runs codex mcp add mobster -- /Users/you/.local/bin/mobster mcp, which writes ~/.codex/config.toml:

[mcp_servers.mobster]command = "/Users/you/.local/bin/mobster"args = ["mcp"]

mobster mcp is a local stdio server. Codex starts it as a child process on your Mac, and nothing goes through a relay.

On 7 October 2026 a real codex exec session (Codex 0.161.0) connected to this server and called its status tool. The verify loop below uses the same plain MCP tools. If something doesn’t work, open an issue with what Codex printed.

The Codex integration page keeps this setup current, including how to give the server a model key for Smart mode.

It fits Codex’s timeout

Codex gives each tool call 60 seconds by default, and no Mobster call needs more: every tool returns within 45 seconds, and wait within 50. Longer work carries on under a run_id. The first run on a Mac creates the simulator, boots it and builds WebDriverAgent, so verify_start returns status: "preparing" and Codex calls wait until the run is ready. To do the slow part ahead of time:

mobster sim doctor --fix

That creates Mobster’s own simulator, boots it headless and builds WebDriverAgent once per Xcode version. Mobster never opens Simulator.app and never touches the simulators you created. On an M5 Max (28 September 2026, n = 2), a first run including that preparation took 77.7 s and 103.6 s, and warm runs took 6.8 s and 8.6 s.

Tell Codex how to verify

Codex reads AGENTS.md. Put the verify loop there, with your scheme and app names:

## Verifying UI changesAfter you change a screen in this iOS app, verify it before you say it works.1. Build for the simulator:   xcodebuild -scheme <Scheme> -destination 'generic/platform=iOS Simulator' -derivedDataPath .mobster/build CODE_SIGNING_ALLOWED=NO build2. Call mobster's verify_start with app_path set to the absolute path of   .mobster/build/Build/Products/Debug-iphonesimulator/<App>.app, the steps in plain English, and expect:   what must be true when the steps are done.3. Drive with screen, tap, type_text and swipe, then call verify_finish.4. If the verdict is failed, fix the code and verify again. Report the verdict and the report path.

The build needs no signing team, and Mobster keeps build/ and runs/ out of your commits with a .mobster/.gitignore.

The key-less loop catches what a glance misses

In the key-less loop Codex drives with its own model, and Mobster calls no model and needs no key. Mobster runs the app, reports the screen and judges. verify_start fixes the assertions before Codex touches the app. A real check of Daybreak’s reminder setting, the sample app in the CLI’s repository, as tool calls:

{"tool": "verify_start", "arguments": {  "app_path": "/abs/path/examples/ios/Daybreak/.build/Build/Products/Debug-iphonesimulator/Daybreak.app",  "launch_args": ["-DaybreakSkipOnboarding", "YES"], "open_url": "daybreak://settings",  "steps": ["Turn on Daily reminder.", "Relaunch the app and open Settings again."],  "expect": [{"value": {"id": "daily_reminder"}, "equals": true}]}}{"tool": "tap", "arguments": {"run_id": "…", "target": {"id": "daily_reminder"}}}{"tool": "relaunch", "arguments": {"run_id": "…"}}{"tool": "open_url", "arguments": {"run_id": "…", "url": "daybreak://settings"}}{"tool": "verify_finish", "arguments": {"run_id": "…"}}

It passes. Launched with -DaybreakBug reminder-not-saved as well, the switch is off again after the relaunch, and the check fails with value id=daily_reminder == true failed: was off. That’s the bug a quick look misses: the switch turns on, and the setting doesn’t survive a relaunch.

The verdict tells Codex what to fix

verify_finish returns one of four verdicts, each with an exit code for scripts: passed (0), failed (1), needs_review (2) and couldnt_run (3). With it comes the result JSON: summary names the first failing assertion, reason carries a fix sentence when there is one, and each failed assertion’s observed says what was on screen instead, with up to 5 near misses. On Daybreak’s planted missing-plan bug:

✗ failed  The paywall shows three plans with Annual at $39.99 a year  (18.2 s)
  ✓ text "Choose your plan"
  ✗ count id=/^plan_/ == 3: found 2: plan_weekly, plan_monthly
  ✗ value id=plan_annual == "$39.99 / year": not found; closest: "plan_monthly"
  ✓ visible label=Restore Purchases role=button
  ✓ no_text "Loading"

The count line names the two plans it found, so Codex goes straight to the code that drops the third: ForEach(Plan.all.prefix(2)).

Keep the check

save_check with a name saves the run’s check as .mobster/checks/<name>.yaml, plain YAML you can read and commit. The Checks reference has every field. A launch-only check reruns with no model and no key, so it suits a script:

mobster verify --check .mobster/checks/paywall.yaml --json > result.json
case $? in
  0) echo "paywall ok" ;;
  1) jq -r '.summary, .report' result.json; exit 1 ;;
  *) jq -r '.reason.message' result.json; exit 1 ;;
esac

A check with steps reruns through Codex again, or through Smart, Mobster’s own agent, on your OpenAI or Anthropic key with the spend capped by --max-usd (default $0.25).

Give Codex a simulator

Mobster CLI is free and open source under MIT:

curl -fsSL https://mobster.dev/install.sh | sh
mobster sim doctor --fix
mobster mcp install codex

Mobster for Mac adds guided setup for your iPhone, a live view and approvals, for $34.99 one time.

The full tool list is in the MCP reference, Getting started with verify runs a first check on the sample app, and Give Claude Code a real iPhone covers the phone side.

Questions

  • Can Codex use the iOS Simulator?

    Codex can build your app with xcodebuild, but it can't see a simulator's screen on its own. With Mobster's MCP server it gets a headless simulator that Mobster manages, and tools to read the screen, tap, type and swipe.

  • Do Mobster's tools fit inside Codex's tool timeout?

    Yes. Codex's default tool timeout is 60 seconds, and every Mobster tool call returns within 45 seconds, wait within 50. Longer work, such as a first simulator boot, carries on under a run_id that the agent polls with wait.

  • Can I rerun a check without Codex?

    Yes. Save it with save_check or --save and run mobster verify --check. A launch-only check calls no model, and the exit code is the verdict. A check with steps needs Codex again or Smart on your own key.

Sources

We read each of these on 8 October 2026. Reviewed by Andy Guo on . Corrections are welcome at the GitHub repo.