iOS simulator automation

Drive an iOS simulator like you mean it.

SimGadget boots simulators, reads the accessibility tree, and taps controls by name — from TypeScript, or from any AI agent that speaks MCP. No Python, no Homebrew, no four-year-old tooling.

$ npm install simgadget
$ npx -y simgadget-mcp

macOS on Apple Silicon · Xcode with iOS simulators · Node 18+.
You do not install idb_companion — SimGadget brings its own.

SimGadget is a TypeScript library for driving iOS simulators, and an MCP server built on it that lets a fleet of AI agents each drive their own simulator at once.

1.2 ms
wire time for a tap
13 ms
find a control by name
2
npm runtime dependencies
340 B
to tap, vs 7–10 KB for a tree
01 Why it exists

Most other libraries and MCPs use code from 2022.

The alternatives shell out to the Python idb CLI, or to Homebrew's idb_companion — last released in 2022 — or to xcrun simctl, which cannot read accessibility at all.

The reputation this has
  • Taps that report success and change nothing
  • Controls inside tab bars that are simply invisible
  • Coordinates that silently invert the moment you rotate
  • A Python process spawned for every single call
  • A simulator that wedges and has to be thrown away
What SimGadget did about it
  • A tap that hit-tests first and refuses when it can't land
  • The app's real view hierarchy, toolbars included
  • One coordinate space that survives rotation, written down
  • gRPC straight to the companion — no Python in the loop
  • Automatic recovery from the accessibility wedge

SimGadget ships its own idb_companion, built from current upstream source against current Xcode, pinned by sha256 and fetched on first use. Everything above it was rewritten on top of that.

02 Four things worth the switch

Fast, small, current, and honest about what happened.

Built for speed, and measured

A tap costs ~1.2 ms of wire time instead of the ~165 ms it takes to spawn a Python process for every single call. Finding a control by name is ~13 ms on the fast path. A whole screen is ~350 ms. Asking what is at a point is ~10 ms.

The whole design is shaped by that: tap({label: "Sign Up"}) resolves the element on the simulator and operates it, so nothing ever pulls down a kilobyte-scale tree just to find one button.

Almost zero dependencies

The library has exactly two npm runtime dependencies: @grpc/grpc-js and @bufbuild/protobuf. That's it. No test framework leaking into your install, no CLI wrappers, no 14 MB of transitive weight.

That is also why there are two packages. The MCP SDK and Zod are 14 MB between them, and a library that taps a simulator has no business putting them in front of you.

A companion from this decade

SimGadget pins a build from current idb source against Xcode 26.6 / Swift 6.3.3, sha256-verified, downloaded once and cached.

This is not housekeeping — it is what makes the rest possible. Tap-by-name doesn't work on the old companion. Neither does reading the contents of a tab bar, a nav bar or a toolbar.

There is deliberately no fallback to whatever idb_companion is on your $PATH: an old companion doesn't reject request fields it doesn't understand, it ignores them and answers anyway. A fallback would return results that are wrong but entirely plausible.

Bugs nothing else has fixed

A long list of failures that cost real debugging time to find, each of them the kind that reports success while doing nothing. Instant taps that don't register. Switches that were never tappable. System sheets landing taps 476 points away. Simulators that wedge on boot.

Every one is measured, and every measurement traces to a run in the repository.

04 Two packages

Pick the door you were already walking towards.

library

Script your tests accurately and quickly.

You have a shell and a Node runtime. You don't need a protocol between you and a simulator.

Because we support labels, tapping, typing, scrolling, it's all reproducable, even if you alter the exact place of the elements.

signup.ts
import { createSimulator } from "simgadget";

const sim = await createSimulator({
  deviceType: "iPhone 16 Pro",
});
await sim.installApp("./build/MyApp.app");
await sim.launchApp("com.example.myapp");

await sim.tap({ label: "Sign Up" });
await sim.typeText("test@example.com");
mcp server

Give every agent its own iPhone.

One server. Many agents. Many simulators. Nobody steps on anybody.

agent transcript~340 bytes
 ui_tap { id: "qa1", label: "Sound" }
 Toggled Sound off -> on.

 ui_tap { id: "qa1", label: "Stepper" }
 Refused: "Stepper" is covered by
  "Search" (SearchField) at (102, 96).
simgadgetsimgadget-mcp
ForTypeScript / JavaScript codeAI agents — Claude Code, Cursor, anything MCP
Installnpm install simgadgetnpx -y simgadget-mcp
Runtime deps24
Gives youSimulator handle, typed results, typed errors17 tools, sessions, multi-agent isolation
Requirements macOS on Apple Silicon, Xcode with iOS simulators, Node 18+. The library also uses xcrun simctl, sips and tar, which ship with macOS. You do not install idb_companion — SimGadget fetches a pinned one on first use, or run npx simgadget prefetch if you'd rather front-run the download in CI.
05 FAQ

Frequently asked questions

Do I need to install idb or idb_companion?
No. SimGadget fetches a pinned, sha256-verified companion on first use and caches it. A Homebrew companion on your $PATH is deliberately ignored — a silent fallback to a 2022 binary would be worse than none, because it answers wrong instead of erroring.
Do I need Python?
No. SimGadget speaks gRPC to the companion directly. That's where most of the speed comes from.
Intel Macs?
No — Apple Silicon only, and it fails loudly at startup naming your architecture rather than timing out thirty seconds later.
Can I use it without an AI agent?
That's what the library is for. npm install simgadget, then see the library page.
Can I use it without writing code?
That's what the MCP server is for. npx -y simgadget-mcp, then point your agent at it — setup here.
Is this the same as ios-simulator-mcp?
It started as a fork of Joshua Yoes' ios-simulator-mcp and has diverged substantially — different transport, different lifecycle model, its own companion, and a library underneath. The foundational work is his and is credited.

Two commands and you're driving.

No pipx install fb-idb. No brew install idb-companion. No Xcode command-line archaeology.

$npm install simgadget
$npx -y simgadget-mcp