Skip to main content
Glama

expo-mcp

MCP server for Expo/React Native app automation with Maestro integration.

Features

  • Session-Based Architecture: start_session launches Expo, binds a device, and acquires a lease — no manual device ID management

  • Device Lease with TTL: 2-minute lease auto-renewed on every device tool call; expires after inactivity so other instances can use the device

  • Cross-Instance Coordination: Multiple MCP instances can run simultaneously without device conflicts

  • Expo Dev Server Management: Start/stop/reload Expo development server

  • Maestro Integration: Full UI automation tools (tap, input, screenshot, etc.)

Installation

npx -y expo-mcp

With pnpm:

pnpx expo-mcp

Usage with Claude Code

Add to your .mcp.json:

{
  "mcpServers": {
    "expo-mcp": {
      "command": "npx",
      "args": ["-y", "expo-mcp"]
    }
  }
}

Monorepo Setup

Use a positional argument to specify the app directory:

{
  "mcpServers": {
    "expo-mcp": {
      "command": "npx",
      "args": ["-y", "expo-mcp", "apps/mobile"]
    }
  }
}

Specific Device

Pin a specific simulator or emulator with --device-id:

{
  "mcpServers": {
    "expo-mcp": {
      "command": "npx",
      "args": ["-y", "expo-mcp", "--device-id=6D192F60-1234-5678-ABCD-000000000000"]
    }
  }
}

Tool Filtering

Exclude specific tools with --exclude-tools:

{
  "mcpServers": {
    "expo-mcp": {
      "command": "npx",
      "args": ["-y", "expo-mcp", "apps/mobile", "--exclude-tools=list_devices"]
    }
  }
}

Or expose only specific tools with --tools:

{
  "mcpServers": {
    "expo-mcp": {
      "command": "npx",
      "args": ["-y", "expo-mcp", "--tools=start_session,stop_session,take_screenshot"]
    }
  }
}

CLI Reference

Usage: expo-mcp [app-dir] [options]

Arguments:
  app-dir                      Path to Expo app directory (default: cwd)

Options:
  --device-id=<id>             Specific device to use (iOS simulator UUID or Android serial)
  --exclude-tools=tool1,tool2  Exclude specific tools from the MCP server
  --tools=tool1,tool2          Only expose specific tools
  -h, --help                   Show help message
  -v, --version                Show version number

Quick Start

# 1. Start session (launches Expo + binds device + acquires lease)
start_session({ target: "ios-simulator" })

# 2. Use tools directly (no device_id needed!)
take_screenshot()
tap_on({ text: "Login" })
input_text({ text: "hello@example.com" })
press_key({ key: "Enter" })
scroll({ direction: "down" })
swipe({ direction: "left" })

# 3. Run Maestro flows
run_maestro_flow({ flow_yaml: "- assertVisible: Welcome" })
check_maestro_flow_syntax({ flow_yaml: "- tap: Login" })

# 4. Reload app after code changes
reload_app()

# 5. Check logs if needed
get_logs({ level: "error" })

# 6. Stop session when done
stop_session()

Tools

Lifecycle Tools

Tool

Description

get_session_status

Get session status (server state, device info, lease remaining time)

start_session

Start Expo server, connect device, and acquire device lease

stop_session

Stop Expo server and release all resources

reload_app

Hot reload the app on connected device

get_logs

Get Metro bundler logs (filterable by level and source)

press_key

Press a key (Enter, Backspace, Home, Lock, Tab, Volume Up/Down)

scroll

Scroll the screen in a direction (default: down)

swipe

Swipe by direction or precise start/end coordinates

start_session Options

Option

Type

Description

target

ios-simulator | android-emulator | web-browser

Target platform to launch

device_id

string

Specific device (iOS UUID or Android serial). Auto-detected if omitted

host

lan | tunnel | localhost

Connection mode

port

number

Server port (default: 8081, auto-increments if busy)

