Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
METRO_PORTNoMetro's port when it is not one of the standard ones (8081–8083, 19000–19002). The `--port` argument in `args` and the `connect` tool's `port` do the same.
RNE_CACHE_DIRNoWhere the compiled OCR helper lives (default `~/Library/Caches/react-native-eye`).
RNE_OUTPUT_DIRNoDefault directory for recordings and saved profiles (default `~/Downloads`).
RNE_NATIVE_DRIVERNoSet to `off` to never install or start the on-device runner (iOS) or server (Android). Taps, swipes, typing and OS layout then go through axe/adb exactly as before the driver existed. On Android it also force-stops a server left running by an earlier session.
RNE_FILTERED_TOOLSNoComma-separated tool names to hide.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
pingA

Health check. Returns 'pong'.

connectA

Connect to a running React Native app via Metro. Optionally pass a port, a target_id from list_targets, or a device name — otherwise standard ports are scanned and the app's JS runtime is picked.

list_targetsA

List every debuggable React Native target Metro exposes (a device can have several: the JS runtime, the UI page, stale pages from earlier reloads). Pass a target_id to connect.

get_logsA

Recent console logs from the app. Filter by level and/or search substring. Note: only logs emitted after connect are captured — reload_app to catch cold-start output.

get_errorsB

Uncaught exceptions and redboxes captured since connecting. Includes the errors LogBox swallows, which never reach the debugger on their own.

get_networkA

Recent HTTP requests captured in-app. The list view shortens long URLs (query strings collapse to a char count) — pass detail: for the full URL and request/response bodies. Dev-tooling traffic (Metro, Expo, react-devtools, dev polls) is hidden unless include_dev:true; exclude:[...] drops URLs by substring. Note: requests before connect are missed (cold start).

eval_jsA

Evaluate JavaScript in the app's runtime and return the result. Statements are allowed, and a promise result is awaited (await fetch(...), AsyncStorage.getItem(...)) — pass the promise itself, not await (Hermes has no async/await in evaluated code). Pass background: true for work that outlives one tool call (a long measurement, a snippet that samples for 30s) and collect the result with get_job.

get_jobA

Collect the result of a background job started by eval_js (background: true). Without an id, lists every job the server is holding.

get_stateA

Read app store state (Redux/Zustand/custom), summarised depth-first inside the app so the result stays valid JSON. Optionally a dot-path (e.g. 'user.name') and a depth (default 3). resolved says whether the path actually walked to a value — a mistyped segment reports resolved:false with failedAt and availableKeys instead of silently looking the same as an honest undefined. Assign your store to globalThis.RNE_STORES for reliable access.

get_component_treeA

Depth-limited React component tree via the React DevTools hook, with testID and text where present. max_depth counts only components a developer actually authored — host components (RCTView, RCTText, ...) and structural wrappers (forwardRef/memo/context, styling HOCs) are free and can repeat any number of times without spending budget. RN's own dev-only infrastructure (LogBox, the debugging overlay, the root tag context) is omitted from the output entirely. Large trees are capped and marked truncated rather than returned unbounded.

screenshotA

Capture the current screen. Without output_path returns an inline JPEG downscaled to 800px (pass full_res:true for the native PNG); an image that would still be too large for the caller fails with an actionable error instead of being returned. With output_path saves to a file (format png/jpeg; mask is iOS-only) and returns the path.

read_screen_textA

Read the visible text off the screen with on-host OCR (Apple Vision). Works without a Metro connection and sees text the layout tree cannot: images, canvases, WebViews, native dialogs. Returns one line per recognized text run as <text> @x,y — x,y is the centre in tap units and can be passed straight to tap {x,y}. Lines that also exist in the app's JS layout are marked [tree]: prefer tap {text} for those, since an OCR box is just text, not a control. Optional: search (substring filters, case-insensitive), languages (e.g. ["de","en"]; auto-detected by default), compare_tree (default true). macOS host only; the first call compiles a small Vision helper (~10–30s, cached).

get_layoutA

Interactive on-screen elements with center coordinates. Elements scrolled out of view are listed separately as off-screen. Optional: filter with search terms (matched against text/testID), narrow by element type, or pass at:{x,y} to get the element at a point. source picks the capture path (js = app runtime, os = axe/uiautomator, default auto).

tapA

