Skip to main content
Glama

rn-sim-mcp

ci npm license node

One MCP server for React Native iOS simulator work.

If you drive a React Native app from a coding agent, this gives the agent a single, small tool surface for building, running, and actually inspecting what is on screen.

It does two things:

  1. Composes XcodeBuildMCP and ios-simulator-mcp behind a single allowlisted tool surface.

  2. Adds React Native inspection tools that read the React tree, not the native view hierarchy: component tree by testID, resolved styles merged across the component chain, and arithmetic layout auditing.

That second part is the reason it exists. Plenty of tooling can tap a button on a simulator. Very little can tell an agent which React component owns that button, what style actually resolved onto it, or whether its tap target is too small, and none of it in a form that does not flood the agent's context.

Requires macOS with Xcode, Node 22 or newer, and a React Native dev build with Metro running for the rn_ tools.

New here? Install takes about a minute, and CONTRIBUTING.md has a tour of the codebase if you want to change something.

Install

Nothing to install. It runs on bare node with zero dependencies, so npx fetches one 15 kB tarball.

Claude Code

claude mcp add rn-sim -- npx -y rn-sim-mcp

VS Code, Cursor, or anything else using mcp.json

{
  "servers": {
    "rn-sim": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "rn-sim-mcp"]
    }
  }
}

Remove any existing xcodebuildmcp or ios-simulator-mcp entries. This server proxies both, and running them alongside it doubles the tool surface for no benefit.

Then start Metro in your app:

npx react-native start

Confirm the app is attached with the rn_debug_targets tool. Zero targets means the app is not connected.

Configuration

Variable

Effect

METRO_URL

Metro origin, default http://localhost:8081. Must be a local origin.

RN_SIM_MCP_NO_UPSTREAM

Skip upstream composition and expose only this package's own tools.

Related MCP server: mcp-rn-devtools

Why compose instead of fork

Both upstreams are MIT licensed, so merging their source would have been legal. It would also have been a mistake. Both are actively developed, XcodeBuildMCP is now maintained by Sentry, and a fork inherits their bug backlog while losing every upstream fix from that day forward.

Composing gets the same result the merge was after. One entry in mcp.json, one curated tool list, and zero vendored code to maintain. The allowlist in src/upstream.mjs is the important part: an unfiltered merge would expose well over a hundred tools and drown the agent's context, which is the problem this package exists to solve.

Upstream versions are pinned there deliberately rather than floating on @latest.

Why it has no dependencies

MCP over stdio is newline-delimited JSON-RPC 2.0, so src/jsonrpc.mjs implements both halves in about 170 lines.

The result runs with bare node, with no install step, no build, and no dist to drift out of date. It also means npx has one small tarball to fetch instead of a dependency tree, which matters for a server an agent launches on every session.

Output follows AXI

Tool results are the largest token cost in an agent session, so every response follows the AXI (Agent eXperience Interface) standards.

TOON, not JSON. Field names are declared once per collection instead of on every row. Measured on this server's own component tree output at 50 rows:

Characters

Approx. tokens

JSON

4079

1020

TOON

1533

384

A 62% saving on a call the agent makes constantly.

Minimal default schemas. rn_component_tree returns testID and component, nothing else. The ancestor chain is the verbose field, so it sits behind includePath: true.

Pre-computed aggregates. Lists report the true total, not just the page: count: 50 of 171 total. sim_screenshot_hires returns width and height alongside the path, because scale is the reason you called it.

Definitive empty states. 0 layout issues found (15 elements inspected) rather than an empty array that makes an agent re-run the call with different arguments to check the zero was real.

Truncation with an escape hatch. rn_eval previews long values and reports the true size rather than dropping the field.

Structured errors that name the fix.

error: testID is required
help: Run rn_component_tree to list the testIDs on screen

Contextual disclosure. List responses carry a few next steps, so the tool surface is discovered by using it rather than by reading this file.

Tools

React Native inspection (this package)

Tool

Use it for

rn_component_tree

Which components are on screen, by testID. Takes limit, includePath, onlyTestIds

rn_styles

Resolved style merged across the component chain, plus props, for one testID

