reins
Supports Expo/React Native apps on Android emulators and USB devices via adb reverse for bridge connectivity, and uses adb to capture screen snapshots.
Provides Expo/React Native glue such as connectExpo, hooks, and <ReinsPanel> to pair Expo apps with the bridge, expose actions and state, and capture panel snapshots.
Provides a Metro config wrapper for Expo and React Native apps to integrate reins into the bundler and enable app pairing and debugging.
Provides a Next.js config wrapper and token route handler to wire reins into Next.js apps, including Webpack/Turbopack support and dev-only pairing.
Provides React hooks and a <ReinsPanel> component so agents can run registered actions, read app state, and snapshot specific panels in React web apps.
Provides a Redux state adapter so agents can read redacted snapshots of a Redux store through the reins state tool.
Provides a Vite plugin that serves the pairing token in development and swaps reins for a production stub, enabling agent-driven inspection and debugging of Vite apps.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
reins
Give coding agents the reins: a tiny dev-only library and agent skill to drive, inspect and debug your web and Expo apps. Built for Lucid Coding, and the companion to Coordinator (mindmakr/coordinator).
Live site & docs → mindmakr.github.io/reins
An AI coding agent that tests your app usually clicks by pixels and guesses what happened. reins lets the app tell the agent what it can do and what state it is in. You register a few named actions ("log in as the tester", "switch to Arabic"), point at some state, and mark the panels worth looking at. The agent then calls those actions, reads the state, sees recent network calls and errors, and takes pixel-exact pictures of a panel. All of it goes through an MCP server on your machine.
reins is for development and test builds. Production builds swap it for an empty stub, and reins verify fails the build if any reins code is left.
One package (
npm i -D reins) includes the core, React & Expo hooks, Vite/Next/Metro plugins, the MCP bridge (npx reins bridge) and the bundle verifier (npx reins verify).The browser/RN core (
reins) is under 5 KB min+gzip and has zero browser runtime dependencies.Agent skill included: install the Claude Code plugin (or skill folder) and run
/reins:setup—your agent inspects your repo and wires everything for you.Inert until paired: it does nothing until it pairs with the bridge on your machine using a one-time token.
Let your agent set it up (/reins:setup)
In Claude Code, install the reins plugin:
/plugin install reins --marketplace mindmakr/reinsOr in two steps:
/plugin marketplace add mindmakr/reins
/plugin install reins@reinsThen in any new or existing Vite, Next.js, React or Expo project:
/reins:setup— inspects your project, installsreins, wiresreins/vite,reins/nextorreins/metro, adds dev-onlyreins.connect(), hooks up state adapters and high-value actions, wraps key screens in<ReinsPanel>, addsreins verifyto your build script, and configures.mcp.json./reins:drive— drives your paired app through the 7 MCP tools (reins_list_actions,reins_run_action,reins_state,reins_network,reins_errors,reins_panel_box,reins_snap)./reins:verify— runs your production build and verifies zeroreinsdev code shipped.
In OpenAI Codex CLI, Cursor or Antigravity: copy skills/reins/ into .agents/skills/ (or ~/.gemini/config/skills/) and ask the agent to follow the reins skill.
Related MCP server: browser-testbench
What's in reins
Everything ships in the single reins package (and the workspace packages @reins/* remain available if you prefer separate packages):
Import / CLI | What it does |
| The core (< 5 KB min+gzip, 0 browser deps): actions, state, network and error buffers, panels, WebMCP. |
|
|
| React Native glue: |
|
|
| Vite plugin: serves |
|
|
|
|
| The localhost ( |
| Fails if |
Five-minute setup (by hand)
Vite + React
npm i -D reinsvite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import reins from 'reins/vite';
export default defineConfig({ plugins: [reins(), react()] });src/main.tsx:
import { reins } from 'reins';
import { zustand } from 'reins/adapters';
import { useAppStore } from './store';
if (import.meta.env.DEV) {
reins.state('app', zustand(useAppStore));
reins.connect(); // fetches the token from /__reins/token, then pairs
}In a component:
import { useReinsAction, ReinsPanel } from 'reins/react';
export function Settings() {
const { setLocale } = useI18n();
useReinsAction({
name: 'set-locale',
description: 'Switch the UI language',
input: { type: 'object', properties: { locale: { type: 'string', enum: ['en', 'ar', 'fr'] } }, required: ['locale'] },
run: ({ locale }) => setLocale(locale),
});
return <ReinsPanel id="settings">…</ReinsPanel>;
}Add the check to your build script: "build": "vite build && reins verify dist".
Next.js (App Router)
npm i -D reinsnext.config.mjs:
import { withReins } from 'reins/next';
export default withReins({ /* your config */ });app/api/reins-token/route.ts:
export { GET } from 'reins/next/token-route';
export const dynamic = 'force-dynamic';A client component mounted once, for example in your root layout:
'use client';
import { useEffect } from 'react';
import { reins } from 'reins';
export function Reins() {
useEffect(() => {
if (process.env.NODE_ENV !== 'production') reins.connect({ tokenUrl: '/api/reins-token' });
}, []);
return null;
}Check the output: "build": "next build && reins verify .next/static".
Expo
npx expo install reinsmetro.config.js:
const { getDefaultConfig } = require('expo/metro-config');
const { withReins } = require('reins/metro');
module.exports = withReins(getDefaultConfig(__dirname));App.tsx:
import { connectExpo, ReinsPanel, useReinsAction } from 'reins/expo';
if (__DEV__) connectExpo();
export default function App() {
useReinsAction({ name: 'open-cart', description: 'Open the cart screen', run: () => navigation.navigate('Cart') });
return <ReinsPanel id="home">…</ReinsPanel>;
}The bridge only listens on 127.0.0.1. The iOS simulator shares your machine's loopback, so that just works. For an Android emulator or a USB device, run adb reverse tcp:7357 tcp:7357. Phones on Wi-Fi cannot reach the bridge, on purpose.
Check the export: npx expo export && npx reins verify dist.
reins/metro loads ESM with require, which needs Node 20.19 or newer, or 22.12 or newer. Metro must have package exports turned on, which is the default from Expo SDK 53.
Run the bridge and connect your agent
Add reins as an MCP server in your agent. For example, in .mcp.json (Claude Code) or your agent's MCP settings:
{
"mcpServers": {
"reins": { "command": "npx", "args": ["reins", "bridge"] }
}
}The agent starts the bridge for you. You can also start it yourself with npx reins bridge --no-mcp to watch it. The bridge writes a fresh token to .reins/token. Your dev server serves that file to the page, and the page pairs.
Options: --port, --dir, --origin <exact origin> (extra allowed page origins), --cdp <url> (for reins_snap in a browser), --no-rotate, --no-mcp, --browser-only.
How an agent uses it
Tool | What it returns |
| The paired app, its actions with input schemas, state sources and panels. Call this first. |
| Runs one action: |
| A redacted snapshot of one state source or all of them. |
| Recent fetch and XHR calls: method, URL, status, time, redacted headers and bodies. |
| Recent console errors, uncaught errors and unhandled rejections. |
| A panel's box in CSS pixels, with |
| A pixel-exact PNG of a panel under |
A typical loop: list actions, run login-as-tester, run set-locale with ar, check reins_errors is empty, then reins_snap the checkout panel and compare it with the design.
reins_snap in a browser uses Playwright, if it is installed, over the Chrome DevTools Protocol. Start Chrome with --remote-debugging-port=9222 and the bridge with --cdp http://127.0.0.1:9222. On Android it captures the screen with adb and returns the panel's box in device pixels. Otherwise it returns the box, so the agent's own browser tool can clip a screenshot to it.
People get the same handle in DevTools once the page is paired: __reins__.actions(), __reins__.run('set-locale', { locale: 'ar' }), __reins__.state(), __reins__.network(). Each action run shows as a collapsed console group and a performance.measure entry in the Performance panel.
If the browser supports WebMCP (navigator.modelContext or document.modelContext), reins also registers each action as a WebMCP tool. Read-only actions get readOnlyHint. Consequential ones get destructiveHint and a required confirm input.
State adapters
import { reins } from 'reins';
import { zustand, redux, reactQuery, routerLocation } from 'reins/adapters';
reins.state('cart', zustand(useCartStore));
reins.state('store', redux(store));
reins.state('queries', reactQuery(queryClient));
reins.state('route', routerLocation()); // or routerLocation(() => router.state.location)
reins.state('anything', () => ({ step, total }));Pairing also adds location, localStorage, sessionStorage and cookies. Storage and cookies list key names only. Their values are redacted unless allowlisted.
Companion: Coordinator (Lucid Coding)
Coordinator (mindmakr/coordinator) asks every open question up front, agrees a testable bar, and runs multi-step work through isolated builders and independent blind critics until the bar is met.
reins is built to be Coordinator's hands and eyes inside your app:
Builders wire features along with
useReinsAction,reins.stateand<ReinsPanel id>.Blind visual & code critics (who never see the builder's reasoning) use
reins_run_actionto switch locales (en,arRTL) and themes, checkreins_state,reins_networkandreins_errors, and attachreins_snapPNGs as durable proof on the Coordinator run dashboard.
Install both in Claude Code:
/plugin install coordinator --marketplace mindmakr/coordinator
/plugin install reins --marketplace mindmakr/reinsRead the Lucid Coding Manifesto.
Security model
reins gives an agent real control of a running app, so the limits are enforced in code and covered by tests:
Kept out of production. The core only turns on when
__DEV__,import.meta.env.DEVorNODE_ENV !== 'production'says it is a dev build. The Vite, Next and Metro plugins swapreinsfor an empty stub in production builds. The core carries the marker__REINS_DEV_ONLY__, andreins verify(reins-verify-bundle) fails your build if it finds it. A staging build keeps reins only when built withREINS_ENABLE=1.Off until paired. Until the bridge accepts its token, the core adds no listeners and patches nothing. The bridge makes a random 192-bit token, writes it to
.reins/token(with its own.gitignore) and renews it after each pairing. It listens on127.0.0.1only, which cannot be changed. It rejects WebSocket origins that are not localhost or on your--originlist. Clients with no Origin, like React Native, still need the token, and--browser-onlyrefuses them.Redacted by default. Request and response bodies,
Authorization,CookieandSet-Cookieheaders, storage values, cookie values, sensitive query values and sensitive state keys (token, password, secret, session and so on) are replaced with[redacted]. Allowlist keys withreins.connect({ allow: { headers, bodyKeys, storageKeys, cookies, queryKeys, stateKeys } }). httpOnly cookies cannot be read by page code at all.Consequential actions need confirmation. An action marked
consequential: trueis refused unless the call saysconfirm: true.Everything is logged. Every call shows in the browser console. The bridge appends every agent call, pairing, refusal and DevTools or WebMCP call to
.reins/audit.log, with arguments redacted.Lazy.
connect()waits forloadand an idle moment before it does anything.No eval. Only actions the app registered can run.
See SECURITY.md for what reins does not protect against and how to report a problem.
Prior art and how reins differs
Playwright MCP drives a browser from the outside through the accessibility tree. reins works from inside the app: the agent calls the app's own named actions and reads its real state. They work well together, and
reins_snapcan use Playwright to take its pictures.Chrome DevTools MCP gives an agent DevTools: network, console, performance and screenshots. It sees everything, unredacted, and it knows nothing about your app's own flows. reins exposes only what the app chooses to, redacted, and it also works in React Native.
WebMCP is a proposed browser API for pages to offer tools to agents. reins registers its actions there when the browser supports it, and it also reaches agents that are not in the browser through the bridge.
React DevTools shows a person the component tree and its state. reins gives an agent a small, stable interface chosen by the app instead of the whole tree.
Contributing
See CONTRIBUTING.md. For coding agents adding reins to an app, see AGENTS.md and skills/reins/SKILL.md.
Licence
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Hosted browser for agents: open pages, search the web, extract data, read PDFs and take screenshots.
Give AI agents a real cloud Chrome: open sessions, navigate, read pages, click, type and screenshot.
Control a real browser from AI agents: navigate, click, type, screenshot, read the page.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI coding agents to visually interact with frontend apps by taking screenshots, clicking elements, reading console logs, and performing visual diffs.7 npm3MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to remotely control, debug, and automate real browsers, iOS simulators, and Android emulators, including navigation, element inspection, interaction, screenshots, and mobile gestures.27 npmMIT
- AlicenseAqualityBmaintenanceEnables agents to inspect and drive Electron or Chrome/Chromium apps via the Chrome DevTools Protocol, exposing DOM snapshots, console logs, network requests, and gated interactions like clicking, typing, and navigating.6110 npm1MIT
- AlicenseAqualityCmaintenanceEnables AI coding agents to open and exercise web applications in an isolated Chromium browser, capture screenshots and runtime/network diagnostics, and run deterministic page checks with linked evidence.121MIT