Skip to main content
Glama

English · Türkçe

npm CI License: MIT

A real run: a terminal of MCP tool calls goes through the checkout of the shop example on an iPhone simulator in the appdyno hub, three bags of coffee beans into the cart and on to Place order, which takes the app down, and the answer says it died, with its last log line: Fatal error: Index out of range

An agent reads the screen as elements, taps, types and swipes. It sends a push, opens a deep link, and measures how the app starts, scrolls and holds its memory. Every action answers with the screen once it has settled, so the agent sees what it did in the same call. You can watch and touch the same device in a live window. It all runs on your Mac, with no cloud and no telemetry.

Works with Claude Code, Claude Desktop, Codex, ChatGPT, Cursor, VS Code, Devin Desktop (formerly Windsurf), Antigravity, Gemini CLI, Zed, opencode, Cline and any other MCP client.

Quick start

On a Mac with Node 22 or newer:

npx -y appdyno install     # adds appdyno to the MCP clients on this Mac, asking which

Restart the client, start a simulator or an emulator or connect a phone, and ask your agent:

Open my app, go through checkout, and tell me what breaks.

Each step answers with what the device showed. When a tap takes the app down, that same answer says so, with the crash and the app's last log lines. A real one, from this repository's shop example on an iPhone simulator, where three of one product take the order down:

APP_NOT_RUNNING: tapped @7rwa "Place order"; the app died: EXC_BREAKPOINT SIGTRAP Trace/BPT trap: 5 (~/Library/Logs/DiagnosticReports/Shop-….ips)
its last log lines:
2026-11-13 15:04:41.624 Df Shop[46315:14884fe] (libswiftCore.dylib) Swift/ContiguousArrayBuffer.swift:695: Fatal error: Index out of range
  launch_app starts it again, and crashes says why it died

crashes then names the function, discount(forQuantity:), and the same checkout saved as a flow fails in CI until the bug is fixed.

Ask it as well to send your app a push, to open each link your app opens, or to measure its cold launch and keep it as a baseline. npx -y appdyno doctor says what this Mac is missing, and Install covers a phone, the Mac app and any other client.

Related MCP server: Karagöz

One call, one answer

There is no second call to look, and no fixed sleep: an answer says settled when the screen came to rest, and changed when it differs from before. A refusal has a code and a hint for the next step.

What an agent can do

what an agent can do

its tools

See and act. Read the screen as elements and act on one by text, id or ref: tap, type, swipe, scroll to it, long press, drag, pinch, press a key. Up to 30 steps in one call.

screen find tap type_text swipe gesture steps wait_for

Push notifications. Send a push of each type the device takes, from a title and a body or from the platform's own JSON.

push

Links. Open a deep link, a universal link or an App Link. List the links an installed app opens.

open_link

Conditions. Dark mode, text size, language, a slow network, airplane mode and biometrics, each put back when the session ends. A location, and the way the screen is turned.

device_setting set_location set_orientation

Measure. Launch time, frames, memory, CPU, network bytes and energy, read from the platform's own tools and kept with their raw output. A gate fails a change that made the app slower.

perf_launch perf_scroll perf_snapshot perf_compare and more

Evidence. Video, a report of each step, logs, crashes, network traffic, accessibility audits and visual diffs.

record report logs crashes network audit visual

Flows. What an agent did once runs again with no model, on another device, and in CI.

flow

A person, too. A live window you can touch while the agent drives. When only a person can go on, such as at Face ID, the agent asks one and waits until they say done.

mirror hand_off

All 48 tools are in Tools. Each is also a command, and a call in the library.

A real run: an MCP client lists the links a test app opens on an iPhone simulator in the hub, opens its deep link, sends it a push its own code shows, then another one onto the home screen, with each call's real time and first line of answer below

push sends a push by type, and answers with the screen after it. Asked with no type, it says which types this device takes, how each one is delivered, and the payload it would send.

  • On a simulator an alert goes by simctl and reaches the app's own code, from fields or from APNs' own payload with a badge, a sound and a category.

  • On Android a push always goes to the app itself. A debuggable build that includes Firebase Messaging takes alert, rich, background and Live Activity pushes as real FCM messages, handed straight to its Firebase SDK, with no Firebase project or key. tapped opens the app as a tapped notification does, with the push's data in the intent that launches it. Any other build takes tapped only, and the answer says what the rest need.

  • With APNs set up by a person, with appdyno push setup apns, a simulator also takes rich, background, Live Activity, VoIP and widget pushes by APNs' sandbox, and a real iPhone on its cable takes those and an alert. Behind strict controls: the sandbox by default, a token only from the app's own log or typed by a person in a window's Push pane, 4 KB at most (5 for VoIP), 10 pushes a minute, and no key or token in any answer or log.

  • With FCM set up, with appdyno push setup fcm, an Android device takes alert, rich, background and Live Activity pushes by FCM, behind the same kind of controls.

