My Fire TV came back from a factory reset with nothing on it. Instead of an evening with a keyboard, I described what I wanted in a chat window and watched eight apps get installed, two keyboards enabled and the right one set as system IME — including a split-APK app that adb install refuses outright. That was the moment this stopped being a toy.
Repo: GitHub - st412m/ha-adb-mcp · GitHub
It’s a Home Assistant addon that exposes network ADB over MCP (Model Context Protocol), so an assistant connected to your HA instance can run shell commands, take screenshots, dump the UI tree and tap coordinates, type text (including non-ASCII), install and remove apps, move files, and read logcat — on any Android device on your LAN.
Why not the official MCP Server integration?
Fair question, and they don’t compete. The official integration exposes the HA conversation agent — the intents your assistant already understands: turn on a light, set a temperature. It’s the right tool when what you want is an entity.
This addon sits a layer below that. It talks to Android directly, so the assistant can do things HA has no entity for: read a crash log, dump the current UI and tap a coordinate, sideload an APK, disable a preinstalled package, pull a file off the box. If your device is an Android TV that HA already tracks via the androidtv integration, the two coexist (details below) — this just operates where entities don’t exist.
What I actually use it for
- Debloating a Fire TV. Listing what’s installed, deciding what’s safe to disable, and doing it — with the reasoning visible in the chat rather than copy-pasted from a forum thread.
- Restoring a box after a reset.
pm path <pkg>on a working device lists the exact split set of an app; pull those, pass them back as an array, done. - Diagnosing. “Why did this app die last night” is a logcat question, and filtering runs on-device so a huge buffer never crosses the wire.
- UI automation.
adb_ui_dumpreturns a compact element list with tap coordinates, so “open the app and go to the third settings tab” works without screenshot guesswork.
Coexistence with the androidtv integration
Android’s adbd doesn’t tolerate two independent TCP clients, and the integration connects directly by default — the sessions fight. The addon runs a classic adb server on 5037; point the integration at ADB server = HA host IP, port 5037 and both share one daemon and one device session. Note that adb_server_ip isn’t in the integration’s options flow, so switching an existing entry means deleting and re-adding it (entity IDs survive if the MAC is unchanged).
Honest limitations
- ADB is not a sandbox.
adb_uninstalltakes app data with it, andpm uninstall --user 0on a system package can leave a device broken or unbootable. An assistant will execute what it’s asked to. There’s anallow_shell: falsemode that disables the raw shell and keeps screenshots and UI control working — a sensible place to start. - Auth is a secret token in the URL path. One layer. Use a long random value and HTTPS. Never expose port 5037 outside your LAN — the adb server has no auth at all.
- The tool list is cached per chat by the client, so after an addon update an open chat keeps the old schemas.
- ~60 s gateway timeout per call. Background long-running commands on-device and poll instead of blocking.
- Screenshots wake devices, and HDMI-CEC will happily switch on the TV attached. Worth knowing before scripting a screenshot loop.
- aarch64 is build-verified, not device-verified — clean build and start on a Pi 4, but no Android device was attached on that setup.
On the engineering, since it’s relevant to trust
A soak test caught a memory leak in the screenshot path early on: about 3.1 MB retained per frame, ratcheting, never released. It was reproduced in two independent runs, traced to the streaming pipeline, fixed by going file→file, and re-verified before 1.0.0 — 24 frames now add under 2 MB total, with per-series deltas decaying to noise. I mention it not because the bug was interesting but because “an addon that hands an AI a shell on your devices” deserves more than
“works on my machine”, and I’d rather show the numbers than assert it.
Feedback, issues and reports from other architectures all welcome.