Skip to main content
Glama
mcpland
by mcpland

Testing MCP

Node CI npm license

Write complex integration tests with AI - AI assistants see your live page structure, execute code, and iterate until tests work

Table of Contents

Related MCP server: Web Inspector MCP

Quick Start

Step 1: Install

npm install -D testing-mcp

Step 2: Configure Model Context Protocol (MCP) server (e.g., in Claude Desktop config):

{
  "testing-mcp": {
    "command": "npx",
    "args": ["-y", "testing-mcp@latest"]
  }
}

Step 3: Connect from your test:

import { render, screen, fireEvent } from "@testing-library/react";
import { connect } from "testing-mcp";

it("your test", async () => {
  render(<YourComponent />);
  await connect({
    context: { screen, fireEvent },
  });
}, 600000); // 10 minute timeout for AI interaction

Step 4: Run with MCP enabled:

Prompt:

Please run the persistent test in the `examples/react-jest` directory:

`TESTING_MCP=true RTL_SKIP_AUTO_CLEANUP=true npm test test/App.test.tsx`

Then, use the `testing-mcp` tool to write the test by following these steps:

1. Click the button displaying "count is 0".
2. Verify that the button text changes to "count is 1".
3. Write the test code to a file.

Now your AI assistant can see the page structure, execute code in the test, and help you write assertions.

Why Testing MCP

Traditional test writing is slow and frustrating:

  • Write → Run → Read errors → Guess → Repeat - endless debugging cycles

  • Add console.log statements manually - slow feedback loop

  • AI assistants can't see your test state - you must describe everything

  • Must manually explain available APIs - AI generates invalid code

Testing MCP solves this by giving AI assistants live access to your test environment:

  • AI sees actual page structure (DOM), console logs, and rendered output

  • AI executes code directly in tests without editing files

  • AI knows exactly which testing APIs are available (screen, fireEvent, etc.)

  • You iterate faster with real-time feedback instead of blind guessing

What Testing MCP Does

šŸ” Real-Time Test Inspection

View live page structure snapshots, console logs, and test metadata through MCP tools. No more adding temporary console.log statements or running tests repeatedly.

šŸŽÆ Remote Code Execution

Execute JavaScript/TypeScript directly in your running test environment. Test interactions, check page state, or run assertions without modifying test files.

🧠 Smart Context Awareness

Automatically collects and exposes available testing APIs (like screen, fireEvent, waitFor) with type information and descriptions. AI assistants know exactly what's available and generate valid code on the first try.

await connect({
  context: { screen, fireEvent, waitFor },
  contextDescriptions: {
    screen: "React Testing Library screen with query methods",
    fireEvent: "Function to trigger DOM events",
  },
});

šŸ”„ Session Management

Reliable WebSocket connections with session tracking, reconnection support, and automatic cleanup. Multiple tests can connect simultaneously.

🚫 Zero CI Overhead

Automatically disabled in continuous integration (CI) environments. The connect() call becomes a no-op when TESTING_MCP is not set(particularly utilised hooks), so your tests run normally in production.

šŸ¤– AI-First Design

Built specifically for AI assistants and the Model Context Protocol. Provides structured metadata, clear tool descriptions, and predictable responses optimized for AI understanding.

šŸ”€ Multi-Client Support

Run multiple MCP clients simultaneously (Claude Desktop, Cursor, VS Code, etc.) without port conflicts. The daemon architecture automatically manages connections and port allocation.

Installation

Install dependencies and build the project before launching the MCP server or consuming the client helper.

npm install -D testing-mcp
# or
yarn add -D testing-mcp
# or
pnpm add -D testing-mcp

Node 18+ is required because the project uses ES modules and the WebSocket API.

Configure MCP Server

Add the MCP server to your AI assistant's configuration (e.g., Claude Desktop, VSCode, etc.):

{
  "testing-mcp": {
    "command": "npx",
    "args": ["-y", "testing-mcp@latest"]
  }
}

The server automatically discovers and connects to the bridge daemon, which manages WebSocket connections on dynamically assigned ports.

Connect From Tests

Import the client helper in your Jest or Vitest suites hook to expose the page state to the MCP server.

Example Jest setup file(setupFilesAfterEnv)