Tap an element by text, testID, or x+y coordinates. Pass duration_ms for a long press. via picks the delivery path (js = call the component's own press handler through the app runtime, os = a real simulator/device touch, default auto). Returns the coordinates tapped, the path used, and what changed on screen.

swipeA

Swipe in a direction (scaled to the screen), or between explicit coordinates. via picks the delivery path: js scrolls the container under the start point by the same distance through the app runtime (no touch), os is a real simulator/device gesture, auto (default) tries js and names the reason when it falls back.

scroll_toA

Bring an off-screen element into view. Returns immediately when it is already visible. via: js asks the element's own scroll container to jump to it (no touch, no swipe); os swipes toward it and re-reads the layout after each swipe, stopping as soon as it appears; auto (default) tries js and names the reason when it falls back.

type_textA

Type text into a text input. into selects the field by testID, placeholder or accessibilityLabel — omit it only when a single input is on screen. via "js" (default via "auto" tries it first) calls the field's own onChangeText in ~1ms and runs the app's real onChange pipeline; via "os" drives the simulator keyboard. verify (default true) reads the value back afterwards and fails loudly if it differs — the OS keyboard sends positional keycodes that a non-ASCII host keyboard layout silently rewrites.

press_keyA

Press a hardware key. "back" goes up one screen — via "js" (tried first by default) calls the navigation container's own goBack() with no touch, via "os" uses the hardware key (Android) or an edge swipe (iOS). "home" is OS-only. "enter" submits a text field by firing its own onSubmitEditing, the only route to a submit handler that does not need the OS keyboard — pass into to name the field when more than one is on screen and none holds focus.

list_devicesA

List available iOS simulators and Android devices (booted ones are marked).

launch_appB

Launch an app by bundle id (iOS) / package name (Android) on the active device. Optional: terminate_running to restart a running app, env to pass launch environment variables (iOS only).

install_appC

Install an app bundle on the active device (.app/.ipa on iOS, .apk on Android).

open_simulatorB

Open the iOS Simulator app (macOS only).

open_urlA

Open a deeplink or universal link on the active device (myapp://screen, https://…). Touch-free: it delivers no touch event, so it is unaffected by slow touch delivery and is usually the cheapest way to reach a screen.

set_permissionA

Grant, revoke or reset one privacy permission for an app, so the system alert never appears. iOS services: camera, photos, photos-add, location, location-always, contacts, contacts-limited, microphone, motion, calendar, reminders, media-library, siri, all. Android services: camera, microphone, photos, location, contacts, notifications. app_id defaults to the connected app.

reload_appA

Reload the JS bundle and wait for the new runtime (captures cold-start logs/network on the next run).

observeA

One-shot snapshot of the screen: screenshot + interactive elements + recent errors + recent logs. Sections are independent — one failing does not lose the rest. Prefer this over separate screenshot/get_layout/get_logs calls.

check_stateA

One-shot: current route + store state (optional dot-path) + recent errors. The route is discovered automatically — the react-navigation container ref is found by walking the React tree, so no app-side setup is needed (globalThis.RNE_ROUTE / globalThis.RNE_NAV still take precedence when the app publishes them). If no navigator is found the route is null and the hint says why.

run_flowA

Run a sequence of UI steps server-side in one call (tap/type/swipe/wait_for/expect/expect_not/eval). Set via:'js' to dispatch taps and typing through the app's fiber tree instead of paying a simulator touch per step; each step's report line names the path it used. Aborts on the first failure or app error, and returns an observe snapshot at the stop point. Prefer this over many separate tap/observe calls.

record_videoA

Start a screen recording (one at a time). Stop with stop_recording. Android uses screenrecord, which caps a clip at 3 minutes. codec applies to iOS only.

stop_recordingA

Stop the active screen recording and return the file path.

navigateA

Read or drive react-navigation (and Expo Router) from outside the app. stack reports the current navigation state — one line per nesting level with the focused route marked. navigate/push go to a route by name (push always adds a new card, navigate reuses an existing one), back/pop/pop_to_top unwind it, reset replaces the whole state via resetRoot. Every mutating action reports the resulting stack. The navigation container ref is found by walking the React tree, so no app-side setup is needed; it is cached on globalThis.RNE_NAV until the next reload. An unknown route name comes back as react-navigation's own "was not handled by any navigator" message.

sample_cpuA

Profile the running app's threads for a few seconds and report which one is hot — the UI/main thread, the JS thread, or something else. iOS simulator: macOS sample, with native call-graph frames. Android: top -H, per-thread %CPU only (no frames).

get_fpsB

Measure frame timing for a short window. Android also reports real UI-thread frames from dumpsys gfxinfo; on the iOS simulator only the JS-thread requestAnimationFrame rate is available (UI-thread frames need a physical device and xctrace).

profile_rendersA

Count React re-renders over a window: which components rendered, how many times, how long they spent, and which update started each commit. Installs a switchable hook on the React DevTools global hook (dev builds only) that prunes untouched subtrees, so it costs roughly what the commits cost rather than what the tree costs. Nothing re-renders on its own — drive the app during the window, which usually means background: true plus tap/swipe, then get_job to collect.

profile_jsA

Record a Hermes CPU profile for duration_ms, then report where the JS thread spent its time: busy/idle/GC split, the functions with the most self time, and the ones with the most inclusive time (symbolicated through Metro when it can). The raw .cpuprofile is saved to disk and opens in Chrome DevTools → Performance → Load. Drive the app (or leave it alone) while this runs — the profile covers whatever happens during the window.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

B3.4/5.0

Scored across 35 tools

Disambiguation4/5

Most tools target distinct resources or actions, but several composite tools intentionally overlap with atomic tools: observe vs screenshot/get_layout/get_logs, check_state vs get_state/navigate, and run_flow vs tap/type_text/swipe/eval_js. Descriptions explicitly recommend the composite tools, which keeps selection mostly clear, though press_key 'back' and navigate 'back' also overlap.

Naming Consistency4/5

Names consistently use snake_case and are mostly verb-first (list_devices, get_logs, type_text, profile_js). Minor deviations are single-word operational verbs such as tap, swipe, connect, and navigate, plus the noun 'screenshot', but the overall convention remains readable.

Tool Count2/5

With 35 tools, the surface is well beyond a tightly scoped 3–15 range and past the 16–25 'heavy' bracket. Although the server spans many React Native debugging domains, the large number of atomic plus composite tools makes the selection surface excessive for an agent.

Completeness4/5

Coverage is broad: device/app management, targets, logs/errors/network, eval and background jobs, state/component tree, OCR/layout/tap/type/swipe, navigation/flows, recording, and performance profiling. Minor gaps remain around explicit app terminate/uninstall and standalone wait/assert helpers, but launch_app terminate_running and run_flow provide workarounds.

Maintenance

ActivityNo data
ResponsivenessSyncing