MCP Servers

A collection of Model Context Protocol servers, templates, tools and more.

MCP server by Nizarius

Created 1/6/2026
Updated 2 days ago
Repository documentation and setup instructions

MCP Browser Server for React Native Web

npm version License: MIT

A Model Context Protocol (MCP) browser automation server specifically designed to work with React Native Web applications. Features multi-tab support, screenshot capabilities, and persistent browser sessions.

The Problem

React Native Web uses a gesture responder system that listens for mousedown/mouseup events instead of standard click events. This breaks standard browser automation tools like Playwright's locator.click() method.

The Solution

This MCP server uses coordinate-based clicks with Playwright's low-level page.mouse API, which properly triggers the mouse events that React Native Web components listen for.

Features

  • Coordinate-based clicking - Uses page.mouse.down() / page.mouse.up() instead of synthetic clicks
  • Multiple element finding strategies - CSS selector, text content, testID, or exact coordinates
  • Custom page snapshots - Shows interactive elements with positions (not reliant on accessibility tree)
  • Screenshot support - Returns base64-encoded PNG images that AI agents can view
  • Multi-tab management - Create, switch between, and close browser tabs
  • Persistent sessions - Browser stays open between tool calls for continuous interaction
  • Full browser control - Navigate, type, scroll, press keys, evaluate JavaScript

Installation

From npm

npm install @nizarius/mcp-rnw-browser
npx playwright install chromium

From source

git clone https://github.com/nizarius/mcp-rnw-browser.git
cd mcp-rnw-browser
npm install
npm run build
npx playwright install chromium

Configuration for Cursor

Add to your Cursor MCP settings (~/.cursor/mcp.json or Cursor Settings > MCP):

Using npm package (recommended)

{
  "mcpServers": {
    "rnw-browser": {
      "command": "npx",
      "args": ["@nizarius/mcp-rnw-browser"]
    }
  }
}

Using local installation

{
  "mcpServers": {
    "rnw-browser": {
      "command": "node",
      "args": ["/path/to/mcp-rnw-browser/dist/index.js"]
    }
  }
}

Available Tools

Navigation

rnw_navigate

Navigate to a URL. Creates a browser session if none exists.

{ "url": "http://localhost:8081" }

Returns: Page snapshot with all interactive elements.

Screenshots & Snapshots

rnw_snapshot

Get a text snapshot of interactive elements on the page with their positions. Returns element tags, text content, testIDs, roles, positions, and center coordinates for clicking.

// No parameters required
{}

Returns: Text list of all interactive elements with their positions.

rnw_screenshot

Take a screenshot and return as a base64-encoded PNG image.

// Viewport screenshot (default)
{}

// Full page screenshot (captures entire scrollable area)
{ "fullPage": true }

// Element screenshot (captures specific element)
{ "selector": "#my-component" }

Returns: Base64-encoded PNG image that AI agents can view directly.

Interactions

rnw_click

Click on an element using React Native Web compatible mouse events (mousedown/mouseup).

// By CSS selector
{ "selector": "button.submit", "findBy": "css" }

// By text content (partial match)
{ "selector": "Sign In", "findBy": "text" }

// By testID (data-testid attribute)
{ "selector": "login-button", "findBy": "testid" }

// By exact coordinates (useful when element detection fails)
{ "x": 500, "y": 300, "findBy": "coordinates" }

Returns: Click coordinates and updated page snapshot.

rnw_type

Type text into a focused element or find an element first and type into it.

// Type into currently focused element
{ "text": "Hello World" }

// Find element first, then type (clicks to focus)
{ "text": "Hello World", "selector": "input", "findBy": "css" }

// Type and press Enter (e.g., for search/submit)
{ "text": "Hello World", "selector": "input", "findBy": "css", "pressEnter": true }

Returns: Confirmation of typed text.

rnw_scroll

Scroll the page or a specific scrollable element.

// Scroll page down by 300 pixels
{ "direction": "down", "amount": 300 }

// Scroll page up
{ "direction": "up", "amount": 500 }

// Scroll within a specific container
{ "direction": "down", "amount": 200, "selector": ".scroll-container" }

Parameters: direction (up/down/left/right), amount (pixels, default: 300), selector (optional).

Returns: Updated page snapshot.

rnw_wait

Wait for a specified time or until an element appears on the page.

// Wait for 1 second (1000ms)
{ "time": 1000 }

// Wait for element to appear (with 5s timeout)
{ "selector": "button.loaded", "findBy": "css" }

// Wait for text to appear
{ "selector": "Loading complete", "findBy": "text" }

Returns: Confirmation when wait completes or error if timeout.

rnw_press_key

Press a keyboard key. Useful for navigation, form submission, or triggering shortcuts.

// Press Enter
{ "key": "Enter" }

// Press Escape
{ "key": "Escape" }

// Press arrow keys
{ "key": "ArrowDown" }

// Press Tab to move focus
{ "key": "Tab" }

Common keys: Enter, Escape, Tab, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Backspace, Delete, Space.

