Repository navigation
v1.0.0
appdyno 1.0.0 is the first public release: an MCP server, a command line and a Mac app that drive, test and measure iOS and Android apps on simulators, emulators and real phones. Each of its 48 tools is also a command and a call in the library; coming from 0.6.0, read Changed first.
Added
- The Mac app,
Appdyno.app, from a disk image or a Homebrew cask, signed and notarized: it carries its own Node, the Android agent, the device viewer and Perfetto's trace processor, lives in the menu bar, and looks for a newer release when it opens and once a day, which it installs only when you say so. Google's terms keep adb out of it, andappdyno tools install adb --accept-licensefetches it. appdyno installadds the server to the MCP clients on this Mac, changing only its own entry after a backup, with--dry-runto see the change and--removeto take it out.appdyno pathputs the app's command on every shell's PATH.appdyno updatemoves to the latest release only once it is verified, by npm's provenance for the package and a signed appcast for the app, and--checkchanges nothing.appdyno doctorsays the version and how it was installed.appdyno mcp --http 127.0.0.1:PORTserves the same tools over Streamable HTTP, for a client that cannot start a program on this Mac: on this Mac's loopback alone, behind a token, to one client at a time.appdyno hubshows every device of this Mac in one window, to start, stop, create and watch, with Connect a Phone, which takes a phone from its cable to ready, a page that adds and tests each MCP client, Tools and Help, in English and Turkish.appdyno mirroropens a live window of a simulator, an emulator, an Android phone or an iPhone on iOS 27 by USB, driven by mouse, trackpad and keyboard while an MCP client drives the same device.appdyno pairlets a window reach a phone by Wi-Fi.- A window's Inspector has ten panes, Performance, Flows, Apps, Activity, Logs, Network, Accessibility, Device, Links and Push, which do by hand what the tools do, live numbers and launch and scroll measures among them.
- Record Flow writes what a person does in a window as a flow, by selector, with a password kept as a secret's name. Show Beside This One, or
appdyno mirrorwith two--deviceand--pair, puts two devices side by side, and a touch goes to both. - The
mirrortool opens and closes a window from a client, andhand_offasks the person to do what a tool cannot, such as Face ID, and waits.--silentkeeps it quiet, for CI and a shared Mac. pushsends an app a push notification of seven types: bysimctlon a simulator, by FCM's own message on Android with no Firebase project, and by APNs or FCM once a person has stored its credentials withappdyno push setup.open_linksettingsopens Settings at a named page, andlinkslists the schemes and domains an installed app opens.press_keytakescontrol_center,notification_center,spotlight,escape,space, the arrows,muteandsiri, a letter or digit with keys held, ascommand+a, and acount.screenshotsaves afileand sizes its image bypointsorwidth, and withwatchMssays in words what moved on the screen.assertcheck: movesholds something to moving.- A screen whose tree has no words, such as a game or a canvas, is read from its picture by the Mac's own text recognition, and
find,tap,wait_forandasserttake what it reads. swipeexactmoves the content by itsdistanceand stops,gesturedragtakesholdMsto press before it moves, andset_locationclearends a fixed location.simulatorcreatemakes and boots a new iOS simulator.appinstalls an.ipa, builds and runs a project withbuild_and_run, and copies an app's data out and back withdownload_dataandreplace_data.device_settingtakesincrease_contrast,reduce_transparency,airplane,wifi,mobile_data,thermalandkeychain. On Android it slows a phone's network too, folds a device from API 31, sets a language below API 33 and enrolls a fingerprint on an emulator.list_devicessays what blocks each device and how to fix it, anduse_devicetakes a device by its serial, a simulator's or an AVD's name, or its model.- On an iPhone,
clipboardworks with no runner, andinspectorlists and presses what is on the screen with no signing identity. crashessymbolsnames a release build's stack, from its dSYM on iOS and its libraries with symbols on Android.appdyno perf why, orperf_compareaction: why, finds the likeliest cause of a regression with what shows it: a function, a phase of a start, a frame's cause or a hang.perf reference,perf functionsandperf commentgo with it.- A journey is measured and gated:
appdyno test --measure, orflowrunwithiterations, keeps each step's numbers, andperf comparenames the step that got slower.perf_launchbaselinekeeps a baseline in one call, andperf_comparebudgetsets a budget. - On Android,
perf_snapshotalsoreadssurface,startInfo,anonMemoryandbattery, numbers are set against Google Play's definitions,perf_tracesays why slow frames were slow, andperf_launchbaselineProfilemeasures a Baseline Profile. - On an iPhone, a window's numbers come each second with no runner, and
perf_tracewhat: hangssays whether each hang was busy or blocked and in which function, whichdsymnames. - Kept traces stay under a limit, 10 GB by default (
--trace-limit-gb), andappdyno perf prunelists what goes. Perfetto's trace processor, pinned and checked, is fetched the first time an Android trace needs it. reporttimeline(appdyno timeline) puts a journey's video, touches, steps, frames, requests, log and memory on one clock, in one HTML file to send.reportflight(appdyno flight), once turned on, keeps an app's last 30 s and saves them on a crash or a stall.- Flows take parameters as
${NAME}, run another flow withrunand carry tags, andappdyno testtakes--tag,--env-fileand--retries, which reports a file that passed on a retry as flaky.flowexporttowrites Maestro YAML to a file.
Changed
apphas nolaunch:launch_apptakesrestart,argsandenvand starts the app fresh with them, takes an app by its name as well as its id, and says whether it started the app or brought it to the front.find,wait_forandasserttake their target inselector, as every touch does. A selector's words at the top of a tool or a step are refused, with the call in that shape in the hint.- On iOS the on-screen keyboard is one element,
@keyboard keyboard, as on Android, and a touch on it is refused.type_textwith no target, where nothing has the focus, is refused withNO_FOCUS. - Every answer's
structuredContentholds its whole text astext, and leavesdoneout where the text holds it. A refusal's text starts with its code and ends with its hint. press_keyreads a key's name whatever its case,returnasenter, and a letter in a shortcut is a small one.logstakescontains, reads from when the last action began where nosinceis given, and on a simulator keeps to the app's own lines and the errors of Apple's frameworks.- Protocol 2: the host checks every request against its schema before it reaches a device, a dark screen is
SCREEN_OFF,device_infolists no capabilities, and a runner or agent of another version is refused at its first answer. pushis a tool of its own, out ofdevice_setting, and takesalert,background,rich,live_activity,tapped,voipandwidgets.set_orientationtakeslandscape_left,landscape_rightandupside_downwhere it tooklandscape, and answers once the screen has turned.device_settingsayschangedonly when the device reads otherwise after the change,dark_modereadsonoroff, andtext_sizeon iOS takes iOS's own named sizes.localeon a simulator, with an app given or selected, holds that app in the language and leaves the simulator alone, whichapp ""sets whole.launch_applanguageon iOS is for that launch alone.appdyno mcpis the one way to start the server, asappdyno-mcpis gone,benchtakes no--driver, and the library exports one function,connect.- A client's calls that act run one at a time, in the order they came, and say
waiting its turnwhile they wait; calls that only read run beside them. - A
wait_forthat runs out is refused withTIMEOUT, and analertwith no alert withNOT_FOUND, so on the command line both exit 1. - The performance gate fails on
noisy,few-samplesandrefusedas on a regression, andperf baselineexits 1 until it holds the 3 runs a comparison needs. - Several numbers are measured anew, so take a baseline kept with 0.6.0 again: exit counts are per run, every percentile has one definition, a step that never settled keeps no time, and an iOS step leaves out the runner's wait for an alert.
perf_scrollreads one round, and three under ascenario.perf_profileandperf_compareare no longer marked read-only, as either can swipe or restart the app.- The command line keeps its selected device per working directory, a condition it changes stays until
restore, and downloaded tools are kept in~/Library/Caches/appdyno/tools.
Fixed
- An answer no longer claims what did not happen: typing whose field reads back other text presses no Enter and says
submitted: false, and a touch that may have gone out is answeredTIMEOUTordispatched: "unknown"and never made twice. - An action whose app dies under it is refused at once with
APP_NOT_RUNNING, the crash report's reason and the app's last log lines, instepsand flows too, and behind Android's crash dialog as well. - The settle no longer calls a screen still while it slides slowly or while an alert comes up late, nor busy for a progress bar that stands still.
- A call that is stopped or times out stops on the device: no stroke, key or typing goes out after it, on Android, a simulator or an iPhone.
- Conditions go back as they were, Android's text size, language, dark mode, contrast, rotation lock and Wi-Fi among them, also when a client kills the server, and
simulatorshutdownputs them back first. - A simulator's first tap no longer waits for its runner to start, and
launch_app,open_link,type_textandlist_devicesanswer sooner. logsreads what a crashed Android app wrote as it died,crashesreads Android's exits by the device's own clock and a simulator's reports of that simulator alone, and the Android agent clears what its old builds and recordings left on the device.- Xcode's tools leave nothing behind: no
DTServiceHubafter a runner or a recording, noinstruments*.ktracein the temp folder, no runner build of older sources, and no simulator booted again after a person shut it down. scroll_tono longer runs past its row on a simulator, andperf_scrollgoes on into new rows while a list moves, where a round past its end read as smooth.- Measures read true on more devices: a Xiaomi with HyperOS has its frames counted once, and an iPhone's CPU share is its instrument's own.
- On a Samsung a tap on plain text no longer waits out its 3 s, and the edge panel is no longer taken for an alert.
- Android 17 is driven as earlier versions are: a finger a killed agent left down no longer blocks every touch, and its credential prompt reads as a passcode.
Security
- An input on the system's power, emergency or erase controls asks the person first, from any tool,
stepsor a replayed flow: Android's power menu, iOS's power-off screen and Control Center in any language, Settings' resets, and a third press of the power key in 5 s. Only--allow-power virtual|alllets these go ahead unasked, not--allow-data-loss. - Placing a call asks too: a
tel:,telprompt:,facetime:orfacetime-audio:link, a touch, key or text in a phone app or Android's own default dialer, and a button of iOS's call prompt, shown as an alert or as a sheet. - The guard reads the screen again after an input that may have changed it or failed on its way, and after another client's input to the same device, and sends nothing it cannot judge. An iPhone's
inspectorpresspasses it too: each press asks, and under--allow-appsor--no-homeit is refused. - What loses data asks the person first, by the client's own prompt:
app uninstall,clear,replace_dataandrevoke,granton an iPhone, anddevice_settingkeychain. A no does nothing, and the answer never says a person declined, as a client may answer by itself. - Where the client cannot ask, and always over
--http, these are refused unless the person started the server with--allow-data-lossor--allow-power. The command line asks on its terminal or takes--yes, which no MCP refusal names. --allow-appsholds every input, not only a tool's arguments: a touch, key or text that would land outside an allowed app is refused, andopen_linkandapp installreach only an allowed app, Settings only with its id in the list.--no-homeholds Settings by any route,open_link, a link to it,launch_appand aperf_measure among them. An allow list given empty, or one that matches empty text, is refused at the start, andsimulatorcreateis off under--allow-devices.- Logs, requests and console lines hide more credentials, a token in a query, an
AuthorizationorCookieheader whole, a JWT and a password in a link among them. - What is typed on an iPhone or a simulator stays in no file: XCTest's result bundles held each key, so delete the old ones,
~/Library/Developer/Xcode/DerivedData/temporary-*. react_nativecalls Metro on this Mac alone,webviewopens a page's socket only on the DevTools port it asked, and neither follows a redirect.flow runon a server takes no value from the server's environment,flow saveandflow exportwrite only in the server's folder or its state folder, and a kept run'scompilereaches a device only asspeed,speed-profileorverify.- A window passes nothing to a device until a person clicks in it.
- Report a vulnerability privately, as SECURITY.md says.