tethertrace
Tests and controls real Android 11+ phones over Wi-Fi by speaking the ADB wire protocol directly (wireless pairing, TLS/SPAKE2, shell, install, screencap). Provides MCP tools to discover and pair devices, read the on-screen UI tree, take screenshots, tap/type/scroll/press keys, launch and stop apps, install APKs, pull app logs, and run exploration, smoke tests and YAML flows, returning labelled failure verdicts with evidence.
Can run a local model from Ollama (e.g. ollama:qwen3:8b) to explain test reports so nothing leaves the machine.
Can optionally pass a test report to an OpenAI model (via OPENAI_API_KEY) to summarise and explain failures, constrained to the evidence in the report.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
tethertrace
Build, install and test your Android app on your real phone over Wi-Fi.
No adb. No Android SDK. No Android Studio. No test code. No cloud. Works with Claude, Codex and local models.
Quick start · Test an APK · Build from source · Verify a new build · AI agents · Status · Help wanted
npx tethertrace pair 123456 # once, with the code from Wireless debugging
npx tethertrace test app-release.apk # install, explore, catch crashes. No test code.You want to | Run |
Know if an APK crashes, with no test written |
|
Build the project in this folder and test it on your phone |
|
Check only what a new build could have broken |
|
Run an exact path every time |
|
Let Claude, Codex or a local model drive the phone |
|
Building an Android app? Just give it your APK
tethertrace test app-release.apkThat one command installs the APK over Wi-Fi, cold-starts it, walks through your screens by itself (tapping what it can see), and watches for crashes and freezes. You get:
a report with a screenshot of every screen it reached and the cold-start time,
the exact tap that crashed the app, the crash lines, and a
repro.yamlthat reproduces it,an
explored-flow.yamlyou can keep as a regression test and re-run withtethertrace run,a coverage level next to the verdict (
ok,limitedornone), so "no crash observed" on a canvas UI or game it couldn't tap never looks like a pass.
It never types, declines permission prompts, never flips switches or checkboxes, never opens floating windows or picture-in-picture, and skips anything that looks destructive or outward-facing (delete, pay, buy, send, share, log out…, in English and Hindi). Add your own with --deny "reset|archive". Add --record to get a video of the whole run.
Works with native Views, Jetpack Compose, Flutter and React Native, because it tests the built app, not your source code.
Related MCP server: duet
No APK yet? Build it too
tethertrace doctor # what is in this folder, and what a build needs
tethertrace build --test # build, install on your phone, explore for crashesbuild runs your project's own build (the Gradle wrapper, or flutter build apk) and works out the JDK and Android SDK it needs. It uses what is already on your computer. If something is missing, it asks before downloading the smallest set that can compile an app (a Temurin JDK and the one Android platform your project compiles against, straight from Google's SDK index), verifies the checksums, and keeps it in ~/.tethertrace. You do not need Android Studio or sdkmanager, and you do not set JAVA_HOME or ANDROID_HOME.
It reads native Android projects (Groovy and Kotlin DSL, version catalogs, several modules, flavors) and Flutter projects. CI builds an example app this way on Windows, Linux and macOS starting from an empty machine, on every change.
A failed build comes back with a category (compile_error, jdk_incompatible, dependency_download_failed, …) and the lines that matter. Details and limits: docs/build.md.
Why
Nothing to install but Node. tethertrace speaks the ADB wire protocol itself in TypeScript: wireless pairing (TLS 1.3 + SPAKE2), the encrypted connection, shell, install, screenshots. No
adb.exe, no 150 MB platform-tools, no USB drivers.Any app. Point it at an APK or a package name; it reads the package straight from the APK.
From source to a tested build in one command.
build --testfinds the right JDK and SDK, builds, installs and explores.verifythen remembers the app and re-runs only what a new build could affect.Honest answers when something breaks. Every failure is labelled (
element_not_found,app_crash,anr,app_exited,device_disconnected, …) and comes with the screenshot, what was on screen, and only your app's logs. "No crash observed" is never sold as "everything works".Built for AI agents. An MCP server lets Claude Code, Codex, Gemini CLI, Cursor or any MCP client see the screen, tap, type, install and run tests on the phone in your hand. AI is optional: the CLI is fully deterministic without it.
Quick start
You need Node.js 22+ and an Android 11+ phone on the same Wi-Fi.
npm install -g tethertraceOr run it without installing: npx tethertrace <command>, for example npx tethertrace doctor.
On the phone: Settings → Developer options → Wireless debugging → On.
Tap Pair device with pairing code and run, with the code you see:
tethertrace pair 123456Done. From now on just turn Wireless debugging on and use it:
tethertrace info tethertrace test path/to/your-app.apk # explore + crash check, no setup tethertrace smoke --apk path/to/your-app.apk tethertrace ui # what's on screen tethertrace tap "Sign in" # tap by visible text tethertrace run examples/android-settings-tour.yaml
The phone is found automatically over mDNS. Pass --device 192.168.1.20:41235 (or set TETHERTRACE_DEVICE) if you have several.
Use it from Claude, Codex and other AI tools
# Claude Code
claude mcp add tethertrace -- tethertrace mcp# Codex: ~/.codex/config.toml
[mcp_servers.tethertrace]
command = "tethertrace"
args = ["mcp"]Then ask: "Install app-release.apk on my phone, open the login screen, try signing in with the test account and tell me why it fails."
The agent gets these tools: discover_devices, pair_device, select_device, device_info, list_apps, apk_info, screenshot, ui_tree, wait_for, tap, type_text, press_key, scroll, swipe, launch_app, stop_app, install_apk, app_logs, smoke_test, explore_app, run_flow, verify_app, app_memory, record_screen, explain_report, inspect_project, toolchain_status, and build_project when you start it with --allow-build. Tests can record the screen with record: true.
Safety is enforced by the server, not left to the client:
--read-only: look, never touch.--package com.my.app: refuses to read or touch the screen while any other app is in front.--allow-shell: raw shell is off unless you add this.--confirm install,execute: a person approves each such call.Every decision goes to a local audit log.
Every tool has a permission class (read, interact, install, execute, sensitive) and every call passes one policy on the server before it reaches the phone. A ready catalog entry for HOL Guard is in integrations/hol-guard.
Details: docs/mcp.md.
Gemini CLI, Cursor, VS Code, Claude Desktop and local models (Ollama, LM Studio): see docs/mcp.md.
Agent skill
skills/tethertrace/SKILL.md teaches an agent when to reach for tethertrace and how to use it well: checking the phone connection, picking test, smoke or run, writing flows from the real labels, reading verdicts and coverage honestly, and the safety rules. It ships with the package. For Claude Code:
mkdir -p ~/.claude/skills && cp -r "$(npm root -g)/tethertrace/skills/tethertrace" ~/.claude/skills/# Windows PowerShell
New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Copy-Item -Recurse "$(npm root -g)\tethertrace\skills\tethertrace" "$HOME\.claude\skills\"Codex, Cursor and other agents that read SKILL.md: copy the same folder into their skills directory. The skill works with the MCP server connected or with the CLI alone.
Write a test in YAML
app: com.example.app
name: login
steps:
- launch
- tap: "Sign in" # visible text or accessibility label
- tap: { id: email } # or { desc: ... } / { contains: ... } / { index: 1 }
- type: "${TEST_EMAIL}" # secrets come from env vars and never reach reports
- key: enter
- waitFor: "Home"
- assertVisible: { contains: "welcome" }
- screenshot: hometethertrace run login.yamlEvery run writes an HTML report. When a step fails you get the category, the screenshot, the list of what was on screen instead, and the app's own logs. Full reference: docs/flows.md.
Let your AI write the tests for your app
Flows are plain YAML written for your app: its screens, its labels, its ids. You don't have to write them by hand:
From an AI agent. With the MCP server connected, the agent can read your app's source code, open each screen on the phone, look at the real labels with
ui_tree, write the YAML, run it withrun_flow, and fix it until it passes. The server ships a ready-made prompt for this,write_test(in Claude Code it shows up as the slash command/mcp__tethertrace__write_test), or just ask:"Write a tethertrace test for com.example.app that proves a user can log in with the test account. Read the source, check the real labels on my phone, save it to flows/login.yaml and run it until it passes."
From the explorer.
tethertrace test app.apksavesexplored-flow.yaml, a working flow through every screen it reached, as a starting point.From
tethertrace ui. Open a screen and copy the labels and ids it prints.
Keep your app's flows in your app's repo and run them on every build.
Check a new build without re-running everything
tethertrace verify --discover -p com.example.app # first time: record the app's screens
tethertrace verify # after a new build: check what could be affected
tethertrace verify --full # everythingtethertrace remembers each app in a plain JSON file you can read and edit: the builds it has seen, the screens the explorer reached, and how each flow went on each build. After a new build, verify runs a flow when it was never run, its file changed, it failed last time, or the source it covers changed in git:
app: com.example.app
name: login
covers: [app/src/main/java/com/example/login/**] # re-run only when this source changes
steps:
- launch
- tap: "Sign in"A flow that is skipped is reported as not run. It is never counted as passed.
A flow that passed on the previous build and fails now is reported as a regression.
Anything it cannot decide, it runs. Flows are never rewritten for you.
No AI is involved, so the same inputs pick the same flows every time.
Details: docs/verify.md.
Ask an AI why it failed (optional)
tethertrace explain reports/login-2026-11-07 # no AI, just the evidence
tethertrace explain reports/login-2026-11-07 -m anthropic # Claude (ANTHROPIC_API_KEY)
tethertrace explain reports/login-2026-11-07 -m openai:<model> # OpenAI (OPENAI_API_KEY)
tethertrace explain reports/login-2026-11-07 -m ollama:qwen3:8b # local, nothing leaves your machine
tethertrace explain reports/login-2026-11-07 -m lmstudio:<model>The model only sees the report folder and is told to quote evidence and say "unknown" when the evidence is thin. tethertrace's own verdict stays the source of truth.
Experimental: look inside an APK, and one package for several platforms
Two research features. Both are marked experimental and may change.
tethertrace analyze app.apk # framework, code, native libraries, what it depends on
tethertrace compatibility app.apk --target ios # which parts could reach iOS, which cannot, and whycompatibility is a static report. It never says an APK runs on iOS, because it does not: there is no Android runtime there. It tells you which route applies to your app (rebuild from source, repackage a web layer, or none).
tethertrace pack . # a built web app becomes app.tapp
tethertrace run app.tapp --platform desktop # preview it in a browser
tethertrace run app.tapp --platform android # run it on your phone inside a small runtime app
tethertrace convert app.tapp --to apk # or make a standalone Android app from itA .tapp is a ZIP of HTML, JavaScript and WebAssembly with a manifest that lists every file's SHA-256, the permissions it wants and the origins it may contact. A runtime verifies it, gives it its own origin and enforces that list. The desktop and Android runtimes have been run for real (Android on one phone, including a YAML flow against a package); iOS is not built and needs a Mac, an iPhone and Apple signing. The design, the format and the research behind both features: docs/universal-runtime.
Build your own AI phone agent on top of it
tethertrace is also a library. Anything a person can do on their own phone (read what's on screen in any app, tap, type, open apps, take screenshots), your code can do over Wi-Fi, with no app to install on the phone. That makes it a base for your own AI products:
a personal assistant that reads incoming messages and drafts replies for you to approve,
an accessibility helper that reads screens aloud or does repetitive taps,
a QA bot that tests every build on real phones,
store-screenshot and demo-video generators,
monitoring that opens an app every hour and checks it still works.
import { Device, discover, loadOrCreateKey, SERVICE_CONNECT } from "tethertrace";
const key = await loadOrCreateKey(); // paired once with `tethertrace pair`
const [phone] = await discover({ services: [SERVICE_CONNECT] });
const d = await Device.connect({ host: phone.host, port: phone.port, key });
const screen = await d.uiNodes(); // every label, button and id on screen, as data
const png = await d.screenshotScaled(0.5); // or an image for a vision model
// ...let your model decide what to do, then:
await d.tap("Reply"); // by visible text, { id }, { desc } or { contains }
await d.type("On my way!");
d.close();Or skip the code and give an agent the MCP server (above): it gets the same powers as tools.
Use it responsibly. Only on your own phone and your own accounts, with the person's consent. Keep a human approval step before anything that sends a message, posts, pays or deletes. Many apps (especially messaging apps) forbid automated use in their terms, so check them first; never use it for spam or bulk messaging. Scope agents with --package and --read-only wherever you can. type sends ASCII only, so non-Latin replies need another input route.
All commands
Command | What it does |
| What is in this folder, what a build needs, what is missing |
| Find phones with Wireless debugging on this network |
| Pair once with the 6-digit code |
| Model, Android version, ABI |
| Installed apps · package/version of an APK |
| Build the project ( |
| Install over Wi-Fi (streamed, with progress for large APKs) · cold start with launch time · force-stop |
| Screen PNG · on-screen elements · one app's logcat |
| Record the screen on its own, or during |
| Interact by visible text, id or description |
| Zero-config: install, explore screens, catch crashes, write report + flows |
| Install (optional) → cold start → watch → evidence + verdict |
| Run a YAML test with a full report |
| After a new build, re-run only the flows that could be affected and report regressions · show what is remembered about an app (docs/verify.md) |
| Summarise a report, optionally with an AI model |
| MCP server for AI agents · approve an action an agent asked for (with |
| Run a shell command on the phone |
How it works
your computer your phone (Android 11+)
┌────────────────────────────────────────────┐ ┌────────────────────────┐
│ tethertrace (Node, TypeScript) │ Wi-Fi │ adbd (Wireless │
│ mDNS discovery ──────────────────────────────────────▶ │ debugging) │
│ pairing: TLS 1.3 → SPAKE2 → AES-128-GCM │ │ │
│ connect: CNXN → STLS → TLS 1.3 (paired key)│◀────────▶ │ shell · exec · install│
│ YAML runner · evidence · classifier │ │ uiautomator · logcat │
│ MCP server ◀── Claude / Codex / any agent │ │ screencap │
└────────────────────────────────────────────┘ └────────────────────────┘Details, including how compatibility with Google's adb was checked: docs/how-it-works.md.
Status
Version 0.1, early, and published on npm. What has been verified, and where:
Area | Verified |
Pairing (and reconnecting after Wireless debugging is toggled), TLS connect, discovery | Physical realme RMX3563, Android 14, Windows 11 host, home Wi-Fi |
Apps of different kinds on that phone | A Flutter app (install 81.6 MB, 20-step flow across 6 screens), system Settings (scroll, search + typing), the native Calculator (taps by id and label, result asserted), the Clock app (smoke) |
MCP server | Driven over stdio by the official MCP SDK client against that phone: screenshot, UI tree, taps, logs, APK-only smoke test, |
Wire compatibility | Google's |
Zero-config | On that phone against a Flutter app: 10–15 screens per run, no crash, share buttons and 5 settings toggles correctly skipped; plus mock tests for crash + repro and replaying the generated flow |
Screen recording | On that phone, whose built-in |
Building from source |
|
| On that phone: first run, same build skipped, reinstall seen as a new build, a |
Security policy | 21 package-scope cases on that phone (other app in front, status bar, raw coordinates, system keys), plus negative tests for every permission class |
Large installs | An 82 MB APK on that phone: streamed, peak memory 112 MB. A link that goes dead is simulated in tests and fails after 30 s instead of hanging |
Everything | 97 automated tests against a mock device, on Windows, Linux and macOS, Node 22 and 24 |
Not yet verified | Other phone brands and Android versions, macOS/Linux with a real phone, React Native builds (the project is detected, the build has not been run), real packet loss on a bad network, APKs over about 100 MB, each AI client's own setup (the MCP protocol itself is tested), iOS (not supported) |
If you try it on another phone, please tell us how it went. That is the most useful contribution right now.
Limitations
Android only. iOS projects are detected but cannot be built or driven yet.
Real phones only. It does not start or manage emulators.
typesends ASCII only (an Androidinput textlimitation), so Hindi and other non-Latin text cannot be typed.Elements are found through the accessibility tree: text in custom-drawn canvases, games and secure screens (banking, passwords) is invisible to it. The explorer says so with coverage
none.verifydoes not trace code dependencies.covers:is written by hand, so a flow that depends on a shared utility has to list that path too. When unsure, use--full.Discovery needs mDNS. On a network that blocks it, pass
--device host:port. A Wi-Fi that isolates clients from each other cannot be worked around (stockadbfails there too).builddoes not download the Flutter SDK or install a React Native project's Node dependencies.Gradle files are read by pattern matching, not by running Gradle, so unusual build scripts may show fewer variants than exist.
Some phones switch Wireless debugging off when the screen locks or Wi-Fi changes. Turn it on again; pairing is remembered.
Security and privacy
Wireless debugging gives full shell access to the phone. Only enable it on networks you trust, and turn it off when you're done.
Nothing is sent anywhere: no telemetry, no accounts. Reports stay in
./reports.Typed text never appears in reports. Screenshots, on-screen text and app logs can still contain personal data, so review a report before sharing it.
Report vulnerabilities privately: SECURITY.md.
Roadmap
Next, in this order:
verify: trace dependencies, or a list of shared paths that makes every flow runClearer errors and a remembered address when mDNS is blocked
More phones verified
React Native builds verified
Typing non-Latin text
iOS: building with xtool and driving an iPhone without Xcode
Later: the same flow on several phones in parallel, recording a flow by using the app, and redacted repro bundles you can attach to an issue.
Help wanted
An iPhone and a Mac. iOS is the biggest open piece and the maintainer has neither, so none of it can be tested here. If you like protocol-level work, this is a real open problem.
Five minutes with your phone. tethertrace is verified on one phone. Run
npx tethertrace pair <code>andnpx tethertrace test <any apk>on a Samsung, Pixel, Xiaomi or anything else, and say how it went, good or bad.A React Native project. Run
tethertrace buildon it and report what happens.A bad network. Installs are tested against a simulated dead link only. Reports from office Wi-Fi with packet loss are welcome.
Contributing
Issues and pull requests are welcome. main is protected: every change goes through a pull request reviewed by the maintainer. See CONTRIBUTING.md.
Used tethertrace?
If it helped you ship or debug something, a ⭐ helps others find it. And we'd love to hear about it in Discussions → Show and tell: which phone, which kind of app, what broke, what worked.
Also by the maker
License
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
Cloud Android phones for AI agents: create a phone, read the screen, tap, type, install APKs, park.
AI agents on real phones: run tasks, read the screen, tap, type and install apps.
Disposable cloud Android emulators for coding agents: run an APK or PR build, tap, type, screenshot.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceLets AI agents see and use a real Android phone over Wi-Fi: read the screen, find elements by text or ID, tap, type, swipe, take screenshots and read notifications, without ADB or root.519MIT
- AlicenseNot gradedqualityBmaintenanceEnables an AI coding agent to drive a real Android phone over adb and one or more visible Chrome windows in the same test run, with safe guarded commands, screenshots returned as images, per-step logs, reports, and recordings. It lets agents act, inspect the screen and device log, fix code, and rerun a scenario until the feature passes.21 npm3MIT
- AlicenseAqualityBmaintenanceEnables AI agents to see and drive a real Android phone over plain ADB: screenshots and numbered UI trees, gestures, typing with accents and emoji, SMS/RCS reading and prepared replies, notifications, files, and settings, with no root and no app installed on the phone. Safeguards mask security codes and require explicit confirmation before sending, paying, deleting or confirming anything.182MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to see and control Android devices, with fast input, screenshots, UI element discovery, app and file management, shell access, and audio/video streaming or recording.389 npmMIT