Skip to main content
Glama

easy-ui-mcp

A Dockerized MCP (Model Context Protocol) server for local UI testing. It exposes Playwright-based browser automation tools over HTTP/SSE so an AI agent (like Claude Code) can drive web UI flows step-by-step and get back a JSON + HTML report with screenshots — no server-side LLM, no test scripts to write.

Quick Start

docker compose up -d --build
curl http://localhost:8765/health
# {"status":"ok"}

Connect Claude Code:

claude mcp add --transport http easy-ui-mcp http://localhost:8765/mcp

Then ask Claude Code to navigate to a page and take a screenshot — it will call the tools below and report back.

Using this from another repo? MCP registration is per-project — run claude mcp add from that repo's root too (the container above only needs to run once, shared across repos). See AGENTS.md → Using easy-ui-mcp From Another Repo for the full required steps.

Related MCP server: Playwright MCP Server

Networking

The container runs with network_mode: host in docker-compose.yml (not a published port on a bridge network). This is required, not optional: the browser Playwright drives inside this container needs to reach localhost:<port> on your host machine, where the target app's dev server (the repo you're testing) is actually running. A default bridge network gives the container its own isolated network namespace with no route back to the host at all — target URLs like http://localhost:8766 will hang or fail with ERR_CONNECTION_REFUSED, and http://<host-LAN-IP>:8766 will just time out, even if the target server is listening and reachable via curl from the host shell.

If you fork/redeploy this container anywhere network_mode: host isn't available (e.g. Docker Desktop on macOS/Windows, where host networking support is limited or absent), use host.docker.internal as the target hostname instead of localhost when calling ui_navigate, and add a network_mode: host fallback of extra_hosts: ["host.docker.internal:host-gateway"] to docker-compose.yml.

Tools

ui_start_session, ui_end_session, ui_step, ui_navigate, ui_click, ui_fill, ui_assert, ui_check, ui_wait_for, ui_get_page_state, ui_take_screenshot — plus a REST wrapper at POST /api/run-test for non-MCP callers.

Label your steps

ui_step(label) groups everything that follows it under a plain-language heading, until the next ui_step. The label is the report's only caller-authored statement of intent. The server uses deterministic templates such as “Opened …”, “Clicked …”, and “Filled …” for individual actions—no LLM runs inside the container—so an unlabelled session still renders readable action descriptions under one implicit group.

ui_start_session  target: "Account Access toggle smoke"
ui_step           label:  "Open the Settings page"
ui_navigate       ...
ui_wait_for       ...
ui_step           label:  "Turn Manual Invoice access on"
ui_click          ...
ui_assert         ...
ui_end_session

Sessions with no ui_step calls still render correctly, under a single implicit group.

Verifying vs waiting — pick the right one

A session is marked failed if any hard action fails, so how you verify decides whether the report tells the truth.

Tool

Condition false means

Use it for

ui_assert

The session fails.

A claim about the app: "the toggle is now on"

ui_check

Recorded and shown, run continues

An observation you want in the report but which should not condemn the run

ui_wait_for

Keeps polling; timing out fails the session

Waiting for the page to render or settle

Never call ui_assert in a retry loop to wait for something — the first false result permanently fails the run even if the app is fine. That is what ui_wait_for is for.

For both ui_check and ui_wait_for, a condition that cannot run (no page open, or the expression throws) is always a hard failure: that is a harness error, not an observation.

Auto-failure screenshots are budgeted per session (FAILURE_SCREENSHOT_BUDGET, default 3). Identical screenshot content is embedded in the HTML report only once.

What the report shows

A verdict box (status, target, step/action/failure counts, duration), then the run as labelled steps with per-step outcomes and elapsed time, then any browser problems, and finally the raw action log collapsed behind a disclosure.

Console errors, uncaught page errors, and network-level request failures are captured automatically and listed under Browser problems — a flow that passes while the console throws is a false green worth seeing. HTTP error responses such as 404 or 500 do not trigger Playwright's requestfailed event and are not listed automatically. Captured problems are informational and never change the verdict. Up to 50 are retained per session; past that the report says the rest were dropped.

See AGENTS.md for the architecture and full MCP connection guide, and HARNESS.md for the REST API reference. Deploy/rollback procedures are in RUNBOOK.md.

Scope (v1)

Web only (Chromium), local only, no mobile support yet. See PRD.md for full product intent and PROJECT_SPEC.md for architecture decisions.

A
license - permissive license
Not graded
quality - not tested
B
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.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • AI-powered browser automation — navigate, click, fill forms, and extract data from any website.

  • Browser-backed QA with evidence and fix-ready reports for coding agents.

  • AI QA tester — real browsers scan sites for bugs, SEO, perf, and accessibility issues via chat.

View all MCP Connectors

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/thunderkds/easy-ui-mcp'

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