mobile-mcp Gives an Agent Thirty Tools and a Real Phone
The accessibility tree is what makes agent phone control cheap and precise. It is also what turns every labeled field on screen into text the agent reads without a single image token.
A phone is the one computer an agent cannot talk its way into. No shell. No filesystem it can enumerate. No API for "tap the button that says Continue." The usual workaround is screenshots into a vision model, which burns image tokens, guesses at coordinates, and breaks the first time a button moves eight pixels.
mobile-next/mobile-mcp skips the screen. Its README states the approach directly: it "drives apps from the native accessibility tree (no vision model, no image tokens), falling back to screenshots + coordinates only when needed." That one design decision is why the project is sitting around 7.8k stars and landed at #13 on Trendshift's board this afternoon, and it is also why the security question worth asking is not the one people ask about phone automation.
What an accessibility tree actually hands over
The accessibility tree is the structured, labeled description of on-screen elements that screen readers consume. It exists so a blind user can navigate an app, which means it is deliberately complete, deliberately semantic, and deliberately text.
Read that again with an agent in the loop. A screenshot of your banking app is pixels, and something has to interpret them. The accessibility tree of the same screen is a list of labeled nodes, and the account number is a string. There is no interpretation step and no cost. mobile_list_elements_on_screen returns it.
So the efficiency argument and the exposure argument are the same argument. The reason mobile-mcp is precise and cheap is the reason it reads everything on screen as data. That is not a flaw in the project. It is what driving a phone by accessibility means, and anyone shipping this needs to hold both halves at once.
The tool surface
The README lists 30+ tools in six groups. Naming them is more useful than describing them, because the shape of the list is the shape of the capability:
- Device management:
mobile_list_available_devices,mobile_get_screen_size,mobile_get_orientation,mobile_set_orientation,mobile_set_location,mobile_clipboard - Remote devices:
mobile_login_to_cloud_provider,mobile_list_remote_devices,mobile_allocate_remote_device,mobile_release_remote_device - App management:
mobile_list_apps,mobile_get_foreground_app,mobile_launch_app,mobile_terminate_app,mobile_install_app,mobile_uninstall_app - Screen interaction:
mobile_take_screenshot,mobile_save_screenshot,mobile_list_elements_on_screen,mobile_click_on_screen_at_coordinates,mobile_double_tap_on_screen,mobile_long_press_on_screen_at_coordinates,mobile_swipe_on_screen,mobile_start_screen_recording,mobile_stop_screen_recording - Input and navigation:
mobile_type_keys,mobile_press_button,mobile_open_url - Logs and crashes:
mobile_get_device_logs,mobile_list_crashes,mobile_get_crash,mobile_batch_commands
Three of those deserve a second look. mobile_set_location means the agent decides where the device thinks it is, which matters for anything with geofenced behavior. mobile_clipboard reaches the one buffer users treat as scratch space for exactly the strings they do not want to retype. And mobile_install_app plus mobile_uninstall_app means the tool list includes changing what software is on the device, which is a different category of action from tapping a button on it.
mobile_batch_commands is the quiet one. Batching is how you make a multi-step interaction reliable, and it is also how a single approved tool call becomes a sequence you did not read before approving.
How it connects
Requirements per the README: Xcode command line tools, Android Platform Tools, and Node.js v20 or later. Install is npx -y @mobilenext/mobile-mcp@latest.
Android goes through adb. iOS simulators go through xcrun simctl. Physical iOS and Android devices work over USB with the right platform tools and drivers. It also supports iOS Simulators on macOS and Linux, and Android emulators on Linux, Windows and macOS. Nothing exotic, which is the point: it is a thin MCP surface over the automation paths mobile engineers already use.
Latest release is 1.0.5, dated 2026-09-23. The repo is Apache-2.0, and here is a detail I checked against the raw LICENSE file rather than the badge: the license body still carries the unfilled template line Copyright [yyyy] [name of copyright owner]. There is no named holder. That is a paperwork problem rather than a functional one, and it is the kind of thing a legal review flags at the worst possible moment.
The boundary is the tool list, and MCP has no opinion about it
Here is where I land, and it is not a criticism of this project.
MCP gives a client a list of tools and a way to call them. What it does not give you is a scope. There is no protocol-level way to say "this server may read the accessibility tree but may not type," or "this server may drive the simulator and never the physical device," or "this server gets mobile_list_apps and not mobile_install_app." Whatever granularity you get comes from your client's permission model, which for most clients means approving tool calls one at a time or approving the server wholesale.
So the practical boundary for an MCP server exposing 30+ device tools is the list itself, plus however much attention the person clicking approve is paying at the time. On a simulator running a test suite that is completely fine. On a physical device signed into real accounts it is a device-level session with an agent on the other end, and the accessibility tree means the agent can read every labeled field on every screen it navigates to, including the ones holding one-time codes.
The project is honest about its posture. The README says it "runs locally and communicates only with the devices you connect," telemetry can be turned off with MOBILEMCP_DISABLE_TELEMETRY=1, and HTTP server mode supports Bearer token authorization through MOBILEMCP_AUTH. That last one is worth reading as what it is: authorization on the HTTP transport is opt-in through an environment variable. Left unset on a shared runner or a machine reachable from a network you do not control, HTTP mode is an unauthenticated device-control endpoint. On loopback with stdio, none of that applies.
Put this into practice
Start on a simulator, not a phone. xcrun simctl on macOS or an Android emulator gives you the entire tool surface with none of the real accounts. If your actual goal is test automation, you may never need a physical device at all, and you should find that out before you plug one in.
If you do use a physical device, use a dedicated one. Not your phone. A cheap Android with a throwaway Google account and nothing installed that matters. This is the same discipline people already apply to test devices, and the accessibility-tree read makes it more important, not less.
Keep it on stdio unless you have a reason not to. stdio over a local pipe has no network surface. If you need HTTP mode, set MOBILEMCP_AUTH in the same commit that enables it, not in a follow-up.
Restrict the tool list at the client. Most MCP clients let you allow or deny individual tools. For a read-and-inspect workflow, the interesting set is mobile_list_available_devices, mobile_list_elements_on_screen, mobile_take_screenshot, mobile_get_foreground_app and the log tools. Leaving mobile_install_app, mobile_uninstall_app and mobile_clipboard out of an exploratory session costs you nothing.
Set MOBILEMCP_DISABLE_TELEMETRY=1 if your device state is in any way sensitive, which on a real phone it is.
Honest limitations
Accessibility-first is the right default and it is not universal. Custom-drawn UIs, games, canvas-heavy apps and anything built without accessibility labels will not produce a useful tree, and the README says the fallback is screenshots plus coordinates. Coordinate-based interaction is brittle across screen sizes and orientations, which means the failure mode is not an error but a tap that lands somewhere else. Your test passes and your assertion was never exercised.
Physical iOS devices need platform tools and drivers, and anyone who has fought WebDriverAgent knows that sentence is doing a lot of work. Budget real setup time and expect the simulator path to be dramatically smoother.
The unfilled Apache-2.0 copyright line means there is no named holder in the license file. I am not a lawyer and this is not legal advice; it is a flag worth raising with whoever reviews your dependencies, because "Apache-2.0" and "a LICENSE file with a template placeholder in it" are not identical facts.
And I have not audited the screenshot fallback path for whether captured images land in logs or temp files that outlive the session. If you are pointing this at anything sensitive, that is the first thing I would go read the source for, and I would not take my word or the README's for it.
What to do with this
The reason this project is worth your afternoon is that it makes a real argument about agent design: the accessibility tree was always the better interface, and the industry reached for vision models because they were easier to demo. mobile-mcp picks the harder and cheaper path, and the result is faster, more precise and more auditable than a screenshot loop.
It also hands an agent thirty-odd tools and a device. Those two sentences are both true, and the second one is not a reason to avoid the project. It is a reason to spend ten minutes on your client's tool allowlist before you spend an afternoon on the fun part.
Point it at a simulator tonight. Then decide, on purpose and in writing, what you are willing to plug in.
Sources: mobile-next/mobile-mcp README, raw LICENSE file, release 1.0.5, Trendshift board. Star count read from a cache-busted shields.io endpoint on 2026-09-27.
Medium metadata
- Title: mobile-mcp Gives an Agent Thirty Tools and a Real Phone
- Subtitle: The accessibility tree is what makes agent phone control cheap and precise. It is also what turns every labeled field on screen into text the agent reads without a single image token.
- Tags: MCP, AI Agents, Mobile Development, Security, Test Automation
- Canonical: import from the fervorai.dev URL