opencode and the iOS simulator: MCP setup
Add Mobster to opencode.json as a local MCP server with a one-array command, set a safe timeout, and let opencode check your iOS app on a simulator.
The short version
Install Mobster CLI, then add the mobster block below to ~/.config/opencode/opencode.json, or opencode.json in a project.
From the docs. This setup follows opencode's MCP documentation, read on 8 October 2026. Mobster's MCP server is tested with Claude Code; we haven't run it in opencode ourselves yet. opencode’s MCP docs.
opencode can write and build your iOS code from the terminal. With mobster mcp added, it can also run the app on a headless iOS simulator Mobster manages, read each screen as a list of controls by name, and get a verdict of passed or failed from assertions on the accessibility tree, with frames and a report. The same server can drive a real iPhone over USB.
You need an Apple silicon Mac with macOS 15 or later and Xcode with an iOS Simulator runtime. A real iPhone also needs Developer Mode and the WebDriverAgent runner, set up in Mobster for Mac or with mobster serve --manage-device (Device setup).
Install Mobster CLI
curl -fsSL https://mobster.dev/install.sh | shor
brew install radishsoftware/tap/mobstermobster version
which mobster
mobster sim doctor --fixThe last command creates Mobster’s simulator, boots it headless and builds WebDriverAgent once per Xcode version, so the first check doesn’t wait for it.
Add the server
opencode reads opencode.json at the project root and ~/.config/opencode/opencode.json for every project, merges them, and gives the project’s file the last word. Its MCP block differs from most clients in three ways: the key is mcp, a local server needs "type": "local", and command is one array that holds the arguments too.
{ "$schema": "https://opencode.ai/config.json", "mcp": { "mobster": { "type": "local", "command": ["mobster", "mcp"], "enabled": true, "timeout": 120000 } }}The timeout is there on purpose. opencode’s docs describe it as the time allowed for fetching a server’s tools, 5 seconds by default, and its config schema as a timeout for the server’s requests. Its source also passes it to every tool call. Mobster’s calls take up to 45 seconds, and wait up to 50, so a 5-second value copied from an example would cut them off. 120,000 ms is safe under every reading. opencode mcp add walks you through the same thing interactively.
Key-less checks need no key: opencode drives with its own model, and Mobster judges. For Smart, where Mobster runs the steps itself on your OpenAI or Anthropic key, add Mobster’s env file to the array. Mobster expands the ~ itself:
"command": ["mobster", "mcp", "--env-file", "~/.config/mobster/agent.env"]Check it’s connected
opencode mcp listmobster should be listed. Then, in a session:
Call mobster's status tool and tell me what it says.status names Mobster’s version, the simulator setup, whether Smart is available and why not if it’s off, and where runs go.
A first check: onboarding, with Smart
Most integration pages here show the key-less loop, where the agent taps through the app itself. opencode can also hand the whole flow to Mobster. With a key in the env file, the server offers a verify tool: Mobster performs the steps on your key, then decides the verdict from the assertions, exactly as in a key-less run.
Daybreak, the sample app in the CLI’s repository, ships this check as onboarding.yaml. As a prompt:
Build Daybreak for the simulator, then use mobster's verify tool to complete onboarding
without allowing notifications and reach the paywall. Expect "Choose your plan" and three plans.opencode calls verify with the app, the steps and the expectations, plus a spend cap:
{"tool": "verify", "arguments": { "app_path": "/abs/path/examples/ios/Daybreak/.build/Build/Products/Debug-iphonesimulator/Daybreak.app", "steps": ["Complete onboarding. Don't allow notifications.", "Reach the paywall."], "expect": [{"text": "Choose your plan"}, {"count": {"id": "/^plan_/"}, "equals": 3}], "max_usd": 0.15}}max_usd defaults to 0.25 and can go up to 1.00; max_seconds defaults to 180. A run that finishes within 40 seconds returns its result. A longer one returns {"status": "running", "run_id": …}, and opencode calls wait. What the model says about its own run is never an input to the verdict: the verdict comes from the two assertions on a settled read of the accessibility tree. Smart sends each screen’s image and accessibility text to OpenAI or Anthropic, whichever key it runs on.
Put the rule in AGENTS.md
opencode reads project instructions from AGENTS.md, and /init creates or updates one. Add:
## 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.Use a real iPhone
list_devices names every device Mobster can use. With a USB iPhone’s name as device and no run_id, screen, tap, type_text, swipe, alert, open_url, launch_app and home act on the phone itself. Mobster holds the phone’s lock until stop with the device, or 90 idle seconds.
This is where opencode needs one more setting. It starts from permissive defaults, so it calls tools without asking unless a rule says otherwise. Its permissions are keyed by tool name, and it names MCP tools with the server’s prefix. Make Mobster’s acting tools ask before you connect a phone:
{ "permission": { "mobster_tap": "ask", "mobster_type_text": "ask", "mobster_swipe": "ask", "mobster_alert": "ask", "mobster_open_url": "ask", "mobster_launch_app": "ask", "mobster_home": "ask", "mobster_use_code": "ask", "mobster_set_clipboard": "ask", "mobster_install_app": "ask" }}Then limit the server to the phones you mean, since a rule covers a tool, not a device:
"command": ["mobster", "mcp", "--allow-device", "Test iPhone"]Any other real device is listed as not_allowed and refused. Mobster’s MCP annotations mark which tools only read, and its instructions tell the agent to ask you before anything that sends, buys, posts or deletes on a real iPhone. Don’t rely on instructions alone: the permission rules are what make opencode stop. A locked phone stops the call at once, and Mobster never enters a passcode.
Troubleshooting
| Symptom | Fix |
|---|---|
| opencode doesn’t load mobster | Use the mcp key, "type": "local", and one command array: ["mobster", "mcp"] |
| Calls fail after a few seconds | A small timeout is cutting them off. Set "timeout": 120000 |
The first verify_start returns status: "preparing" | The simulator is booting and WebDriverAgent is building. opencode calls wait, or run mobster sim doctor --fix first |
No verify tool | Smart is off. status says why: no key, a missing env file, or --keyless |
couldnt_run | reason.class and reason.fix in the result say what to do (Checks) |
The MCP reference lists every tool. AI end-to-end tests for iOS explains how the verdict is decided.
Questions
What timeout should opencode use for Mobster?
Set "timeout" to 120000 on the server. opencode's docs describe the field as a 5-second timeout for fetching tools, while its source also applies it to tool calls. Mobster's calls take up to 50 seconds, and 120 seconds covers both readings.
Does opencode ask before it calls Mobster's tools?
Not by default. opencode starts from permissive defaults where most permissions are allow. Set Mobster's acting tools, such as mobster_tap and mobster_type_text, to ask before you point it at a real iPhone.
Why doesn't opencode load the server?
Check the shape. opencode's key is mcp, not mcpServers, the server needs "type": "local", and command is one array with the arguments in it, ["mobster", "mcp"].
Sources
We read each of these on 8 October 2026. Reviewed by Andy Guo on . Corrections are welcome at the GitHub repo.
- opencode docs: MCP servers
- opencode docs: config (locations and precedence)
- opencode config schema (timeout for MCP server requests)
- opencode source: MCP tool calls take the server's timeout
- opencode docs: permissions
- opencode docs: rules (AGENTS.md)
- opencode docs: CLI (opencode mcp)
- Mobster docs: MCP server
- Mobster docs: device setup
opencode’s logo is a trademark of opencode, shown only to name the product. Mobster isn’t affiliated with or endorsed by opencode.