Until APNs is set up, a real iPhone takes no push, and the answer says so. FCM's own message was run on an API 34 emulator, and its data pushes on a Samsung phone too. The requests to Apple and Google are tested against recorded ones, and the sending to Apple against a local stand-in server: no push has yet gone through Apple's or Google's own servers in testing.

open_link opens a deep link, a universal link or an App Link and answers with the screen it led to. Given an app's id, it lists the links that app opens: on a simulator its URL schemes and the domains its signature names, on Android each filter as scheme://host/path and each App Link domain with the state Android verified it in.

Push notifications has every type on every device, and what was run on what.

The live window and the hub

appdyno hub opens every device on this Mac in one window, driven by mouse and keyboard while an agent drives it too. Its Performance pane reads frames, CPU and memory as they happen. AI Clients shows each MCP client on this Mac as it truly stands, and adds appdyno to it. A phone joins by cable, or by Wi-Fi once paired with appdyno pair. See The window and the hub.

A person approves what loses data

Nothing the agent sends counts as a yes, and no tool erases or resets a device. What asks the person first lists each action, and how a person allows them ahead of time.

On each device

device

what it needs

iOS simulator

Xcode. No account and no signing

iPhone

Xcode, Developer Mode, and a development signing identity with a profile for it

Android emulator

adb, from Android Studio or Google's platform tools

Android phone

adb, and USB debugging. Wi-Fi once paired

What works where has every measure on every device, and how each was proved. An iPhone's live picture is experimental, and rests on undocumented Apple services that may change.

Install

1. What you need

for

you need

appdyno

a Mac, and Node 22 or newer. The Mac app carries its own Node; from npm, the hub's window needs Xcode or its Command Line Tools

an iOS simulator or an iPhone

Xcode, and iOS 17 or newer

an Android emulator or phone

adb, from Android Studio or Google's platform tools, and Android 8.0 (API 26) or newer

2. Get appdyno

npm install -g appdyno     # installs the appdyno command

Or take the Mac app, which needs no terminal: download Appdyno-<version>-arm64.dmg from the releases and drag it to Applications. It runs on Apple silicon with macOS 13.5 or newer, and Add to MCP Clients in its menu bar does step 3. See The Mac app. To build appdyno from a checkout instead, see CONTRIBUTING.md.

3. Add it to your MCP client

appdyno install --dry-run  # shows the change for each client it finds, and writes nothing
appdyno install            # asks which clients; --yes takes all of them

It changes only appdyno's own entry, keeps a backup beside the file, and appdyno install --remove takes it out. Restart the client afterwards. For any other client, add this to its server list:

{
  "mcpServers": {
    "appdyno": { "command": "npx", "args": ["-y", "appdyno", "mcp"] }
  }
}

A client opened from the Dock may not find npx: if it says spawn npx ENOENT, see An app cannot find npx or adb.

4. Get a device ready

  • iOS simulator: nothing more. Start one in Xcode's Simulator, or ask your agent to. appdyno ios build builds appdyno's helpers for a simulator and an iPhone ahead of time, which takes a few minutes; otherwise the first action builds the one it needs. It also deletes builds of older versions, except one that a running process still uses.

  • Android emulator: create one in Android Studio's Device Manager and start it.

  • Android phone: turn on Developer options (Settings, About phone, tap Build number seven times), then USB debugging in them. Connect the cable and answer Allow on the phone. For Wi-Fi, pair once under Wireless debugging, Pair device with pairing code: appdyno pair <address> <code>.

  • iPhone: connect the cable and answer Trust, turn on Developer Mode, and give it a development signing identity with a profile: An iPhone or a simulator takes you through it. For Wi-Fi, pair once on the cable: appdyno pair --device <udid>.

5. Check

appdyno doctor             # what is here, what is missing, and how to fix it
appdyno devices            # what is connected
appdyno screen             # what is on the screen
appdyno hub                # every device in one window you can touch
appdyno perf survey --app com.example.app   # every measure on this device, then a page of them

Connecting a client takes each client step by step, and gets a phone ready from nothing, signing included.

On real apps

Wikipedia's own debug build, from its repository, on an Android emulator in the hub: an MCP client searches for Istanbul, opens the article, taps a link that wraps over two lines, reads that article and measures it. Every call is real, with the time it took:

