Skip to main content

Pure Python MCP server for mobile automation — Android via uiautomator2, iOS via pymobiledevice3

Project description

pymobile-mcp

Pure Python MCP server for mobile automation.

  • Android: uiautomator2 + adbutils
  • iOS: pure pymobiledevice3 userspace tunnel + WebDriverAgent (no go-ios, no root)

Public contract: fixed upstream mobile-mcp@c5d7d2723 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.

CI Release PyPI Python License: GPL-3.0

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=true failures
  • 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)

[!NOTE] iOS real-device screen recording returns the approved upstream-compatible Actionable exception on current pure-userspace RSD (iOS 26.5.2). iOS Simulator uses simctl recordVideo + WDA and is not covered by that exception.

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"

[!TIP] Prefer a venv. System Python + pip install often fights with Homebrew/PEP 668.

Quick start

  1. Connect an Android emulator/device (adb devices) and/or a paired iPhone.
  2. For iOS, ensure your WDA runner is installed (Xcode once); pymobile-mcp launches it over userspace tunnel.
  3. Run the server:
pymobile-mcp run
# equivalent:
python -m pymobile_mcp.cli run
  1. 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"
      }
    }
  }
}

[!IMPORTANT] For iOS USB, unset or bypass HTTP proxies (NO_PROXY=* or clear http_proxy/https_proxy). Proxy env often breaks usbmux / userspace tunnel.

First tools to try

After the client connects:

  1. mobile_list_available_devices — confirm Android/iOS ids
  2. mobile_get_screen_size / mobile_take_screenshot
  3. mobile_list_elements_on_screen — UI tree (no raw page source tool)
  4. mobile_list_appsmobile_launch_app with 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymobile_mcp-0.3.1.tar.gz (68.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymobile_mcp-0.3.1-py3-none-any.whl (52.8 kB view details)

Uploaded Python 3

File details

Details for the file pymobile_mcp-0.3.1.tar.gz.

File metadata

  • Download URL: pymobile_mcp-0.3.1.tar.gz
  • Upload date:
  • Size: 68.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pymobile_mcp-0.3.1.tar.gz
Algorithm Hash digest
SHA256 2b5ff7603854262bd7a6925311f9cb92f4b48346b820fb5ee9db849c78359b88
MD5 2e494ab590a534c15b819ca4374518eb
BLAKE2b-256 880d61e5d99bbcb2324f943fdbbca06505a2d9bf57ce85c69094c5e474c3c8a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymobile_mcp-0.3.1.tar.gz:

Publisher: publish.yml on ByteTrue/pymobile-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pymobile_mcp-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: pymobile_mcp-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 52.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pymobile_mcp-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ec798dbcb89e3db1100935b4b7fd8d8270c23c3da84fd8cc21ad41394ee4fbc0
MD5 ee99e0a537ca024e3b2388efc0819d45
BLAKE2b-256 c8faca02e8b8870109a2b4ad189848ea2a4ab9d2e1b491647bef3087b266127a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymobile_mcp-0.3.1-py3-none-any.whl:

Publisher: publish.yml on ByteTrue/pymobile-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page