pymobile-mcp
Pure Python MCP server for mobile automation.
- Android:
uiautomator2+adbutils - iOS: pure
pymobiledevice3userspace tunnel + WebDriverAgent (no go-ios, no root)
Public contract: fixed upstream mobile-mcp@c5d7d27 — 23 tools by default, 26 with MOBILEFLEET_ENABLE=1.
mobile_get_page_source is not public; fleet runtime uses the documented approved exception when no Python fleet provider is installed.
Current release: 0.3.1 · Changelog · Live regression checklist
Features
- One stdio MCP server for Android + iOS
- Upstream-compatible natural-language/image results and exact Actionable vs
isError=truefailures - Live smoke scripts that exit
blocked(code 2) when devices are missing — never fake pass - Destructive actions (install/uninstall) gated by explicit env flags
Requirements
| Platform | Need |
|---|---|
| Host | Python ≥ 3.10, pip |
| Android | adb in PATH, authorized device or emulator |
| iOS | macOS recommended, paired iPhone/iPad, Developer Mode, mounted DDI, installed WDA runner (default com.byte.WebDriverAgentRunner.xctrunner) |
Install
From a git checkout (development)
git clone https://github.com/ByteTrue/pymobile-mcp.git
cd pymobile-mcp
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
pymobile-mcp --help
Dev install (tests)
pip install -e ".[dev]"
python -m pytest -q
From PyPI
pip install pymobile-mcp==0.3.1
From GitHub (no local clone of tooling)
pip install "git+https://github.com/ByteTrue/pymobile-mcp.git@v0.3.1"
Quick start
- Connect an Android emulator/device (
adb devices) and/or a paired iPhone. - For iOS, ensure your WDA runner is installed (Xcode once); pymobile-mcp launches it over userspace tunnel.
- Run the server:
pymobile-mcp run
# equivalent:
python -m pymobile_mcp.cli run
- Point an MCP client at the process (stdio).
MCP client config
Installed entrypoint (pymobile-mcp on PATH):
{
"mcpServers": {
"pymobile-mcp": {
"command": "pymobile-mcp",
"args": ["run"]
}
}
}
Checkout / venv (absolute paths are more reliable for GUI clients):
{
"mcpServers": {
"pymobile-mcp": {
"command": "/ABS/PATH/pymobile-mcp/.venv/bin/python",
"args": ["-m", "pymobile_mcp.cli", "run"],
"cwd": "/ABS/PATH/pymobile-mcp",
"env": {
"NO_PROXY": "*",
"PYTHONPATH": "src"
}
}
}
}
First tools to try
After the client connects:
mobile_list_available_devices— confirm Android/iOS idsmobile_get_screen_size/mobile_take_screenshotmobile_list_elements_on_screen— UI tree (no raw page source tool)mobile_list_apps→mobile_launch_appwith a known package/bundle id
Capability matrix (23 default tools; 26 with fleet env)
| Status | Meaning |
|---|---|
| supported | Implemented and covered by automated contract tests; this label is not a claim of current-device live attestation |
| approved exception | Explicit, reviewed black-box difference with stable upstream-compatible text |
Current live evidence passes on Android physical, Android emulator, iOS Simulator, and iOS real device. Android recording and iOS Simulator recording both passed live; iOS real-device recording remains the approved exception.
| Tool | Android | iOS |
|---|---|---|
| mobile_list_available_devices | supported | supported |
| mobile_list_apps | supported | supported |
| mobile_launch_app | supported | supported |
| mobile_terminate_app | supported | supported |
| mobile_install_app | supported (destructive) | supported (destructive, gated) |
| mobile_uninstall_app | supported (destructive) | supported (destructive, gated) |
| mobile_get_screen_size | supported | supported |
| mobile_click_on_screen_at_coordinates | supported | supported |
| mobile_double_tap_on_screen | supported | supported |
| mobile_long_press_on_screen_at_coordinates | supported | supported |
| mobile_list_elements_on_screen | supported | supported (WDA source internal) |
| mobile_press_button | supported | supported (HOME/VOLUME_*; BACK unsupported) |
| mobile_open_url | supported (http/https default) | supported (device must be unlocked) |
| mobile_swipe_on_screen | supported | supported |
| mobile_type_keys | supported | supported |
| mobile_save_screenshot | supported | supported |
| mobile_take_screenshot | supported | supported |
| mobile_set_orientation | supported | supported |
| mobile_get_orientation | supported | supported |
| mobile_start_screen_recording | supported; live passed | simulator supported/live passed; real device approved exception |
| mobile_stop_screen_recording | supported; live passed | simulator supported/live passed; real device approved exception |
| mobile_list_crashes | supported (dropbox) | supported (crash reports) |
| mobile_get_crash | supported (dropbox) | supported (crash reports) |
Environment variables
| Env | Purpose |
|---|---|
MOBILEMCP_ALLOW_UNSAFE_URLS=1 |
allow non-http(s) schemes for mobile_open_url |
MOBILEFLEET_ENABLE=1 |
expose the upstream fleet tool set (26 tools); runtime returns approved exception without a Python fleet provider |
PYMOBILE_MCP_ANDROID_DROPBOX_ALL=1 |
include non-crash dropbox tags (strictmode/boot/…) |
PYMOBILE_MCP_ANDROID_DEVICE |
pin Android serial for smokes |
PYMOBILE_MCP_ANDROID_ACTIONS=1 |
enable tap/type interactions in Android UI smoke |
PYMOBILE_MCP_ANDROID_TAP=x,y |
override Android tap point |
PYMOBILE_MCP_ANDROID_APK + PYMOBILE_MCP_ANDROID_PACKAGE + PYMOBILE_MCP_ANDROID_DESTRUCTIVE=1 |
allow install/uninstall smoke |
PYMOBILE_MCP_IOS_DEVICE |
pin iOS UDID |
PYMOBILE_MCP_IOS_ACTIONS=1 |
enable interaction steps in iOS core smoke |
PYMOBILE_MCP_WDA_XCTRUNNER |
WDA runner bundle id (default com.byte.WebDriverAgentRunner.xctrunner) |
PYMOBILE_MCP_WDA_PORT |
WDA port used by the in-process userspace RSD service client (default 8100; not a remote WDA URL) |
PYMOBILE_MCP_IOS_IPA + PYMOBILE_MCP_IOS_DESTRUCTIVE=1 |
allow iOS install/uninstall smoke |
NO_PROXY=* |
recommended for iOS USB / usbmux |
Live smoke
Scripts print JSON with status: passed|failed|blocked.
Exit 2 + blocked = missing device/env, not a product pass.
export NO_PROXY='*'
PATH=.venv/bin:$PATH
# Android
python tests/android_live_smoke.py
PYMOBILE_MCP_ANDROID_ACTIONS=1 python tests/android_live_smoke.py
python tests/android_app_system_live_smoke.py
python tests/android_recording_crash_live_smoke.py
# iOS (unlock phone for open_url)
python tests/ios_pmd3_wda_live_smoke.py
PYMOBILE_MCP_IOS_ACTIONS=1 python tests/ios_pmd3_wda_live_smoke.py
python tests/ios_system_helpers_live_smoke.py
python tests/ios_app_lifecycle_live_smoke.py
python tests/crash_tools_live_smoke.py
python tests/ios_app_recording_crash_live_smoke.py # real recording uses approved exception
Full dual-device gate: docs/regression-checklist.md.
Architecture (short)
MCP client --stdio--> pymobile-mcp server
│
├─ tools/registry + specs (23 default / 26 fleet contract)
├─ tools/* handlers
└─ drivers/
├─ android.py (adbutils / uiautomator2)
├─ ios.py (UserspaceRsdTunnel + WDA)
└─ ios_simulator.py (simctl + WDA)
Development
pip install -e ".[dev]"
python -m pytest -q
CI runs unit tests on Python 3.11 and 3.12 (workflow). Device live smokes stay local.
Known limits
- Android crashes come from
dumpsys dropbox --print, filtered to crash/ANR/tombstone-like tags by default - iOS real-device recording remains an approved exception; Simulator recording requires a booted CoreSimulator + WDA
- Recording state is process-local (
ActiveRecording); no cross-process resume - Custom URL schemes need
MOBILEMCP_ALLOW_UNSAFE_URLS=1 - Screenshot/recording host paths must resolve under cwd or system temp
- No go-ios/mobilecli runtime fallback by design
Troubleshooting
| Symptom | What to check |
|---|---|
| iOS device list empty | Cable/trust, pymobiledevice3 usbmux list, proxies (NO_PROXY=*) |
| iOS driver tunnel errors | Developer Mode, pymobiledevice3 mounter auto-mount, only one userspace tunnel process |
open_url fails on iPhone |
Unlock the device (passcode lock blocks Safari/WDA URL open) |
| Android no devices | adb devices authorized; kill stale adb if offline |
| Install/uninstall smoke skipped | Set package/apk/ipa and *_DESTRUCTIVE=1 |
| CI green but live red | Expected — CI is unit-only; use regression checklist |
Metadata
Release files for pymobile-mcp 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pymobile_mcp-0.3.1.tar.gz | 68.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pymobile_mcp-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 121.1 kB
Release files / pymobile_mcp-0.3.1.tar.gz
| Download URL | pymobile_mcp-0.3.1.tar.gz |
|---|---|
| Size | 68.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2b5ff7603854262bd7a6925311f9cb92f4b48346b820fb5ee9db849c78359b88
|
|
BLAKE2b-256 checksum How to use checksums |
880d61e5d99bbcb2324f943fdbbca06505a2d9bf57ce85c69094c5e474c3c8a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 20, 2026.
Transparency logRelease files / pymobile_mcp-0.3.1-py3-none-any.whl
| Download URL | pymobile_mcp-0.3.1-py3-none-any.whl |
|---|---|
| Size | 52.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ec798dbcb89e3db1100935b4b7fd8d8270c23c3da84fd8cc21ad41394ee4fbc0
|
|
BLAKE2b-256 checksum How to use checksums |
c8faca02e8b8870109a2b4ad189848ea2a4ab9d2e1b491647bef3087b266127a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 20, 2026.
Transparency logSecurity for pymobile-mcp 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pymobile_mcp-0.3.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 20, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.