Skip to main content
Glama

rn-device-mcp

An MCP server that puts the iOS Simulator and Android emulators/devices in front of your coding assistant. Built for React Native / Expo work: the assistant can look at the screen, read the app's logs, open deep links, install a build and relaunch the app, instead of asking you to do it and describe what you see.

macOS only (uses xcrun simctl, sips and adb).

Tools

iOS Simulator

Tool

What it does

ios_simulators

Simulators with runtime, state and udid, booted first

ios_boot / ios_shutdown

Boot by udid or name (waits until ready), shut down

ios_screenshot

Screen as an image (downscaled to 900 px by default)

ios_open_url

Deep link, universal link or Expo dev-client URL

ios_launch_app / ios_terminate_app

By bundle id; relaunch: true for a cold start

ios_install_app

Install a simulator .app (from eas build --local, Xcode DerivedData)

ios_apps

Installed apps with bundle ids

ios_logs

Unified log for the last N minutes, filtered by process and/or substring

Android

Tool

What it does

android_devices

Emulators and USB devices known to adb

android_screenshot

Screen as an image

android_open_url

Deep link via ACTION_VIEW

android_launch_app / android_stop_app

By package name; relaunch: true for a cold start

android_install_apk

adb install -r

android_reverse_metro

adb reverse tcp:8081 so a USB device reaches Metro

android_dev_menu

Opens the RN dev menu (menu key)

android_input

Tap at x,y, type text, or send a keyevent

android_logcat

Recent logcat, RN and crash tags only by default; clearAfter to read only new lines next time

iOS tools default to the booted simulator (simctl's booted alias); Android tools default to the only online device. Observation tools carry readOnlyHint: true; everything that changes device state does not.

Related MCP server: React Native Debug MCP

Setup

npm install && npm run build
claude mcp add rn-device --scope user -- node /absolute/path/to/rn-device-mcp/dist/index.js

adb is found via ADB_PATH, ANDROID_HOME, ANDROID_SDK_ROOT, ~/Library/Android/sdk, then PATH.

A typical loop

  1. ios_boot "iPhone 17 Pro" → ios_install_app build/MyApp.app → ios_launch_app com.example.myapp

  2. ios_open_url myapp://course/954 → ios_screenshot → the assistant reads the screen

  3. Something is off → ios_logs process: MyApp contains: "TypeError"

  4. Same on Android with android_*, plus android_input for a quick tap when there is no test id to hang on to.

Development

npm test          # vitest, no devices needed: the process runner is injected
npm run typecheck
  • src/exec.ts — execFile wrapper, no shell, so URLs and names are never interpreted

  • src/image.ts — PNG → downscaled base64 image content

  • src/ios.ts / src/android.ts — simctl and adb wrappers with output parsers

  • src/tools.ts — tool definitions and handlers

  • src/index.ts — MCP wiring over stdio

Available Tools

20 tools
android_devicesList Android devicesA
Read-only

Lists emulators and USB devices known to adb, with serial and state.

Inputs: no named parameters.

android_dev_menuOpen the RN dev menuA

Sends the menu key, which opens the React Native dev menu in debug builds.

Inputs: serial.

android_inputTap, type or press a keyA

Low-level input: tap at x,y (pixels from android_screenshot at maxDimension 0), type text into the focused field, or send a keyevent such as KEYCODE_BACK / 4.

Inputs: key, tap, text, serial.

android_install_apkInstall an APKC

Installs (or reinstalls, keeping data) an APK.

Inputs: apkPath (required), serial.

android_launch_appLaunch an appB

Launches an app by package name. relaunch: true force-stops it first.

Inputs: packageName (required), serial, relaunch.

android_logcatLogcatA

Recent logcat lines. By default only ReactNativeJS (console.*), ReactNative and crash tags; all: true lifts the filter. clearAfter: true empties the buffer so the next call shows only new lines.

Inputs: all, serial, contains, maxLines, +1 more.

android_open_urlOpen a URL / deep linkB

Opens a deep link or URL with an ACTION_VIEW intent.

Inputs: url (required), serial.

android_reverse_metroadb reverse for MetroA

Runs adb reverse tcp:8081 tcp:8081 so the app can reach Metro on the host (needed for USB devices, harmless on emulators).

Inputs: port, serial.

android_screenshotScreenshot the Android deviceA
Read-only

Captures the device screen and returns it as an image.

Inputs: serial, maxDimension.

android_stop_appForce-stop an appC

Force-stops the app.

Inputs: packageName (required), serial.

ios_appsInstalled appsA
Read-only

Lists installed apps with bundle ids. userOnly (default true) hides Apple's system apps.

Inputs: device, userOnly.

ios_bootBoot a simulatorA

Boots a simulator by udid or name (e.g. 'iPhone 17 Pro'), waits until it is ready and brings Simulator.app to front.

Inputs: device (required).

ios_install_appInstall a .app bundleB

Installs a simulator build (.app directory, e.g. from eas build --local or Xcode DerivedData).

Inputs: appPath (required), device.

ios_launch_appLaunch an appA

Launches an installed app by bundle id. relaunch: true terminates it first (cold start).

Inputs: bundleId (required), device, relaunch.

ios_logsSimulator logsA
Read-only

Recent unified-log lines from the simulator. Filter by process (the app's product name, e.g. 'MyApp') and/or a substring. JS console output from RN shows up under the app process.

Inputs: device, process, contains, maxLines, +1 more.

ios_open_urlOpen a URL / deep linkB

Opens a URL in the simulator: a deep link (myapp://...), a universal link, or an Expo dev-client URL (exp+myapp://...).

Inputs: url (required), device.

ios_screenshotScreenshot the simulatorA
Read-only

Captures the simulator screen and returns it as an image. Use it to see what the app is showing right now.

Inputs: device, maxDimension.

ios_shutdownShut down a simulatorA

Shuts down the booted simulator (or the given one).

Inputs: device.

ios_simulatorsList iOS simulatorsB
Read-only

Lists simulators with runtime, state and udid; booted ones first.

Inputs: includeUnavailable.

ios_terminate_appTerminate an appC

Kills the app process on the simulator.

Inputs: bundleId (required), device.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.1/5.0

    Scored across 20 tools

    Disambiguation4/5

    Tools are cleanly partitioned by platform prefix and a distinct action (boot, shutdown, install, launch, terminate, screenshot, logs), so an agent can pick correctly in almost all cases. The only mild overlaps are ios_launch_app vs ios_open_url (cold start vs deep link) and android_dev_menu vs android_input's KEYCODE_MENU keyevent, both of which the descriptions clarify.

    Naming Consistency4/5

    A consistent platform_action scheme (ios_*, android_*) with snake_case throughout makes the surface predictable. Minor deviations: list tools use bare nouns (ios_simulators, ios_apps, android_devices, ios_logs, android_logcat) instead of a verb, and the platform sets are asymmetric (ios_boot/ios_shutdown exist, android counterparts do not).

    Tool Count3/5

    20 tools is on the heavy side for a device-control server, though the count is partly explained by covering two platforms. Several tools are thin one-off wrappers (android_reverse_metro, android_dev_menu) that could arguably be folded into the input/log utilities.

    Completeness3/5

    The iOS lifecycle (boot, install, launch, terminate, screenshot, logs, apps) and the Android equivalents are broadly covered with no severe dead ends. Notable gaps: there is no iOS UI interaction tool (no tap/type equivalent to android_input), no way to start/boot an Android emulator, and no uninstall or clear-data operations on either platform.

    Related MCP Connectors

    Related MCP Servers