phantom-mcp
Allows testing and automation of Android emulators and real devices through ADB and UIAutomator, enabling screenshot capture, UI interaction, app launching, and accessibility audits.
Provides integration with Appium for iOS automation through WebDriverAgent, enabling UI testing, element interaction, and mobile app automation workflows.
Enables testing and automation of iOS simulators and real devices via xcrun simctl and WebDriverAgent, supporting screenshot capture, UI interaction, app management, and accessibility testing.
Provides platform support for running mobile testing automation tools, serving as the base operating system for iOS simulator management and Android emulator execution.
Enables iOS simulator management and WebDriverAgent execution for iOS app testing and automation through Xcode command-line tools.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@phantom-mcp take a screenshot of the login screen on the iPhone 15 simulator"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
phantom-mcp
MCP server that allows Claude Code to see and control iOS simulators, Android emulators, and real devices. 24 tools to test mobile apps without leaving the terminal.
Claude can take screenshots, read the screen, tap, scroll, fill in fields, verify assertions, record videos — automatically, on iOS and Android.
A test report with screenshots is generated automatically at the end of each test session.
Architecture
Claude Code
| MCP protocol (stdio)
v
Phantom (Node.js TypeScript)
| |
v v
iOS Android
xcrun simctl ADB
WebDriverAgent UIAutomator
(localhost:8100) (adb shell)
| |
v v
Simulateur / iPhone Emulateur / DeviceRelated MCP server: Glance
Prerequisites
Tool | Required for | How to check |
macOS 13+ | all | - |
Xcode 15+ | iOS |
|
Node.js 18+ | all |
|
Appium 3+ | iOS (WDA) |
|
xcuitest driver | iOS (WDA) |
|
Android SDK | Android |
|
Installation
Option A — npm (recommended)
# 1. Installer le package
npm install -g phantom-mcp
# 2. Installer Appium + driver iOS
npm install -g appium
appium driver install xcuitest
# 3. Enregistrer dans Claude Code
claude mcp add -s user phantom -- npx phantom-mcpOption B — from source
git clone https://github.com/nthimpulse/phantom-mcp.git
cd phantom-mcp
npm install
npm run build
claude mcp add -s user phantom -- node "$(pwd)/build/index.js"The 24 tools
Device management
Tool | Description |
| Lists all devices (iOS sims + Android emus + real devices) |
| Selects the active device. Auto-boots if off. Auto-prepares the device (opt-out via skip_setup) |
| Sets the device to a clean state: clear clipboard / status bar overrides / dismiss keyboard / force QWERTY iOS |
Observation
Tool | Description |
| Captures the active device screen |
| Accessibility tree with index [N] for each element |
| Waits for an element to appear (with timeout) |
| Scrolls until an element is found |
Assertions
Tool | Description |
| Verifies that text IS on the screen |
| Verifies that text IS NOT on the screen |
Interaction
Tool | Description |
| Taps (by index, coordinates, or text). Auto-dismisses keyboard if target is obscured |
| Long press (context menus) |
| Text entry with clear option, and verify option to re-read the value after typing |
| Swipe (up/down/left/right) |
| Closes the soft keyboard (no-op if not visible) |
Navigation
Tool | Description |
| Opens a URL / deep link |
Device actions
Tool | Description |
| Simulates a shake |
| Changes orientation (portrait/landscape) |
| Starts/stops video recording |
App lifecycle
Tool | Description |
| Launches an app by bundle ID / package name |
| Closes an app |
Analysis & Automation (Tier 3)
Tool | Description |
| Accessibility audit: missing labels, tap targets too small, images without alt text |
| Automatic test report: start to begin tracking, end to generate the markdown. Each action is tracked automatically. |
| Compares two screenshots pixel by pixel to detect visual regressions |
| Executes the same action on multiple devices in one command |
Automatic operation
Device selection
Phantom never boots a device automatically. It asks you to choose:
If only 1 device is active, it uses it automatically
If multiple, it asks you to choose with
set_deviceIf none, it shows you the list of available devices
Auto-launch WDA (iOS)
WebDriverAgent is launched automatically on the first iOS tool that needs it. First launch ~60-90s (Xcode build), then instantaneous.
ADB multi-device (Android)
All ADB commands target the device selected via -s <serial>. No multi-device confusion.
Text entry (AZERTY compatible)
Entry uses pbcopy + Cmd+V (paste) instead of the virtual keyboard. It is instantaneous and works on all keyboard layouts (AZERTY, QWERTY, etc.).
Automatic test report
Each action (tap, type, swipe, assert...) is automatically recorded with a screenshot. At the end of the test, a markdown report is generated in /tmp/phantom-report-xxx/.
Security
All system commands go through
execFile(no shell)Inputs validated by regex: bundle IDs, UDIDs, package names, AVD names, URLs
iOS predicates escaped (anti-injection)
Android text escaped for the device shell
Zero
as any, zeroexec()shell
Configuration
Optional environment variables:
PHANTOM_WDA_PATH— path to WebDriverAgent (default: ~/.appium/...)PHANTOM_WDA_URL— WDA URL (default: http://localhost:8100)
Contributing
See CONTRIBUTING.md for local setup, the pattern for adding a new tool, naming conventions, and the PR workflow.
See also:
docs/LIMITATIONS.md — known limitations + workarounds
docs/PATTERNS.md — practical recipes (iOS DatePicker, bottom sheets, etc.)
docs/FEATURE_REQUESTS.md — prioritized features for upcoming versions
docs/CHANGES_2026-04-30.md — release notes v2.3.0
Troubleshooting
WDA crash in a loop
MobAI or another tool is using port 8100.
lsof -i :8100
pkill -f "MobAI""No device available"
xcrun simctl list devices available # iOS
adb devices -l # AndroidWDA does not start
cd ~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent
xcodebuild -project WebDriverAgent.xcodeproj \
-scheme WebDriverAgentRunner \
-destination "platform=iOS Simulator,name=iPhone 17 Pro" \
testADB not found
ls ~/Library/Android/sdk/platform-tools/adbProject structure
phantom/
src/
index.ts Point d'entree MCP (24 tools)
platforms/
types.ts Interfaces communes
ios/
simctl.ts Wrapper xcrun simctl
wda.ts Client WDA + auto-launch
android/
adb.ts Wrapper ADB complet
tools/ 24 tools (21 fichiers)
utils/
device-manager.ts Detection + routing multi-device
xml.ts Parser XML partage
docs/
README.md Ce fichier
TUTORIAL.md Tuto pas-a-pas
FLOWS.md Exemples de flows de testAvailable Tools
24 toolsaccessibility_auditA
Verifie l'accessibilite de l'ecran actuel : labels manquants, tap targets trop petits, images sans alt text. Retourne un rapport de violations.
Inputs: no named parameters.
assert_not_visibleA
Vérifie qu'un élément contenant le texte donné n'est PAS visible à l'écran.
Inputs: text (required).
assert_visibleA
Vérifie qu'un élément contenant le texte donné est visible à l'écran. Retourne OK ou FAIL avec les éléments actuellement visibles.
Inputs: text (required).
deep_linkB
Ouvre une URL ou un deep link dans l'app (ex: myapp://profile, https://example.com). Fonctionne sur iOS et Android.
Inputs: url (required).
dismiss_keyboardA
Ferme le clavier sur le device actif (iOS et Android). No-op si pas de clavier visible. À utiliser après un type_text quand le clavier bloque les boutons en bas.
Inputs: no named parameters.
get_ui_treeA
Retourne l'arbre d'accessibilité de l'écran — tous les éléments visibles avec type, texte, position. Fonctionne sur iOS et Android. Chaque élément a un index [N] utilisable avec tap.
Inputs: no named parameters.
kill_appB
Ferme une app sur le device actif.
Inputs: bundle_id (required).
launch_appB
Lance une app sur le device actif. iOS : bundle ID (ex: com.monapp.ios). Android : package name (ex: com.monapp.android).
Inputs: bundle_id (required).
list_devicesA
Liste tous les devices disponibles — simulateurs iOS, émulateurs Android, et vrais devices connectés. Affiche la plateforme et l'état de chaque device.
Inputs: no named parameters.
long_pressA
Appui long sur un élément de l'écran. Utile pour les menus contextuels, drag & drop, ou actions secondaires.
Inputs: index, x, y, text, +1 more.
multi_deviceA
Execute la meme action sur plusieurs devices et retourne les resultats combines. Utile pour tester sur iOS + Android en une seule commande.
Inputs: device_ids (required), action (required), bundle_id.
prepare_deviceA
Prépare le device actif pour une session de test propre : dismiss keyboard, clear clipboard, reset status bar overrides, force keyboard QWERTY (iOS). Tout est opt-out via flags. Auto-appelé par set_device sauf si skip_setup=true.
Inputs: dismiss_keyboard, clear_clipboard, clear_status_bar, force_qwerty.
rotateB
Change l'orientation de l'écran du device (portrait ou landscape).
Inputs: orientation (required).
screenshotA
Prend un screenshot du device actif (iOS ou Android) et le retourne comme image.
Inputs: no named parameters.
scroll_until_visibleA
Scroll vers le bas (ou la direction choisie) jusqu'à trouver un élément contenant le texte donné. Retourne l'élément trouvé ou une erreur après max_scrolls.
Inputs: text (required), direction, max_scrolls.
set_deviceA
Sélectionne le device à utiliser pour cette session de test. Si le device est éteint, il sera démarré automatiquement. Appelle list_devices d'abord pour voir les IDs. Auto-prépare le device (clear clipboard/status bar, dismiss keyboard, force QWERTY iOS) — opt-out via skip_setup=true.
Inputs: device_id (required), skip_setup.
shakeA
Simule un geste de shake sur le device. iOS : via raccourci Simulator (Ctrl+Cmd+Z). Android : swipes rapides.
Inputs: no named parameters.
swipeB
Fait un geste de swipe sur l'écran. Fonctionne sur iOS et Android.
Inputs: direction (required), distance.
tapB
Tape sur un élément de l'écran. Fonctionne sur iOS et Android. Utilise index (du get_ui_tree), coordonnées (x,y), ou texte. Auto-dismiss le clavier si la cible est physiquement masquée par lui (sécurité, pas de retap nécessaire).
Inputs: index, x, y, text, +1 more.
test_reportA
Gère le rapport de test automatique. Le rapport démarre AUTOMATIQUEMENT dès la première interaction (tap, type_text, etc.) — tu n'as PAS besoin d'appeler 'start'. Appelle UNIQUEMENT action='end' quand tu as fini de tester pour générer le rapport markdown. Si tu veux nommer le rapport, appelle action='start' avec un nom AVANT de commencer.
Inputs: action (required), name.
type_textA
Écrit du texte dans un champ. Fonctionne sur iOS et Android. Peut cibler un champ par son label/texte. Avec verify=true (opt-in), re-lit le champ après le type pour détecter les pickers d'autocomplete qui interceptent les keystrokes.
Inputs: text (required), element_text, clear_first, verify.
video_recordA
Enregistre une vidéo de l'écran du device. Utilise action='start' pour commencer et action='stop' pour arrêter et récupérer le fichier.
Inputs: action (required).
visual_diffA
Compare deux screenshots pour detecter des regressions visuelles. action='snapshot' pour sauver une reference, action='compare' pour comparer avec la reference.
Inputs: action (required), name, threshold.
wait_for_elementA
Attend qu'un élément apparaisse à l'écran (utile après navigation ou chargement). Retourne l'élément trouvé ou une erreur après timeout.
Inputs: text (required), timeout, interval.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 24 tools
Each tool targets a distinct action: tap, long_press, swipe, type_text, etc. Even similar tools like assert_visible and assert_not_visible are clearly opposites. No functional overlap.
All tool names use lowercase snake_case, with a mix of verb-first and noun-first constructions (e.g., 'accessibility_audit' vs 'assert_visible'), but the pattern is largely predictable and readable.
24 tools is slightly high but well-scoped for mobile testing: device management, UI interaction, assertions, visual testing, reporting, and gestures are all covered. Each tool has a clear purpose.
The set covers core workflows: device setup, UI queries, interactions, assertions, screenshots/video, and reporting. Missing explicit drag-and-drop or back navigation, but swipe and long_press compensate.
Maintenance
Related MCP Connectors
Mozark's MCP server for AI-powered app testing: device access, test automation, and QA insights.
MCP server for building and testing AI agents with multi-model experimentation and insights.
Cloud Android 14 phones that Claude, Claude Code, Cursor and Codex can use over MCP. Ready in ~15 s. Plain-English tasks return pass/fail, steps, screenshots and video. 1¢ per phone-minute, AI included, 100 free minutes a month.
MCP server for Appcircle mobile CI/CD platform.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceAn MCP server that lets AI agents drive real mobile-app automation on connected devices, enabling natural-language test tasks, test case generation, and app/build management for Android and iOS.-
- AlicenseNot gradedqualityAmaintenanceAn MCP server that gives Claude Code a real browser, enabling it to navigate, click, type, screenshot, and inspect web pages during development. It also supports multi-step JSON test scenarios, assertions, session recording, and visual regression testing against web apps.106 npmMIT
- AlicenseNot gradedqualityAmaintenanceAn MCP server that gives Claude Code a real browser, enabling navigation, clicking, form filling, screenshots, and accessibility snapshots directly from the terminal. It also supports multi-step JSON test scenarios, assertions, session recording, and visual regression testing with network and console monitoring.106 npmMIT
- AlicenseNot gradedqualityAmaintenanceAn MCP server that gives Claude Code a real browser, enabling it to navigate pages, click, type, capture screenshots, run multi-step test scenarios with assertions, and monitor console and network activity directly from the terminal.106 npmMIT