react-native-eye

React Native MCP server · iOS and Android

Your coding agent can see the app it is building.

react-native-eye is a React Native MCP server. It connects Claude Code, Cursor or any MCP client to a running React Native app. The agent reads the screen, taps and types, and checks logs, network and state. It works through Metro, so the app needs no SDK and no code changes.

Add it to Claude Code

claude mcp add react-native-eye -- npx -y react-native-eye@latest
Cursor, Codex and other clients
  • 35 tools
  • iOS simulators, Android emulators
  • No telemetry
  • MIT

The screen

Welcome back Email Password Log in Forgot password? Create account

What the agent reads

› observe
LAYOUT (js):
ERRORS:
none
LOGS:
[log] auth: no saved session
› get_layout {"search": ["Log in"]} Log in @196,468 (layout: js)

Example output for a login screen. Point at a line to find the element.

A whole flow in one call

Most device tools cost the agent one model round trip per tap. Here the agent sends the steps together and the server runs them back to back. A redbox or an uncaught exception stops the flow at once, and the agent gets the result of every step.

  • observeScreenshot, interactive elements, recent errors and recent logs.
  • run_flowTaps, typing, waits and assertions, run on the server.
  • check_stateCurrent route, store state and unhandled errors.
Request · run_flow
{ "steps": [
  { "type": { "text": "a@b.c", "into": { "placeholder": "Email" } } },
  { "type": { "text": "hunter2", "into": { "placeholder": "Password" } } },
  { "tap": { "text": "Log in", "via": "os" } },
  { "wait_for": { "text": "Home", "timeout_ms": 3000 } },
  { "expect_not": { "text": "Error" } }
] }
Response
Flow completed.

1. type({"text":"a@b.c","into":{"placeholder":"Email"}}) — ok (input: js)
2. type({"text":"hunter2","into":{"placeholder":"Password"}}) — ok (input: js)
3. tap({"text":"Log in","via":"os"}) — ok (input: os/runner)
4. wait_for({"text":"Home","timeout_ms":3000}) — ok
5. expect_not({"text":"Error"}) — ok

What the agent can do

35 tools in five groups. Every response says which path ran, so nothing switches silently.

  • See the screen

    Element positions come from the app's JS runtime in about 80 ms. OCR reads what the tree cannot: images, WebViews and native dialogs.

    observescreenshotget_layoutread_screen_textget_component_tree
  • Act

    A JS press calls the element's own onPress in about a millisecond. A real touch goes through the driver on the device, for gestures, system dialogs and native views.

    run_flowtaptype_textswipescroll_topress_keynavigateopen_url
  • Debug

    Logs, network requests with bodies, store state and JS evaluation. Crashes that LogBox swallows are still reported.

    check_stateget_logsget_errorsget_networkget_stateeval_jsget_job
  • Measure

    Which components rendered and why, a Hermes CPU profile, CPU by thread and frame timing. No setup in the app.

    profile_rendersprofile_jssample_cpuget_fps
  • Manage devices

    Install, launch and reload the app, grant permissions and record video.

    connectlist_targetslist_deviceslaunch_appreload_appinstall_appopen_simulatorset_permissionrecord_videostop_recordingping

Composite tools: one call instead of many.

Two paths into the app

The server reaches the app two ways and picks the cheaper one for each call.

Your agentClaude Code, Cursor, Codex
MCP · stdio
react-native-eyeRuns on your machine
CDP · Metro
JS runtime (Hermes)Layout, presses, typing, logs, network, state
HTTP · localhost
Driver on the deviceReal touches, keys, OS view hierarchy, screenshots

Through the JS runtime

≈ 1 ms per press · ≈ 80 ms per full-screen layout

The server walks React's fiber tree over the Chrome DevTools Protocol. It measures elements and calls press and text handlers directly, with no touch involved.

Through the device

Prebuilt in the npm package · installs itself on first use

An XCUITest runner on iOS and an instrumentation server on Android deliver real touches and type any Unicode text. If the driver cannot start, input falls back to axe or adb, and the response says so.

Measured: the device driver against the tools it replaces

iOS simulator. One feed swipe, median of 40.
driver
0.93 s
axe
26.68 s
3 of 40 timed out at 90 s
Android emulator. View hierarchy over a playing video, median of 10.
driver
4.60 s
uiautomator
27.10 s
9 of 10 failed

From the project's own field tests against a busy video feed, on an iOS 26 simulator and an Android 16 emulator. Both charts share one scale.

Connect it in three steps

  1. Add the server to your client

    # in your project folder
    claude mcp add react-native-eye -- npx -y react-native-eye@latest
  2. Start Metro and a dev build

    Run the app in an iOS simulator or an Android emulator the way you usually do. Metro on ports 8081–8083 and 19000–19002 is found automatically. For any other port, add --port 8090 to the arguments.

  3. Ask the agent

    Connect to my app and tell me what is on the screen.

    The agent calls connect, then observe. The first call on each device installs the driver once.

No telemetry. No accounts. No cloud.

The only network traffic goes to localhost: Metro and the device drivers. A test fails the build if an external URL appears in the server's source.

Good to know

  • Dev builds only. A production build has no Metro connection to attach to.
  • Tested on iOS simulators and Android emulators.
  • React Native below 0.85 allows one debugger at a time, so close other debuggers first.

React Native MCP server: common questions

What is a React Native MCP server?
An MCP server gives an AI coding agent tools it can call. A React Native MCP server points those tools at a running React Native app, so the agent can read the screen, tap, type and check logs, network requests and state while it writes code. react-native-eye does this through Metro, with no SDK in the app.
Which AI agents does it work with?
Claude Code, Cursor, Codex, Claude Desktop and any other client that runs MCP servers over stdio.
Does it work with Expo?
Yes. It supports Expo SDK 54+ and React Native 0.70+, as a dev build with Metro and Hermes running.
Do I have to change my app's code?
No. The server attaches to the debugger endpoint Metro already exposes. One optional line, globalThis.__RNE_STORES__ = …, makes store state easier to read.
Does it work on iOS and Android?
Yes: iOS simulators on macOS and Android emulators through adb. It needs a dev build; a production build has no Metro to attach to.
Is it free?
Yes. It is MIT licensed, with no account, no usage cap and no telemetry.