Returns: Confirmation of key pressed.

rnw_evaluate

Execute JavaScript in the browser context. Useful for debugging, reading state, or performing custom interactions.

// Get page title
{ "script": "document.title" }

// Get current URL
{ "script": "window.location.href" }

// Read localStorage value
{ "script": "localStorage.getItem('authToken')" }

// Get element count
{ "script": "document.querySelectorAll('button').length" }

// Trigger custom action
{ "script": "window.scrollTo(0, document.body.scrollHeight)" }

Returns: JSON-stringified result of the script execution.

Tab Management

rnw_tabs_list

List all open browser tabs with their index, title, and URL.

// No parameters required
{}

Returns: List of all tabs showing index, active status, title, and URL.

rnw_tabs_new

Create a new browser tab and optionally navigate to a URL. The new tab becomes the active tab.

// Create empty new tab (about:blank)
{}

// Create new tab and navigate to URL
{ "url": "http://localhost:8081/settings" }

Returns: New tab index and page snapshot.

rnw_tabs_select

Switch to a specific tab by index (0-based). Use rnw_tabs_list to see available tabs.

// Switch to second tab
{ "index": 1 }

// Switch to first tab
{ "index": 0 }

Returns: Snapshot of the selected tab's page.

rnw_tabs_close

Close a browser tab. If the closed tab was active, switches to the nearest remaining tab.

// Close current active tab
{}

// Close specific tab by index
{ "index": 2 }

Returns: Confirmation and snapshot of the new active tab.

Session Management

rnw_session_status

Get current browser session status. Useful for checking if a session is active before performing actions.

// No parameters required
{}

Returns:

  • isRunning: Whether browser is active
  • tabCount: Number of open tabs
  • currentTabIndex: Index of active tab
  • currentUrl: URL of active tab
  • viewport: Browser window dimensions (width x height)

rnw_close

Close the browser and end the session. All tabs are closed and resources are released.

// No parameters required
{}

Returns: Confirmation that browser session has ended.

How It Works

Standard Playwright Click (Doesn't work with RNW)

// This dispatches a synthetic 'click' event that RNW ignores
await element.click();

This MCP Server's Click (Works with RNW)

// This triggers real mousedown/mouseup events that RNW responds to
await page.mouse.move(x, y);
await page.mouse.down();
await page.mouse.up();

Example Usage with AI Agent

Agent: Let me navigate to your React Native Web app, take a screenshot, and click the login button.

> rnw_navigate { "url": "http://localhost:8081" }

Page loaded. I can see the following interactive elements:
[0] button testid="login-button"
    text: "Sign In"
    center: (640, 400)

> rnw_screenshot {}

[Returns PNG image of the page]

> rnw_click { "selector": "login-button", "findBy": "testid" }

Clicked at (640, 400). The login form is now visible.

> rnw_tabs_new { "url": "http://localhost:8081/settings" }

Created new tab [1] and navigated to settings page.

> rnw_tabs_list {}

Open Tabs (2):
[0] Home - http://localhost:8081/
[1] (active) Settings - http://localhost:8081/settings

Continuous Session Workflow

The browser session persists across tool calls, enabling:

  1. Multi-step interactions - Navigate, screenshot, interact, screenshot again
  2. Visual verification - Take screenshots to verify UI state after actions
  3. Multi-page workflows - Open multiple tabs for complex testing scenarios
  4. Debugging - Use rnw_evaluate to inspect page state
Agent: I'll test the multi-step form submission.

> rnw_navigate { "url": "http://localhost:8081/form" }
> rnw_screenshot {}  // Verify initial state
> rnw_type { "text": "John Doe", "selector": "[data-testid='name-input']", "findBy": "css" }
> rnw_screenshot {}  // Verify text entered
> rnw_click { "selector": "Submit", "findBy": "text" }
> rnw_screenshot {}  // Verify submission result
> rnw_close {}       // End session when done

Troubleshooting

Elements not found

  • Make sure your React Native Web components have testID props set
  • Use rnw_snapshot to see available elements
  • Try using text content with findBy: "text"

Clicks not registering

  • Ensure the element is visible and not covered by another element
  • Try increasing the delay with rnw_wait before clicking
  • Use coordinates directly if element finding fails

Screenshots not working

  • Ensure the browser session is active (rnw_session_status)
  • For element screenshots, verify the selector matches a visible element

Version History

v2.0.0

  • Added screenshot support with base64 image return
  • Added multi-tab management (list, new, select, close)
  • Added session status tool
  • Improved tool response format
  • Persistent browser sessions

v1.0.0

  • Initial release with RNW-compatible clicking
  • Basic navigation, snapshot, and interaction tools

License

MIT

Quick Setup
Installation guide for this server

Install Package (if required)

npx @modelcontextprotocol/server-mcp-rnw-browser

Cursor configuration (mcp.json)

{ "mcpServers": { "nizarius-mcp-rnw-browser": { "command": "npx", "args": [ "nizarius-mcp-rnw-browser" ] } } }