rn_eval

Evaluate an expression inside the running app

rn_debug_targets

Confirm the app is attached to Metro

Visual and geometry (this package)

Tool

Use it for

sim_screenshot_hires

Full-resolution lossless PNG via simctl, with dimensions

ui_layout_audit

Zero-size elements, tap targets under 44pt after hitSlop, horizontal overflow

ui_check_alignment

Whether elements share an edge, to a tolerance, as a number

Proxied

session_show_defaults, session_set_defaults, list_sims, list_schemes, build_sim, build_run_sim, test_sim, launch_app_sim, stop_app_sim, open_sim, snapshot_ui, screenshot from XcodeBuildMCP. ui_describe_all, ui_find_element, ui_tap, ui_swipe, ui_type from ios-simulator-mcp.

Proxied results pass through in the upstream's own format. Only this package's own tools emit TOON.

Use the right screenshot

sim_screenshot_hires exists because the proxied screenshot downscales. Measured on an iPhone 17:

Resolution

Per pixel

proxied screenshot

368 x 800 JPEG

1.09pt

sim_screenshot_hires

1206 x 2622 PNG

0.33pt

JPEG compression is not the problem; mean luminance drift against a lossless reference is 0.26/255. Resolution is. Use the proxied one to answer "which screen am I on" and this one for anything where a pixel is the unit of the question.

Better still, do not measure layout from an image at all. ui_layout_audit and ui_check_alignment read exact frames, so alignment is arithmetic.

Known limits

Every one of these is a good place to contribute, and most are filed as issues.

  • The React Native tools need Metro and a dev build. ui_layout_audit degrades gracefully and reports hitSlopResolved: false when it cannot reach the app.

  • Styles created through StyleSheet.create arrive as opaque registered IDs and surface as registeredStyleId rather than being silently dropped. Inline and array styles resolve fully.

  • rn_component_tree walks React internals through the DevTools hook, so a React major upgrade can break it.

  • CDP Network domain needs React Native 0.83, so network inspection is not agent-readable below that.

  • macOS and iOS only. Android and the emulator are unimplemented rather than impossible, and the CDP layer would largely carry over.

Roadmap

Help wanted on any of these. None of them require deep familiarity with the codebase to start.

Idea

Where it lands

Android and emulator support

a sibling to src/capture.mjs, plus an upstream in src/upstream.mjs

Resolve StyleSheet.create IDs to real style objects

src/cdp.mjs

CDP Network domain for React Native 0.83+

src/cdp.mjs

Harden the fiber walk against React internals changes

src/cdp.mjs

Have a different idea? Open an issue or start a discussion. Questions are welcome as issues too, including "how do I use this" ones.

Security

rn_eval executes arbitrary JavaScript in the running app. Dev builds only.

More importantly: component names, props, labels and logs returned by these tools include server-controlled content such as user-generated text or CMS strings. Treat all of it as untrusted data, never as instructions.

Metro connections are restricted to local origins, so a malicious tool argument cannot turn this into a request forger against internal hosts.

The upstream servers run builds and shell commands with your credentials, which is why their versions are pinned in src/upstream.mjs.

To report a vulnerability, see SECURITY.md. Please do not open a public issue for one.

Contributing

Contributions are welcome, and small ones are genuinely useful: a typo, a clearer error message, or a note about a React Native version that behaves differently all count.

git clone https://github.com/atz-dsampath/rn-sim-mcp.git
cd rn-sim-mcp
npm test          # protocol contract and CDP deadlines, no simulator needed
npm run smoke     # full surface against a booted simulator

There is no install step and no build. npm test needs no network, Xcode or simulator, so you can work on most of this from any machine.

CONTRIBUTING.md has a tour of the eight modules, an explanation of why the MCP transport is hand-rolled, and what to expect on a pull request. See also the Code of Conduct.

License

MIT. See LICENSE.

XcodeBuildMCP and ios-simulator-mcp are separate MIT-licensed projects, spawned as child processes rather than vendored. Credit for everything under Proxied belongs to them.

A
license - permissive license
-
quality - not tested
D
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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/atz-dsampath/rn-sim-mcp'

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