---
title: "opencode and the iOS simulator: MCP setup | Mobster"
description: "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."
canonical: "https://mobster.dev/integrations/opencode"
last-updated: "2026-10-08"
---

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.

# 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](https://opencode.ai/docs/mcp-servers/).

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](https://docs.mobster.dev/device-setup)).

## Install Mobster CLI

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

or

```
brew install radishsoftware/tap/mobster
```

```
mobster version
which mobster
mobster sim doctor --fix
```

The 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 list
```

mobster 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](https://docs.mobster.dev/checks)) |

The [MCP reference](https://docs.mobster.dev/mcp-server) lists every tool. [AI end-to-end tests for iOS](https://mobster.dev/blog/ai-e2e-tests-ios-assertions) 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 8 October 2026. Corrections are welcome at the [GitHub repo](https://github.com/RadishSoftware/mobster/issues).

- [opencode docs: MCP servers](https://opencode.ai/docs/mcp-servers/)
- [opencode docs: config (locations and precedence)](https://opencode.ai/docs/config/)
- [opencode config schema (timeout for MCP server requests)](https://opencode.ai/config.json)
- [opencode source: MCP tool calls take the server's timeout](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/mcp/catalog.ts)
- [opencode docs: permissions](https://opencode.ai/docs/permissions/)
- [opencode docs: rules (AGENTS.md)](https://opencode.ai/docs/rules/)
- [opencode docs: CLI (opencode mcp)](https://opencode.ai/docs/cli/)
- [Mobster docs: MCP server](https://docs.mobster.dev/mcp-server)
- [Mobster docs: device setup](https://docs.mobster.dev/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.

## Read next

- [Every MCP tool, in the reference](https://docs.mobster.dev/mcp-server)
- [Getting started with verify](https://docs.mobster.dev/verify)

## Other agents

- [Claude Code](https://mobster.dev/integrations/claude-code)
- [Codex](https://mobster.dev/integrations/codex)
- [Cursor](https://mobster.dev/integrations/cursor)
- [VS Code](https://mobster.dev/integrations/vs-code)
- [Claude Desktop](https://mobster.dev/integrations/claude-desktop)
- [Gemini CLI](https://mobster.dev/integrations/gemini-cli)
- [Windsurf (Devin Desktop)](https://mobster.dev/integrations/windsurf)