// jest.setup.ts
import { screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { connect } from "testing-mcp";

const timeout = 10 * 60 * 1000;

if (process.env.TESTING_MCP) {
  jest.setTimeout(timeout);
}

afterEach(async () => {
  if (!process.env.TESTING_MCP) return;
  const state = expect.getState();
  await connect({
    filePath: state.testPath,
    context: {
      userEvent,
      screen,
      fireEvent,
    },
  });
}, timeout);

It also supports usage in test files:

// example.test.tsx
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { connect } from "testing-mcp";

it(
  "logs the dashboard state",
  async () => {
    render(<Dashboard />);
    await connect({
      filePath: import.meta.url,
      context: {
        screen,
        fireEvent,
        userEvent,
        waitFor,
      },
      // Optional: provide descriptions to help LLMs understand the APIs
      contextDescriptions: {
        screen: "React Testing Library screen with query methods",
        fireEvent: "Synchronous event triggering function",
        userEvent: "User interaction simulation library",
        waitFor: "Async utility for waiting on conditions",
      },
    });
  },
  1000 * 60 * 10
);

Set TESTING_MCP=true locally to enable the bridge. The helper no-ops when the variable is missing or the tests run in continuous integration.

If the DOM has been automatically cleared after the afterEach hook executes, please set RTL_SKIP_AUTO_CLEANUP=true.

MCP Tools

Once connected, your AI assistant can use these tools:

Tool

Purpose

When to Use

get_current_test_state

Fetch current page structure, console logs, and APIs

Inspect what's rendered and what APIs are available

execute_test_step

Run JavaScript/TypeScript code in the test environment

Trigger interactions, check state, run assertions

finalize_test

Remove connect() call and clean up test file

After test is complete and working

list_active_tests

Show all connected tests with timestamps

See which tests are available

get_generated_code

Extract code blocks inserted by the helper

Audit what code was added

get_current_test_state

Returns the current test state including:

  • Page structure snapshot: Current rendered HTML (DOM)

  • Console logs: Captured console output

  • Test metadata: Test file path, test name, session ID

  • Available context: List of all APIs/variables available in execute_test_step, including their types, signatures, and descriptions

Response includes availableContext field:

{
  "availableContext": [
    {
      "name": "screen",
      "type": "object",
      "description": "React Testing Library screen object"
    },
    {
      "name": "fireEvent",
      "type": "function",
      "signature": "(element, event) => ...",
      "description": "Function to trigger DOM events"
    }
  ]
}

execute_test_step

Executes JavaScript/TypeScript code in the connected test client. The code can use any APIs listed in the availableContext field from get_current_test_state.

Best Practice: Always call get_current_test_state first to check which APIs are available before using execute_test_step.

Context and Available APIs

Inject testing utilities so AI knows what's available:

The connect() function accepts a context object that exposes APIs to the test execution environment. This allows AI assistants to know exactly what APIs are available when generating code.

Basic Usage

await connect({
  context: {
    screen, // React Testing Library queries
    fireEvent, // DOM event triggering
    userEvent, // User interaction simulation
    waitFor, // Async waiting utility
  },
});

Provide descriptions for each context key to help AI understand what's available:

await connect({
  context: {
    screen,
    fireEvent,
    waitFor,
    customHelper: async (text: string) => {
      const button = screen.getByText(text);
      fireEvent.click(button);
      await waitFor(() => {});
    },
  },
  contextDescriptions: {
    screen: "Query methods like getByText, findByRole, etc.",
    fireEvent: "Trigger DOM events: click, change, etc.",
    waitFor: "Wait for assertions: waitFor(() => expect(...).toBe(...))",
    customHelper: "async (text: string) => void - Clicks button by text",
  },
});

How it works: The client collects metadata (name, type, function signature) for each context key. When AI calls get_current_test_state, it receives the full list of available APIs with their metadata, enabling accurate code generation.

Multi-Client Architecture

Testing MCP v0.4.0 introduces a Daemon + Adapter architecture that allows multiple MCP clients to work simultaneously without port conflicts.

How It Works

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  MCP Client A (Claude Desktop)                                  │
│         ↓                                                       │
│  testing-mcp serve (Adapter A) ──┐                              │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
                                   │
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  MCP Client B (Cursor)                                          │
│         ↓                                                       │
│  testing-mcp serve (Adapter B) ──┼── RPC ──→ Bridge Daemon      │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
                                   │          (Single Instance)
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
│  MCP Client C (VS Code)                                         │
│         ↓                                                       │
│  testing-mcp serve (Adapter C) ā”€ā”€ā”˜               │              │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
                                                   ↓
                                         ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
                                         │  Test Client            │
                                         │  await connect()        │
                                         │  (Auto-discovers port)  │
                                         ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Components

Component

Description

Bridge Daemon

Single background process that manages WebSocket connections from tests. Automatically assigns ports.

MCP Adapter

Lightweight stdio MCP server that each client spawns. Communicates with daemon via RPC.

Registry File

~/.testing-mcp/bridge.json - Contains daemon port and auth token for auto-discovery.

Auto-Discovery

Test clients automatically discover the daemon's WebSocket port by reading the registry file. No manual port configuration required:

// Port auto-discovered from ~/.testing-mcp/bridge.json
await connect({
  context: { screen, fireEvent },
});

Manual Daemon Management (Optional)

The daemon starts automatically when needed. For manual control:

# Start daemon manually
testing-mcp bridge

# Check daemon status
testing-mcp bridge status

# Diagnose daemon registry and connectivity
testing-mcp bridge doctor --json

# Stop daemon
testing-mcp bridge stop

CLI Commands

testing-mcp [command] [options]

Commands:
  serve          Run as MCP adapter via stdio (default)
  bridge         Start the bridge daemon
  bridge stop    Stop the running daemon
  bridge status  Show daemon status
  bridge doctor  Diagnose daemon registry and connectivity

Options:
  --help, -h     Show this help message
  --version, -v  Show version number

Examples

# Run as MCP server (for MCP client configuration)
testing-mcp

# Start the bridge daemon (for multi-client support)
testing-mcp bridge

# Check daemon status
testing-mcp bridge status
# Output:
# Status: Running
#   PID:           12345
#   WebSocket:     ws://127.0.0.1:53718
#   RPC:           ws://127.0.0.1:53719
#   Version:       0.5.2
#   Uptime:        5m 32s
#   Connections:   2

# Diagnose daemon health without printing secrets
testing-mcp bridge doctor --json

# Stop the daemon
testing-mcp bridge stop

Environment Variables

  • TESTING_MCP: When set to true, enables the WebSocket bridge to the MCP server. Leave unset to disable (automatically disabled in CI environments).

  • TESTING_MCP_PORT: Overrides the WebSocket port for test clients. In most cases, this is not needed as ports are auto-discovered from the daemon registry.

  • TESTING_MCP_TOKEN: Authentication token to use with an explicit TESTING_MCP_PORT or connect({ port }) override.

  • TESTING_MCP_DATA_DIR: Overrides the daemon registry directory. Use this to isolate multiple workspaces or exploratory testing sessions.

Port Resolution Priority

The connect() function resolves the WebSocket port in this order:

  1. Explicit port option: connect({ port: 3001 })

  2. Environment variable: TESTING_MCP_PORT=3001

  3. Registry file: Auto-discovered from ~/.testing-mcp/bridge.json

  4. Default fallback: 3001

FAQ

1. How do I view MCP errors?

If you see that testing-mcp fails to start in Cursor IDE, you can check detailed logs:

In Cursor IDE: Go to Output > MCP:user-testing-mcp to see detailed error information.

This will show you the exact error messages and help diagnose startup issues.

2. What if the port is already in use?

With the new daemon architecture (v0.4.0+), port conflicts are automatically resolved. The daemon uses dynamic port allocation (port=0), so it always finds an available port.

If you're using an older version or manual port configuration:

  1. Upgrade to v0.4.0+ for automatic port management

  2. Or kill the process using the port:

# macOS/Linux
lsof -ti:3001 | xargs kill -9

3. Can I run multiple MCP clients simultaneously?

Yes! The daemon architecture (v0.4.0+) supports multiple MCP clients:

  • Claude Desktop, Cursor, VS Code can all connect at the same time

  • Each adapter connects to the shared daemon via RPC

  • No port conflicts - the daemon handles all connections

4. Why shouldn't I use watch mode?

Testing MCP currently supports only one WebSocket connection per test at a time.

When your MCP client runs the same test command multiple times (like in watch mode), each run creates a new WebSocket connection. This can cause conflicts and unexpected behavior.

Recommendation: Run tests individually without watch mode when using TESTING_MCP=true.

5. My tests timeout immediately - what's wrong?

If tests with TESTING_MCP=true timeout quickly, you need to increase the test timeout.

AI assistants need time to inspect state and write tests - usually 5+ minutes minimum.

Set timeout in your test:

it("your test", async () => {
  render(<YourComponent />);
  await connect({ context: { screen, fireEvent } });
}, 600000); // 10 minutes = 600000ms

6. Can I put connect() in a test setup file instead of each test?

Yes, if your tests don't automatically clear the DOM between tests.

By placing connect() in an afterEach hook in your setup file, you can make testing completely non-invasive and easier for automated test writing.

Example Jest setup file(setupFilesAfterEnv)

// jest.setup.ts
import { screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { connect } from "testing-mcp";

const timeout = 10 * 60 * 1000;

if (process.env.TESTING_MCP) {
  jest.setTimeout(timeout);
}

afterEach(async () => {
  if (!process.env.TESTING_MCP) return;
  const state = expect.getState();
  await connect({
    filePath: state.testPath,
    context: {
      userEvent,
      screen,
      fireEvent,
    },
  });
}, timeout);

Example Vitest setup file(setupFiles):

// vitest.setup.ts
import { beforeEach, afterEach, expect } from "vitest";
import { screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { connect } from "testing-mcp";

const timeout = 10 * 60 * 1000;

beforeEach((context) => {
  if (!process.env.TESTING_MCP) return;
  Object.assign(context.task, {
    timeout,
  });
});

afterEach(async () => {
  if (!process.env.TESTING_MCP) return;
  const state = expect.getState();
  await connect({
    filePath: state.testPath,
    context: {
      userEvent,
      screen,
      expect,
      fireEvent,
    },
  });
}, timeout);

Important: This approach only works if your afterEach hooks don't automatically remove the DOM (e.g., you're not calling cleanup() before connect()).

7. Where is the daemon registry file located?

The registry file stores daemon connection info for auto-discovery:

Platform

Path

macOS/Linux

~/.testing-mcp/bridge.json

Windows

%LOCALAPPDATA%\testing-mcp\bridge.json

Set TESTING_MCP_DATA_DIR=/path/to/session/.testing-mcp to place the registry and lock file in a session-scoped directory.

Example registry content:

{
  "pid": 12345,
  "wsPort": 53718,
  "rpcPort": 53719,
  "token": "abc123...",
  "startedAt": "2024-01-15T10:30:00.000Z",
  "version": "0.5.2",
  "protocol": 1
}

How It Works

Testing MCP uses a Daemon + Adapter architecture for robust multi-client support:

Architecture Overview

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”         ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”         ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│  Node.js Test    │         │  Bridge Daemon   │         │   LLM/MCP        │
│    Process       │         │    (Singleton)   │         │     Client       │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜         ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜         ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
         │                            │                            │
         │                            │         ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
         │                            │         │  MCP Adapter     │
         │                            │◄────────┤  (per client)    │
         │                            │   RPC   ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
         │                            │                            │
         │  1. await connect()        │                            │
         ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”‚                            │
         │   (Auto-discovers port)    │                            │
         │                            │                            │
         │  2. WebSocket: "ready"     │   3. MCP Tool Call         │
         │    {dom, logs, context}    │      (Stdio/JSON-RPC)      │
         ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”‚ā—„ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
         │                            │                            │
         │  4. "connected"            │   5. RPC: getCurrentState  │
         │    {sessionId}             │◄───────────────────────────┤
         │◄───────────────────────────┤                            │
         │                            │   6. Returns state         │
         │      Test waits...         ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”‚
         │                            │                            │
         │                            │   7. RPC: sendExecute      │
         │  8. "execute"              │◄───────────────────────────┤
         │    {code, executionId}     │                            │
         │◄───────────────────────────┤                            │
         │                            │                            │
         │  Runs code with context    │                            │
         │                            │                            │
         │  9. "executed"             │                            │
         │    {result, newState}      │   10. Returns result       │
         ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”‚
         │                            │                            │
         │                            │   11. finalize_test        │
         │  12. "close"               │◄───────────────────────────┤
         │◄───────────────────────────┤   (Adapter edits file)     │
         │                            │                            │
         │  Test completes            │   13. Returns success      │
         │                            ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”‚
         ā–¼                            ā–¼                            ā–¼

Key Components

Component

Responsibility

Bridge Daemon

Singleton process managing WebSocket connections, session state, and code execution

MCP Adapter

Per-client stdio MCP server that forwards tool calls to daemon via RPC

Registry File

Stores daemon port/token for auto-discovery by adapters and test clients

Test Client

connect() function that establishes WebSocket to daemon

Protocol Summary

Communication

Protocol

Purpose

Test ↔ Daemon

WebSocket

State sync, code execution

Adapter ↔ Daemon

WebSocket RPC

Tool call forwarding

Client ↔ Adapter

Stdio JSON-RPC

MCP protocol

Benefits of This Architecture

  1. No port conflicts: Daemon uses dynamic port allocation

  2. Multi-client support: Multiple AI assistants can connect simultaneously

  3. Auto-discovery: Test clients find daemon automatically via registry

  4. Graceful lifecycle: Daemon starts on-demand, can be managed manually

  5. Security: Token-based authentication between components

License

MIT

Available Tools

5 tools
execute_test_stepA

Execute code directly in the connected test client and get back the updated DOM state and console logs. IMPORTANT: Before using this tool, call get_current_test_state first to check the 'availableContext' field, which lists all available APIs/variables you can use in your code.

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYesThe JavaScript/TypeScript code to execute in the test environment. You can use any APIs/variables listed in the 'availableContext' field from get_current_test_state (e.g., screen, fireEvent, waitFor, userEvent, etc.). The code should only reference variables that are available in availableContext.
testFileNoOptional: specific test file (uses current if not provided)
testNameNoOptional: specific test name (uses current if not provided)

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses the return values (updated DOM state and console logs) and the dependency on availableContext, but it does not mention potential side effects of executing arbitrary code, error handling, or whether the tool requires specific permissions. This is moderate transparency for an execution tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured. The first sentence states the core action and outputs; the second sentence delivers a critical usage caution. No redundancy or filler, and the most important operational detail (checking availableContext) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a code execution tool with no output schema, the description summarizes key outputs (DOM state, console logs) and the essential prerequisite. It lacks detailed return formatting or failure behavior, but the provided context is sufficient for a competent agent to begin using the tool effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema provides 100% coverage, describing the code parameter and its dependency on availableContext, plus optional testFile and testName. The description adds little beyond the schema, only reiterating the availableContext requirement. Baseline 3 applies because the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'Execute code directly in the connected test client and get back the updated DOM state and console logs.' This is a specific verb+resource pairing that distinguishes it from siblings like get_current_test_state (which retrieves state) and finalize_test (which likely closes or completes a test).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides an explicit usage prerequisite: 'Before using this tool, call get_current_test_state first to check the availableContext field.' It gives clear context on when to use the tool and what to do first, though it does not explicitly contrast it with alternative tools or state when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

finalize_testB

Finalize the test by removing connect() call and optionally cleaning up markers

ParametersJSON Schema
NameRequiredDescriptionDefault
testFileYesPath to the test file
removeMarkersNoWhether to remove TESTING-MCP markers (default: true)

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are absent, so the description carries the full load. It discloses the core mutation (removing connect() call and markers) but does not explain consequences like file modification, reversibility, or side effects. This partial transparency earns a middle score.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence that is direct and front-loaded with the primary action. It contains no fluff or redundant repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no annotations, the description should explain what the tool returns, any prerequisites, or potential impacts. It only describes the action and omits post-invocation expectations, leaving the agent uncertain about the outcome. This is a notable gap for a mutation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers both parameters with clear descriptions, so the schema description coverage is 100%. The tool description adds no additional parameter-specific meaning beyond referencing marker cleanup, which is already in the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (finalize) and the specific operations (removing connect() call and optionally cleaning up markers). It distinguishes itself from sibling tools like execute_test_step and get_current_test_state by using the verb 'finalize' and specifying a concrete transformation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not provide explicit guidance on when to use this tool versus alternatives, nor does it mention any workflow context or exclusions. It implies finalization as an end step but lacks any comparison to sibling tools or prerequirements.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_current_test_stateA

Get the current state of a connected test, including DOM, snapshot, console logs, and available context APIs. The response includes 'availableContext' field which lists all APIs/variables that can be used in execute_test_step.

ParametersJSON Schema
NameRequiredDescriptionDefault
testFileNoOptional: specific test file path
testNameNoOptional: specific test name

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It provides useful detail on what the response includes (DOM, snapshot, console logs, availableContext), giving a sense of the tool's behavior. However, it does not mention error conditions, prerequisites beyond 'connected test', or whether the operation is read-only, leaving gaps in transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise: two sentences with no unnecessary wording. The first sentence clearly states the function and what it returns; the second highlights the critical availableContext field and its tie-in to execute_test_step.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema and annotations, the description does a good job covering the tool's purpose and key return fields. It explains the availableContext integration, which is important for using the tool effectively. Minor gaps remain around failure modes and exact response structure, but overall it is sufficient for the tool's moderate complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides 100% description coverage for both optional parameters (testFile, testName), so the baseline is 3. The tool description adds no additional meaning to the parameters, but that is acceptable given the schema already explains them.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with a specific verb and resource: 'Get the current state of a connected test.' It enumerates the included contents (DOM, snapshot, console logs, availableContext APIs), which distinguishes it from sibling tools like list_active_tests or execute_test_step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use case by noting the availableContext field is usable in execute_test_step, suggesting this tool is meant for inspecting state before executing steps. However, it does not explicitly state when to prefer this over alternatives or provide exclusions, leaving usage guidance somewhat implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_generated_codeB

Get all generated code blocks from a test file

ParametersJSON Schema
NameRequiredDescriptionDefault
testFileYesPath to the test file

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must disclose behavioral traits. It only states the action without mentioning read-only nature, return format, error handling, or side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence, front-loaded with the action and resource, with no redundant words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple getter with one parameter, the description gives the essential purpose but lacks details about return structure or usage context, which is needed since no output schema or annotations exist.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the parameter description is clear. The tool description adds no further semantic meaning but aligns with the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'get' and identifies the resource as 'generated code blocks' with the source 'test file', clearly distinguishing it from sibling tools that operate on test state or execution.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives. Sibling names suggest a test workflow but the description doesn't mention prerequisites, timing, or exclusion conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_active_testsA

List all currently connected test processes

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It clearly indicates a read-only listing operation ('List all currently connected test processes'), but it does not disclose return format, behavior when no processes are connected, or any potential side effects. It is adequate but minimal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no filler. It earns its place and is highly concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description should explain what the returned data looks like; it only says 'list' without specifying format or content. Also lacks usage guidance. For a simple listing tool it is acceptable but has identifiable gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema is fully descriptive by default. The description correctly avoids adding unnecessary parameter information. The baseline of 4 applies for a parameterless tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'List all currently connected test processes'. It clearly distinguishes from sibling tools like get_current_test_state, finalize_test, execute_test_step, and get_generated_code, which perform different actions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives. There is no mention of prerequisites, context, or situations where it is preferred. The description only states what it does, not when to invoke it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 5 tool updatesv0.5.2
    • First observedexecute_test_step
    • First observedfinalize_test
    • First observedget_current_test_state
    • First observedget_generated_code
    • First observedlist_active_tests

TDQS

A4/5.0
Disambiguation5/5

Each tool targets a clearly distinct action: inspecting state, executing a step, finalizing a test, listing active tests, and retrieving generated code. The only related tools are get_current_test_state and execute_test_step, but one is read-only while the other executes code, so there is no ambiguity.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: get_current_test_state, finalize_test, list_active_tests, get_generated_code, execute_test_step. The verbs and nouns are uniformly formatted with underscores.

Tool Count5/5

With 5 tools, the server is well-scoped for its testing purpose. Each tool is necessary and there is no bloat or overly sparse set.

Completeness5/5

The tool set covers the full testing workflow: listing active tests, inspecting state, executing steps, retrieving generated code, and finalizing. No obvious missing operations for the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to debug frontend applications by providing direct access to browser DevTools, React state, DOM inspection, and runtime debugging capabilities. Bridges the gap between AI and complex web applications for autonomous debugging and issue resolution.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI coding assistants to control and inspect a live Chrome browser through Chrome DevTools for automation, debugging, and performance analysis.
    3,288,165
    Apache 2.0

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/mcpland/testing-mcp'

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