Skip to main content
Glama

expo-mcp-bridge

npm CI license

Let your AI agent use your phone app the way it uses a browser.

Claude Code, Antigravity, Cursor and any other MCP agent can read the screen, tap, type and fill forms, scroll, take screenshots, read console errors and network requests, and press volume / back / home in your Expo / React Native app, running live in Expo Go on your real phone. No more pasting screenshots into the chat.

  • πŸ“± Real devices, zero native setup β€” Expo Go or a dev build, iPhone or Android, over Wi-Fi.

  • πŸͺΆ Token-cheap β€” the agent reads a compact outline of the visible screen; every action returns only what changed.

  • ⚑ Fast β€” actions finish as soon as the UI settles; app_batch runs a whole flow in one call.

  • πŸ”Ž Sees what's broken β€” new JS errors and failed requests are attached to the action that caused them.

  • πŸ€– Skill included β€” init installs an agent skill (Claude Code) and an AGENTS.md guide (Antigravity, Cursor, Codex…).

  • πŸ”’ Dev only β€” in production builds <AgentBridge /> renders its children and nothing else.

scroll [e1]
  button "icon:chevron-back" [e2]
  text "Welcome back"
  input "you@example.com" value="" [e3]
  input "β€’β€’β€’β€’β€’β€’β€’β€’" value="" (secure) [e4]
  button "icon:eye" [e5]
  button "Log In" [e7]

What the agent sees of a real login screen: ~70 tokens instead of ~1,000 for a screenshot. Tapping e5 returns just:

Tapped.
Changes (+ added, - removed):
~ input "β€’β€’β€’β€’β€’β€’β€’β€’" value="" [e4]
+ button "icon:eye-off" [e9]
- button "icon:eye" [e5]

πŸš€ Quick start

Option A β€” let your AI do it (one shot)

Paste this to Claude Code, Antigravity or Cursor inside your Expo project:

Read https://raw.githubusercontent.com/Rudrasamadhiya/expo-mcp-bridge/main/AI_SETUP.md and set it up in this project.

Option B β€” by hand (2 minutes)

npx expo install expo-mcp-bridge react-native-view-shot
npx expo-mcp-bridge init

Mount the bridge once in your root layout (app/_layout.tsx):

import { Stack, router } from 'expo-router';
import { AgentBridge } from 'expo-mcp-bridge';

export default function RootLayout() {
  return (
    <>
      <Stack />
      <AgentBridge router={router} />
    </>
  );
}

Run npx expo start (LAN mode), open the app on your phone (same Wi-Fi), restart your agent and ask:

"Open the app, try the sign-up form with bad input, and tell me what breaks."

Agent configuration

init writes .mcp.json (Claude Code). Other agents:

Agent

Config

Claude Code

.mcp.json from init, or claude mcp add expo-app -- npx expo-mcp-bridge

Cursor

npx expo-mcp-bridge init --cursor β†’ .cursor/mcp.json

Antigravity / Windsurf / Cline

MCP settings: {"mcpServers": {"expo-app": {"command": "npx", "args": ["expo-mcp-bridge"]}}}

On Windows: "command": "cmd", "args": ["/c", "npx", "expo-mcp-bridge"].


Related MCP server: React Native Debug MCP

🧰 Tools

Tool

What it does

app_status

Connected device, OS, screen size

app_snapshot

Outline of the visible screen with stable refs ([e3])

app_tap

Press by ref, testID or visible text (long: true for long-press)

app_type

Fill an input (submit, append)

app_batch

Several taps/types/scrolls/navigations in one call

app_scroll

down / up / top / bottom

app_toggle

Flip a Switch

app_navigate

expo-router path or deep link (replace to keep the stack shallow)

app_wait

Wait for text / testID to appear or disappear

app_dismiss_keyboard

Hide the keyboard

app_screenshot

JPEG of the visible screen; saveTo file; fullScroll = whole page as one tall image