clear

boolean

Clear Metro bundler cache

dev

boolean

Development mode (default: true)

minify

boolean

Minify JavaScript

max_workers

number

Max Metro workers

offline

boolean

Offline mode

scheme

string

Custom URI scheme

simulator_name

string

iOS simulator name (e.g., "iPhone 16 Pro")

clean_state

boolean

Clean simulator state before launch (default: false)

auto_login

object

Run a Maestro flow after app loads ({ flow_file: "path/to/flow.yaml" })

Maestro Tools

All Maestro tools work automatically once a session is active — device_id is injected from the session:

Tool

Description

take_screenshot

Capture screen (auto-resized for LLM context)

tap_on

Tap on UI element by text, id, or coordinates

input_text

Type text into focused field

back

Press back button

run_maestro_flow

Run Maestro YAML flow inline

run_maestro_flow_files

Run Maestro flow files from project directory

check_maestro_flow_syntax

Validate Maestro YAML flow syntax without running it

inspect_view_hierarchy

Get UI element tree of the current screen

list_devices

List all available devices (works without an active session)

Note: Device tools require an active session. Call start_session first. list_devices and check_maestro_flow_syntax can be called anytime.

Device Lease System

The device lease prevents one MCP instance from holding a device indefinitely:

  1. Acquire: start_session acquires a 2-minute device lease

  2. Auto-Renew: Every device tool call (take_screenshot, tap_on, etc.) resets the 2-minute timer

  3. Expire: If no device tool is called for 2 minutes, the lease expires and the device becomes available

  4. Re-acquire: Call start_session again to re-acquire (server stays running, no restart needed)

  5. Check: get_session_status shows remaining lease time

Multiple MCP instances coordinate via a file-based registry (/tmp/expo-mcp/instances/), so two instances cannot claim the same device simultaneously.

Environment Variables

Variable

Description

Default

EXPO_APP_DIR

Path to Expo app directory (CLI positional arg takes precedence)

Current working directory

MAESTRO_CLI_PATH

Path to Maestro CLI

~/.maestro/bin/maestro

ESSENTIAL_TOOLS

Comma-separated list of tools to expose (--tools takes precedence)

All tools

EXCLUDE_TOOLS

Comma-separated list of tools to exclude (--exclude-tools takes precedence)

None

LOG_BUFFER_SIZE

Max log lines to keep in memory

400

EXPO_TOKEN

Expo authentication token (only needed if offline mode is disabled)

None

How It Works

  1. Session Start: start_session starts Expo dev server, waits for device connection, and acquires a lease

  2. Device Binding: Connected device ID is stored in the session with a 2-minute TTL

  3. Automatic Injection: All Maestro device tools automatically use the session's device ID

  4. Lease Renewal: Every device tool call resets the lease timer

  5. Session End: stop_session cleans up everything, or the lease expires after inactivity

Non-Interactive Environments (CI/CD, AI Agents)

This MCP server automatically enables --offline mode when running in CI environments (CI=1). This allows the app to work without requiring an EXPO_TOKEN.

What Offline Mode Does

  • Skips Expo server communication (manifest signing)

  • Does NOT affect your app's network features (API calls, fetch, etc.)

  • Tunnel mode (--tunnel) is not available in offline mode

If You Need Expo Account Features

For features requiring Expo authentication, disable offline mode and provide EXPO_TOKEN:

{
  "mcpServers": {
    "expo-mcp": {
      "env": {
        "EXPO_TOKEN": "your-token-here"
      }
    }
  }
}

Then call start_session with offline: false:

start_session({ target: "ios-simulator", offline: false })

Requirements

  • Node.js >= 18

  • Xcode (for iOS Simulator)

  • Android Studio (for Android Emulator)

  • Maestro CLI (for UI automation)

License

MIT

-
security - not tested
F
license - not found
-
quality - not tested

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DaveDev42/expo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server