A real run: an MCP client drives Wikipedia's debug build on an Android emulator in the appdyno hub, searching for Istanbul, opening the article, tapping the Hagia Sophia link and reading its article, while the Performance pane reads frames, CPU and memory

The article and its picture are Wikipedia's, under their own licenses.

Seven builds of five open-source apps, each as its repository builds it, debug builds on an Android emulator (API 34) and an iOS simulator (iOS 27.2), on an M5 Pro, on 2026-11-13:

app

built with

cold start

memory

scroll

Wikipedia, Android

Kotlin, views, articles in a web view

2,098 ms

197 MB

4.4% janky, p95 30 ms

Now in Android

Kotlin, Jetpack Compose

1,912 ms

179 MB

3.3% janky, p95 32 ms

AntennaPod

Java, views

1,451 ms

107 MB

1% janky, p95 31 ms

Wonderous, Android

Flutter

1,345 ms

188 MB

its own surface: 60 fps, p95 16.7 ms

Wikipedia, iOS

Swift, Objective-C, UIKit, articles in a web view

3,191 ms

230 MB

6.4% janky, p95 32 ms

NetNewsWire

Swift, UIKit

2,492 ms

57 MB

2.1% janky, p95 16.7 ms

Wonderous, iOS

Flutter

3,519 ms

298 MB

2.1% janky, p95 16.7 ms

A cold start is the median of 5 after a warm-up: on Android the time to a first frame that the system reports, on the simulator the time to the first frame the frame probe sees. Memory is Android's PSS and iOS's physical footprint, after the scroll. A scroll is the median of 3 rounds of 5 swipes; Wonderous on Android draws on a surface of its own, past the frames the system counts, so that surface's frames are read instead. A simulator's and an emulator's numbers are this Mac's, and a debug build is slower than a release build: they compare one run with the next, and do not say how fast a phone is.

Trying them showed what to fix in appdyno. An app with two launcher activities, as a debug build with LeakCanary has, started the system's chooser and measured a cold start of 0 ms, and a touch on a link over two lines landed between the lines. Each fix is in the changelog.

Speed

Medians of 5 runs, through MCP over stdio, on the fixture app, on an M5 Pro, on 2026-11-10 (the phones on 2026-11-09). The iPhone is a 13 Pro Max, and the Android phone a Samsung SM-A525F:

call

iOS simulator

Android emulator

iPhone

Android phone

read the screen

18 ms

11 ms

308 ms

49 ms

tap by coordinate

890 ms

469 ms

970 ms

711 ms

tap by selector

1,084 ms

696 ms

918 ms

989 ms

type into a field

1,137 ms

648 ms

1,934 ms

930 ms

screenshot

82 ms

28 ms

184 ms

166 ms

A tap waits until the screen has been still for 200 ms and answers with what changed, so most of its time is the app's own. In a checkout, after pnpm build and with the fixture app installed on the device, node scripts/speed.mjs <device id> runs the same calls on your Mac. Speed has every call, where the time goes, and what each one proves.

Documentation

read

to

Connecting a client

join appdyno to your MCP client and get a phone ready

Flows

record what an agent did, replay it with no model, run it in CI

Evidence

leave a video, a report, a network log or a visual diff behind

Measuring performance

measure an app, keep a baseline, and fail a change that makes it slower

Tools

every tool, and what each platform can and cannot do

How it is built

how the parts fit, for someone about to change them

The documentation has the rest of the reference.

Security

Local only: no network listener by default, no telemetry, and you decide which devices, apps and links it may touch. Use a test device and test accounts. See SECURITY.md.

Contributing

See CONTRIBUTING.md and the Code of Conduct. CHANGELOG.md lists the releases.

License

MIT. See LICENSE.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      A
      maintenance
      Enables AI assistants to automate mobile app testing and development for iOS and Android through natural language interactions. Supports intelligent element identification, session management, automated test generation, and comprehensive device interactions including clicks, swipes, screenshots, and app management.
      32
      14,478 npm
      518
      Apache 2.0
    • A
      license
      B
      quality
      B
      maintenance
      Enables AI agents to automate Android and iOS devices, including emulators and physical devices, by capturing screenshots, reading UI accessibility trees, performing touch and text input, and managing app lifecycle and logs.
      18
      4
      MIT
    • A
      license
      B
      quality
      B
      maintenance
      Enables agents and LLMs to automate and develop native iOS and Android apps across simulators, emulators, and real devices through a single platform-agnostic, accessibility-first interface. Provides taps, swipes, text input, app install/launch, screenshots, screen recording, device logs, and crash reports without requiring any iOS- or Android-specific expertise.
      35
      45,799 npm
      Apache 2.0