app_layout

Element positions (dp) and font sizes

app_logs

Console logs and JS errors (cursor-based)

app_network

fetch/XHR requests with status, timing and bodies

app_eval

Run JS inside the app (dev only)

app_reload

Reload the JS bundle (tells you honestly if it can't)

device_key

volume_up, volume_down, mute, back, home, power… (Android via adb)

πŸ’» CLI

npx expo-mcp-bridge init            # in your Expo project: .mcp.json + agent skill + AGENTS.md section
npx expo-mcp-bridge init --cursor   # also write .cursor/mcp.json
npx expo-mcp-bridge                 # run the MCP server (your agent starts this from .mcp.json)
npx expo-mcp-bridge --help

Environment variable

Default

What

EXPO_MCP_PORT

8347

WebSocket port the phone connects to (match <AgentBridge port>)

You normally never run the server yourself β€” the agent launches it over stdio. To try it by hand, any MCP client works, e.g. npx @modelcontextprotocol/inspector npx expo-mcp-bridge.

βš™οΈ Props

<AgentBridge
  router={router}      // expo-router's router, for exact app_navigate
  host="192.168.1.20"  // computer IP (auto-detected from Metro)
  port={8347}          // must match EXPO_MCP_PORT
  allowEval={false}    // disable app_eval
  enabled={false}      // turn the bridge off
/>

πŸ”§ How it works

 AI agent ──MCP (stdio)──▢ expo-mcp-bridge server ◀──WebSocket :8347── <AgentBridge /> in your app

The in-app component reads React's live component tree, so it sees exactly what you rendered: your testIDs, labels, inputs and lists. It calls your real onPress / onChangeText handlers, so app logic runs exactly as if a user did it. Native-stack screens hidden under the current one are skipped, modals are captured as overlays, and screenshots capture the visible screen view (whole-window capture can return stale frames on Android).

🩺 Troubleshooting

Symptom

Fix

No app connected

Same Wi-Fi, LAN mode (not --tunnel), firewall allows Node on 8347, <AgentBridge /> mounted. USB-only Android: adb reverse tcp:8347 tcp:8347 + host="localhost".

Port 8347 is already in use

Another agent session runs the server β€” close it or set EXPO_MCP_PORT + port prop.

Metro: Unable to resolve "expo-mcp-bridge" after reinstalling

npx expo start --clear

app_reload can't reload

Metro was restarted; shake the phone β†’ Reload once.

Screenshots fail

Install react-native-view-shot (rebuild the dev client if you use one).

🎬 Make launch videos too

expo-launch-video builds on this bridge: your agent records the app live from the phone and edits a launch video with motion graphics, pop-outs and sound, in a browser studio you can prompt.

Limits

An in-app library controls your own app only; the OS blocks system dialogs and other apps. device_key covers hardware keys via adb on Android. Gestures that exist only in native code (a pan handler with no onPress) can't be triggered from JS.

Contributing

npm install && npm test β€” the bridge runs in Node against the real MCP server. See CONTRIBUTING.md. MIT licensed.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    An MCP server that lets AI agents control iOS and Android devices (tap, scroll, type, take screenshots, read UI trees, and run code). Works with multiple devices at the same time.
    66 npm
    50
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    Give any LLM agent a real Android or iPhone. 62 MCP tools: tap, swipe, type, screenshot, screen-tree reading, app launch, camera, TTS, crash reports, batched execution. Android via ADB, iPhone via WebDriverAgent, on-device inference, Docker+KVM emulators. Works with Claude Code, Cursor, LangChain, LlamaIndex, and any MCP client. MIT.
    66
    537 PyPI
    387
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    An MCP server that gives AI agents hands-on control of a live React Native app, enabling UI taps, screenshots, UI/component trees, native logs, and JS/React profiling to debug, verify fixes, and diagnose performance issues.
    16
    4 npm
    MIT