Playwright E2E MCP
Ejecuta, depura e inspecciona pruebas de extremo a extremo de Playwright desde cualquier agente de IA: resultados estructurados con diagnósticos de fallos archivo:línea, inspección de DOM en vivo, validación de selectores, diferencias visuales y diagnóstico de pruebas inestables.
Servidor MCP alojado
npx add-mcp 'https://playwright-e2e-mcp.vercel.app/api/mcp'Se instala en Claude Code, Codex, Cursor y más
Documentación
playwright-e2e-mcp
Un servidor MCP que permite a los agentes de IA ejecutar, depurar e inspeccionar pruebas end-to-end de Playwright — con resultados estructurados, diagnósticos de fallos accionables e inspección de DOM en vivo.
run-test ──▶ get-failure ──▶ inspect-page ──▶ validate-selector ──▶ fix ──▶ re-run
▲ │
└──────────────────────── list-tests ◀────────────────────────────────┘
En lugar de entregar al agente la salida cruda de Playwright, este servidor convierte cada ejecución en resultados procesables por máquina: estadísticas de aprobados/fallidos, mensajes por fallo con file:line, un tipo de fallo (aserción, tiempo de espera, cierre del navegador, error de sintaxis, servidor de desarrollo caído, disco lleno…), y una pista concreta de "cómo solucionarlo". Cuando una prueba falla porque un selector ya no coincide, el agente puede abrir la página en vivo en un navegador sin interfaz, ver el DOM real con selectores CSS únicos y validar el selector de reemplazo antes de volver a ejecutar.
Demo
Endpoint alojado — lo que un viaje de ida y vuelta de initialize + tools/list contra https://playwright-e2e-mcp.vercel.app/api/mcp devuelve para un cliente que envía el token de portador (sin uno, solo se listan list-tests y get-failure):

Una ejecución de prueba real — run-test servido a través de stdio por npx -y playwright-e2e-mcp contra el examples/sample-test.spec.ts incluido (salida real, sin editar):

Las imágenes se renderizan con node scripts/gen-demo-images.mjs: la tarjeta de ejecución de prueba es salida capturada real; la tarjeta de endpoint es una ilustración del listado autenticado.
Instalación
Funciona con Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Freebuff y cualquier otro cliente MCP — elige la ruta que mejor se adapte:
| Ruta | Cómo |
|---|---|
| npm (canónico, más rápido) | npx -y playwright-e2e-mcp |
| Registro MCP (los clientes que conocen el registro lo descubren automáticamente) | io.github.trajectiq-ai/E2E — listado |
| Cualquier cliente, sin necesidad de cuenta npm | npx -y github:trajectiq-ai/E2E#v0.1.2 (fija una etiqueta de versión) |
| Claude Desktop, sin configuración de Node | doble clic en la extensión .mcpb |
| Clientes solo remotos (conectores ChatGPT) | https://playwright-e2e-mcp.vercel.app/api/mcp |
Detalles y configuración por cliente: Instalación · Configuración del cliente MCP.
Herramientas
| Herramienta | Propósito |
|---|---|
run-test | Ejecutar pruebas de Playwright y devolver estadísticas, fallos, diagnósticos y pistas |
get-failure | Análisis profundo de un fallo: pila, esperado/real, instantánea del DOM en el fallo (del trace de Playwright), siguientes pasos |
inspect-page | Abrir una URL sin interfaz y devolver el DOM renderizado: selectores, visibilidad, cajas, texto, salida de consola, HTML |
list-tests | Listar pruebas disponibles (file, line, título completo, proyectos) con filtrado |
validate-selector | Comprobar un selector CSS contra una página en vivo: validez, número de coincidencias, ejemplos de coincidencias |
generate-e2e-test | Crear una prueba de Playwright a partir de una descripción usando los selectores reales del proyecto, descubiertos a partir de cambios recientes de archivos |
compare-visual-state | Regresión visual: captura de pantalla antes/después de un cambio e informe de qué se movió y cómo cambiaron los colores |
diagnose-flaky | Ejecutar una prueba fallida 2–10 veces con reintentos deshabilitados y devolver un veredicto de evidencia: CONSISTENTLY FAILING, FLAKY o NOT REPRODUCING |
run-test
| Argumento | Tipo | Descripción |
|---|---|---|
projectRoot | string | Directorio del proyecto dentro de la raíz configurada (predeterminado: directorio de trabajo del servidor) |
testFiles | string[] | Archivos/directorios relativos a la raíz; se admiten file:line. Omitir para ejecutar todo |
grep | string | Ejecutar solo pruebas cuyo título coincida con esta expresión regular |
browser | chromium | firefox | webkit | Proyecto de Playwright a ejecutar (coincidido contra los nombres de proyecto de la configuración) |
headed | boolean | Ventana de navegador visible |
timeoutMs | number | Límite de tiempo real duro para la ejecución (predeterminado 120000); todo el árbol de procesos se mata al superarlo y se devuelven resultados parciales |
testTimeoutMs | number | Tiempo de espera por prueba pasado a Playwright |
workers / retries | number | Se pasan a Playwright |
config | string | Ruta de playwright.config o índice basado en 1 cuando el proyecto tiene varios |
retryOnFailure | boolean | Reintentar automáticamente los fallos una vez antes de informarlos (predeterminado true; ignorado cuando retries está establecido) |
lastFailed | boolean | Solo volver a ejecutar pruebas que fallaron en la ejecución anterior (Playwright --last-failed) — el bucle rápido de corregir → re-ejecutar |
args | string[] | Banderas adicionales de Playwright de una lista permitida (--repeat-each=N, --max-failures=N, --update-snapshots, --shard=1/3, --trace=on, …); los valores van después de = y se verifican, y las banderas que toman una ruta, como --config o --output, se rechazan |
Manejo de inestabilidad: por defecto el servidor inyecta --retries=1 (a menos que la configuración ya establezca retries), por lo que una prueba que pasa en el reintento se informa como inestable, no fallida. Los traces se capturan automáticamente (--trace=retain-on-failure) para que get-failure pueda mostrar el DOM en el momento del fallo.
Ejemplo de resultado:
## Playwright run — ❌ FAILED
**Command:** `playwright test --config playwright.config.ts tests/checkout.spec.ts --reporter=json`
**duration 4.2s · exit 1 · config `playwright.config.ts`**
| passed | failed | flaky | skipped | duration |
| ---: | ---: | ---: | ---: | ---: |
| 0 | 1 | 0 | 0 | 1.1s |
### ❌ 1 failing test(s)
### 1 of 1. checkout.spec.ts › pays with card
**File:** `checkout.spec.ts:5` | **failed · server-unreachable**
### ⚠️ SERVER_NOT_RUNNING
Your app (dev server) does not appear to be reachable. Start it in another terminal
(e.g. npm run dev / npm start), keep it running, then retry — or configure `webServer`
in playwright.config.* so Playwright starts it automatically.
get-failure
| Argumento | Tipo | Descripción |
|---|---|---|
index | number | Índice de fallo basado en 1 de la última ejecución (predeterminado 1) |
projectRoot | string | Solo se usa al releer el informe almacenado |
Devuelve el mensaje/marco de código, esperado vs real, pila, tipo de fallo con un diagnóstico, la salida de consola de la prueba, la instantánea del DOM del trace de Playwright (más la acción fallida, su selector y el registro de acciones que llevaron a ella), las solicitudes de red que fallaron (4xx/5xx, endpoints muertos, sin respuesta — con método, URL, estado y tipo de recurso), los errores/advertencias de consola que la página registró antes del fallo, y pasos siguientes numerados (re-ejecutar esta prueba individual por file:line, modo con interfaz/depuración, validate-selector cuando el mensaje menciona un localizador, …).
inspect-page
| Argumento | Tipo | Descripción |
|---|---|---|
url | string | URL http(s) completa a abrir (obligatorio) |
projectRoot | string | Proyecto cuyo Playwright lanza el navegador |
selector | string | Inspeccionar coincidencias de este selector CSS en lugar de todo el DOM |
waitFor | string | Esperar un selector (CSS o text=…) antes de inspeccionar |
waitUntil | load | domcontentloaded | networkidle | Condición de espera de navegación |
includeHtml | boolean | Incluir el HTML renderizado (limitado) |
maxHtmlChars | number | Límite de HTML, predeterminado 20000 |
timeoutMs | number | Límite general, predeterminado 45000 |
Devuelve el selector CSS único de cada elemento, etiqueta, visibilidad, caja delimitadora, texto y atributos, más los mensajes de consola capturados (errores primero).
list-tests
| Argumento | Tipo | Descripción |
|---|---|---|
projectRoot | string | Directorio del proyecto |
config | string | Ruta de configuración o índice basado en 1 |
testDir | string | Restringir el escaneo a un directorio (debe permanecer dentro del proyecto) |
filter | string | Filtro de subcadena sin distinción de mayúsculas/minúsculas en file › title |
limit | number | Máximo de pruebas devueltas, predeterminado 500 |
Usa playwright test --list cuando Playwright funciona, y vuelve a un escaneo de código fuente (manteniendo la razón) cuando la instalación o un archivo de especificaciones está roto.
validate-selector
| Argumento | Tipo | Descripción |
|---|---|---|
url | string | Página en vivo para probar (obligatorio) |
selector | string | Selector CSS a validar (obligatorio) |
projectRoot | string | Proyecto cuyo Playwright lanza el navegador |
timeoutMs | number | Límite general, predeterminado 45000 |
Veredictos: ✅ VALID — N matches (con una muestra de coincidencias), ✅ VALID — 0 matches (con consejos de depuración), ❌ INVALID (error de análisis + corrección), o una advertencia cuando la entrada usa un motor solo de Playwright (text=, xpath=, >>, :has-text()), que no es CSS plano.
generate-e2e-test
| Argumento | Tipo | Descripción |
|---|---|---|
description | string | Lo que la prueba debe cubrir (obligatorio) |
pageUrl | string | Página en la que comienza la prueba (predeterminado: baseURL / webServer.url de la configuración) |
testDir / file | string | Dónde escribir la especificación (predeterminado: testDir detectado + generated/<slug>.spec.ts); file debe terminar en .spec.* o .test.* |
write | boolean | Escribir el archivo en disco (predeterminado true) |
overwrite | boolean | Reemplazar una especificación existente en la ruta de destino; solo las especificaciones generadas por esta herramienta pueden reemplazarse |
liveInspect | boolean | Verificar selectores contra la página en vivo (predeterminado activado cuando se conoce una URL) |
projectRoot / config | string | Igual que las otras herramientas |
Lee los cambios recientes del agente (git status, con respaldo a git diff HEAD~1, luego mtimes recientes), extrae los localizadores que esos archivos realmente declaran (data-testid, getByRole, aria-label, placeholder, id, name, texto de elemento), clasifica primero los selectores verificados en vivo, escribe una especificación construida a partir de ellos e informa cada selector con su file:line de origen.
compare-visual-state
| Argumento | Tipo | Descripción |
|---|---|---|
url | string | Página a capturar (obligatorio) |
name | string | Id de línea base, p. ej. checkout-page (letras, dígitos, . _ -) |
action | compare | baseline | compare (predeterminado) diffs; baseline re-captura la referencia |
selector | string | Capturar solo este elemento |
fullPage | boolean | Capturar la página completa desplazable |
tolerance | number | Porcentaje de píxeles que pueden diferir (predeterminado 0.1) |
pixelThreshold | number | Delta de canal por píxel considerado diferente (predeterminado 60) |
waitUntil / waitFor / timeoutMs | — | Igual que inspect-page |
La primera llamada guarda una línea base bajo .pw-mcp/visual/ (agrega eso a .gitignore, o haz commit para comparaciones de CI). Las llamadas posteriores informan recuentos de píxeles cambiados, regiones fusionadas ((x, y) 120×40 — 1,200 px), el cambio de color promedio ("azul → rojo"), y escriben una imagen de diff resaltada en rojo para revisión.
diagnose-flaky
| Argumento | Tipo | Descripción |
|---|---|---|
testFiles | string[] | Pruebas a diagnosticar (se admiten file:line). Predeterminado: las pruebas que fallaron en la ejecución más reciente |
runs | number | Veces a ejecutarlas, 2–10 (predeterminado 3) |
browser / headed / workers / config | — | Igual que run-test |
timeoutMs | number | Límite de tiempo real duro por ejecución (predeterminado 120000) |
projectRoot | string | Directorio del proyecto |
Cada ejecución se realiza con --retries=0 y reintento automático deshabilitado, por lo que cada resultado es evidencia honesta. La respuesta contiene una tabla por ejecución (estado, duración, primer fallo), el recuento de firmas de error normalizadas distintas, y uno de:
- ❌ FALLANDO CONSISTENTEMENTE — falló en cada ejecución (mismo error → error reproducible, errores diferentes → aún roto, solo ruidoso). Arrégialo; no es inestable.
- ⚠️ INESTABLE — algunas ejecuciones pasaron. Incluye recuentos de
N of My si los fallos comparten una firma (error intermitente real) o varían (inestabilidad de tiempo/entorno). - ✅ NO SE REPRODUCE — pasó en cada re-ejecución; el fallo original fue de una sola vez.
La última ejecución se almacena, por lo que get-failure puede analizarla inmediatamente después.
Instalación
Requisitos:
- Node.js ≥ 20 (el servidor está construido sobre MCP SDK v2 — la línea de especificación
2026-07-28) - Un proyecto con
@playwright/testinstalado y navegadores disponibles (npx playwright install chromium)
No se necesita cuenta de npm — instala directamente desde GitHub (el script prepare
compila dist/ automáticamente al instalar). Fija una etiqueta de versión: un
github:trajectiq-ai/E2E sin fijar ejecuta lo que haya en la rama predeterminada en ese momento.
npx -y github:trajectiq-ai/E2E#v0.1.2
npm install -D github:trajectiq-ai/E2E#v0.1.2 @playwright/test # or as a project dependency
npx playwright install chromium
O descarga el paquete comprimido desde la página de GitHub Releases del repositorio e instálalo localmente:
npm install -D https://github.com/trajectiq-ai/E2E/releases/download/v0.1.2/playwright-e2e-mcp-0.1.2.tgz
Listado en el Registro MCP oficial como
io.github.trajectiq-ai/E2E — los clientes compatibles con el registro lo descubren allí, y cada
etiqueta de versión v* republica la entrada desde CI mediante server.json.
Configuración del cliente MCP
Claude Code / genérico (a nivel de proyecto):
{
"mcpServers": {
"playwright-e2e": {
"command": "npx",
"args": ["-y", "github:trajectiq-ai/E2E#v0.1.2"],
"env": { "PW_MCP_PROJECT_ROOT": "/absolute/path/to/your/project" }
}
}
}
Claude Desktop / Cursor / Windsurf: agrega el mismo bloque a su archivo de configuración MCP.
El servidor usa su directorio de trabajo como raíz del proyecto; establece PW_MCP_PROJECT_ROOT
cuando el cliente lo inicie en otro lugar (por ejemplo, tu directorio personal).
CLIs de Codex / VS Code / Copilot:
codex mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.2
code --add-mcp '{"name":"playwright-e2e","command":"npx","args":["-y","github:trajectiq-ai/E2E#v0.1.2"]}'
Los valores predeterminados de Codex entran en conflicto con este servidor: el primer lanzamiento clona el repositorio y ejecuta
tsc (medido 30 s en una caché fría de npx, frente a un valor predeterminado de 10 s
de startup_timeout_sec), y una ejecución de Playwright con reintentos supera el valor predeterminado de 60 s
de tool_timeout_sec. Aumenta ambos en ~/.codex/config.toml:
[mcp_servers.playwright-e2e]
command = "npx"
args = ["-y", "github:trajectiq-ai/E2E#v0.1.2"]
startup_timeout_sec = 60
tool_timeout_sec = 600
Claude Desktop (un clic): descarga y haz doble clic en la Extensión de Escritorio .mcpb
adjunta a la última versión —
el paquete incluye sus propias dependencias, por lo que no se requiere configuración de Node. Al instalarlo,
te pide que elijas tu raíz del proyecto (obligatorio, sin valor predeterminado: elige la carpeta
del proyecto, no tu directorio personal) y la conecta
a PW_MCP_PROJECT_ROOT, de modo que las herramientas apunten a un proyecto real desde la primera llamada.
Claude Code:
claude mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.2
Gemini CLI / Qwen Code: pega el bloque mcpServers anterior en
.gemini/settings.json (Qwen Code: .qwen/settings.json) — ambos hablan el mismo
formato de configuración de MCP.
Freebuff / Codebuff (a nivel de proyecto): este repositorio incluye un
.agents/mcp.json confirmado, por lo que abrir el checkout en Freebuff
adjunta el servidor a todo el espacio de trabajo — no se necesita configuración global. Tus propios proyectos
pueden hacer lo mismo: coloca un mcp.json con el bloque anterior en su directorio .agents/.
Freebuff te pide que confíes en el .agents/ de un repositorio en la primera ejecución.
Todas las herramientas incluyen anotaciones de herramientas MCP (readOnlyHint,
destructiveHint, idempotentHint, openWorldHint), para que los clientes puedan mostrar avisos de seguridad precisos
antes de ejecutar cualquier cosa.
Desde un checkout local:
{
"mcpServers": {
"playwright-e2e": {
"command": "node",
"args": ["/path/to/playwright-e2e-mcp/dist/index.js"],
"env": { "PW_MCP_PROJECT_ROOT": "/path/to/your/project" }
}
}
}
Endpoint alojado (ChatGPT y clientes remotos)
Algunos clientes — especialmente los conectores personalizados de ChatGPT — solo aceptan servidores MCP HTTPS
remotos y se niegan a iniciar un proceso local de npx. Este repositorio incluye un
puente HTTP Streamable para exactamente ese caso:
| Endpoint | https://playwright-e2e-mcp.vercel.app/api/mcp |
| Transporte | MCP Streamable HTTP (JSON POST de entrada, JSON o SSE de salida) |
| Autenticación | token bearer opcional (PW_MCP_HTTP_TOKEN); sin uno solo se sirven herramientas de solo lectura |
| Fuente | api/mcp.ts → src/http.ts |
El puente ejecuta el mismo createServer() que el transporte stdio; el SDK
atiende cada solicitud con una instancia de servidor nueva, que es lo que una función
serverless quiere. test/http-bridge.test.mjs impulsa el adaptador real de Node a través de
node:http, por lo que un puente roto falla en CI, no en ChatGPT.
Abierto vs. protegido por token. Cuando la implementación no tiene PW_MCP_HTTP_TOKEN,
cualquiera puede alcanzar la URL, por lo que el puente sirve solo list-tests y
get-failure, en modo restringido: list-tests escanea fuentes en lugar de ejecutar
playwright test --list (que ejecutaría la configuración del proyecto), los llamadores
no pueden elegir otro projectRoot, y nada inicia un proceso, maneja un navegador
o escribe un archivo. Establece PW_MCP_HTTP_TOKEN (al menos 16 caracteres; usa un valor
aleatorio) para servir las ocho herramientas a clientes que envíen Authorization: Bearer <token>;
otras solicitudes reciben 401. Los procesos secundarios iniciados a través de HTTP obtienen solo un entorno en la lista de permitidos.
PW_MCP_ALLOWED_HOSTS (separados por comas, * para cualquiera) limita el
encabezado Host aceptado; sin token y sin esa variable, solo se aceptan
nombres localhost y los nombres de host de Vercel de la implementación
(protección contra el reenlace de DNS).
Agrégalo a ChatGPT: Configuración → Conectores → activa Modo avanzado → Desarrollador → Crear conector personalizado → pega el endpoint anterior → autenticación Ninguna (herramientas de solo lectura).
Codex también puede usar el transporte remoto en lugar de iniciar npx, si prefieres
no enviar Playwright a cada máquina:
codex mcp add playwright-e2e-remote --url https://playwright-e2e-mcp.vercel.app/api/mcp
Qué esperar: list-tests funciona e informa las especificaciones incluidas con la
implementación. Incluso con un token, las herramientas que inician un navegador (run-test,
inspect-page, validate-selector, diagnose-flaky, …) no pueden descargar
Chromium en una función serverless, por lo que devuelven su pista normal de NO_PLAYWRIGHT.
Usa la instalación stdio para ejecuciones reales; el endpoint alojado es para descubrimiento
y para clientes que no pueden ejecutar procesos locales.
# verify the handshake without any client
curl -X POST https://playwright-e2e-mcp.vercel.app/api/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
Redespliega después de un cambio: fusiona en main. La integración de Git de Vercel implementa
cada push, por lo que no hay token que gestionar ni paso de CLI — observa el
estado de confirmación de Vercel para el resultado de la implementación.
Configuración
| Variable de entorno | Predeterminado | Propósito |
|---|---|---|
PW_MCP_PROJECT_ROOT | cwd del servidor | Raíz del proyecto predeterminada para cada herramienta |
PW_MCP_ALLOWED_ROOTS | — | Directorios adicionales que un llamador puede pasar como projectRoot (separados por :, ; en Windows). Cualquier cosa fuera de estos y de la raíz predeterminada se rechaza |
PW_MCP_HTTP_TOKEN | — | Solo puente HTTP: token bearer (16+ caracteres) que desbloquea todas las herramientas (ver arriba) |
PW_MCP_ALLOWED_HOSTS | localhost + nombres de host de Vercel cuando no hay token | Solo puente HTTP: lista de permitidos de Host separada por comas; * acepta cualquiera |
PW_MCP_PASSTHROUGH_ENV | — | Solo puente HTTP: variables adicionales separadas por comas pasadas a las ejecuciones de prueba (por ejemplo, BASE_URL) |
PW_MCP_MAX_CHILDREN | 4 | Solo puente HTTP: cuántas ejecuciones de prueba y sondeos de navegador pueden ejecutarse a la vez |
PW_MCP_BLOCK_PRIVATE_URLS | desactivado (activado para el puente HTTP) | 1 hace que las herramientas de URL rechacen direcciones de bucle local, red privada y metadatos de nube, incluidos redireccionamientos y subrecursos |
LOG_LEVEL | info | debug | info | warn | error | silent |
LOG_FORMAT | text | text o json (estructurado) |
Los registros siempre van a stderr — stdout está reservado para el protocolo MCP.
Flujo de trabajo típico
generate-e2e-test{ "description": "checkout with a saved card" }— crea una especificación a partir de tus selectores reales (se omite si escribes la prueba tú mismo).list-tests— mira lo que existe (tests/checkout.spec.ts:5 checkout › pays with card).run-test{ "testFiles": ["tests/checkout.spec.ts"] }— ejecútala; obtén estadísticas + fallos (las pruebas inestables se reintentan automáticamente una vez antes de considerarse fallos).get-failure{ "index": 1 }— lee el marco de código, esperado/real, la instantánea del DOM en el fallo desde el trace, las solicitudes de red fallidas, los errores de consola de la página y los siguientes pasos.- Si parece relacionado con selectores:
inspect-page{ "url": "http://localhost:3000/checkout" }para ver el DOM real, luegovalidate-selectorpara probar que el selector de reemplazo funciona. - Después de cambiar CSS/componentes:
compare-visual-state{ "url": "…", "name": "checkout" }para detectar regresiones visuales no intencionadas. - Si un fallo parece intermitente:
diagnose-flaky{ "runs": 3 }— obtén el veredicto de evidencia (inestable vs. consistentemente roto) antes de decidir qué corregir. - Corrige la especificación o la aplicación, luego vuelve a ejecutar solo lo que falló:
run-test{ "lastFailed": true }, y repite hasta que esté en verde.
Casos límite manejados
| Situación | Comportamiento |
|---|---|
| Playwright no instalado | Error NO_PLAYWRIGHT con los comandos de instalación exactos para tu gestor de paquetes |
| Servidor de desarrollo no ejecutándose | Fallo clasificado como server-unreachable / SERVER_NOT_RUNNING con una pista de "inicia tu servidor de desarrollo" (y consejo de webServer) |
La prueba excede timeoutMs | El grupo de procesos se elimina (SIGINT→SIGKILL en POSIX, taskkill /T /F en Windows) y se devuelven resultados parciales |
| El navegador se bloquea | Clasificado como browser-crash con guía de reintento / reinstalación |
| Barras invertidas de Windows | Todas las rutas se normalizan léxicamente (C:\a\..\b → C:/b); probado unitariamente en ambas plataformas |
| Pruebas inestables | Las pruebas que fallan se reintentan automáticamente una vez (--retries=1) antes de informarse; los pases aparecen como inestables con una advertencia de estabilidad; diagnose-flaky decide inestable-vs-roto con evidencia de múltiples ejecuciones |
| Contexto de trace/DOM | --trace=retain-on-failure se pasa automáticamente, por lo que get-failure puede mostrar el DOM exacto en el momento del fallo — además de las solicitudes de red fallidas (registros de *.network) y errores de consola del mismo trace |
| Re-ejecuciones lentas después de una corrección | run-test con lastFailed: true re-ejecuta solo las pruebas que fallaron la última vez (--last-failed) |
Varios archivos playwright.config | Devuelve un menú numerado (MULTIPLE_CONFIGS); elige con config: "2" o una ruta |
| Error de sintaxis en una especificación | SYNTAX_ERROR con archivo:línea; nada se bloquea; list-tests recurre a un escaneo de fuentes |
| El cliente MCP se desconecta | El AbortSignal por solicitud elimina la ejecución; el fin de stdin activa el apagado, y cada árbol de procesos secundarios rastreado se elimina a la fuerza (killActiveChildren) |
| Disco lleno | ENOSPC detectado → DISK_FULL con una pista de "libera espacio"; el registro nunca lanza excepciones |
| Rutas maliciosas | ../../etc/passwd, rutas absolutas fuera de la raíz, un projectRoot fuera de las raíces permitidas, enlaces simbólicos que salen de la raíz, URLs y bytes nulos se rechazan con INVALID_PATH; los argumentos CLI adicionales deben ser banderas de Playwright en la lista de permitidos |
Notas de seguridad
- Sin shell: Playwright se lanza como
node <playwright/cli.js> …con un array de argumentos — sin interpolación de comandos. Losargsadicionales se limitan a una lista permitida de flags de Playwright, cada uno con un valor verificado (--flag=value), por lo que un llamador no puede intercambiar otro--configo--outputni pasar a git una opción a través de--only-changed. Las rutas con un segmento que comienza con-se rechazan, por lo que un nombre de archivo de prueba no puede leerse como un flag. - Sandbox de rutas: las rutas del usuario deben permanecer dentro de la raíz del proyecto, verificadas léxicamente
y nuevamente con los enlaces simbólicos resueltos. Un
projectRootproporcionado por el llamador debe estar dentro dePW_MCP_PROJECT_ROOT(o una entrada dePW_MCP_ALLOWED_ROOTS). - Código generado:
generate-e2e-testsolo escribe archivos*.spec.*/*.test.*, solo sobrescribe especificaciones cuyo encabezado escribió él mismo, nunca escribe a través de un enlace simbólico, y escapa cada valor que coloca en cadenas o comentarios. - Puente HTTP: herramientas de solo lectura a menos que
PW_MCP_HTTP_TOKENesté configurado; los procesos hijos iniciados a través de HTTP reciben solo un entorno de lista permitida (PATH,HOME, directorios temporales, locale,CI,PLAYWRIGHT_*,npm_config_*sin credenciales incrustadas, más cualquier cosa enPW_MCP_PASSTHROUGH_ENV), como máximoPW_MCP_MAX_CHILDRENse ejecutan a la vez (un cliente desconectado libera su espacio inmediatamente), y los mensajes de error internos no se devuelven a los clientes. La lista permitida solo cubre el entorno del propio hijo: el código de prueba se ejecuta como el mismo usuario del SO, por lo que en Linux podría leer el entorno de inicio del servidor desde/proc. Por eso solo los titulares de tokens pueden ejecutar código del proyecto; mantén otros secretos fuera del entorno del puente, o ejecútalo bajo un usuario separado. - Protección SSRF: en el puente HTTP (o con
PW_MCP_BLOCK_PRIVATE_URLS=1) las herramientas de URL rechazan hosts que resuelven a direcciones de loopback, privadas, link-local/metadata o reservadas, y enrutan el navegador a través de un proxy local que aplica la misma verificación a cada salto de redirección y subrecurso; las formas IPv6 que incrustan una dirección IPv4 (mapeada, NAT64, 6to4, Teredo) también se bloquean, y WebRTC UDP está deshabilitado para que una página no pueda alcanzar la red alrededor del proxy. Está desactivado para stdio por defecto porque abrir servidores de desarrollohttp://localhostes para lo que sirven estas herramientas. - Limpieza: los archivos temporales de informes/scripts se escriben en el directorio temporal del SO y se eliminan; los procesos hijos se rastrean y se matan al apagar. La descompresión de trazas tiene un presupuesto de tamaño por archivo, y los PNG están limitados a 16,384 px por lado y 50 M píxeles.
Desarrollo
src/
├── index.ts # bin entry point (--version/--help, main-module guard)
├── server.ts # McpServer setup, tool registration, shutdown handling
├── tools/ # the eight tools + shared plumbing
├── utils/ # playwright-runner, report-parser, project-detector, path-utils,
│ # logger, trace-reader (trace.zip → DOM/network/console),
│ # image-diff (PNG codec + pixel diff), change-analyzer
└── types/ # shared interfaces and the ErrorKind taxonomy
Construido sobre @modelcontextprotocol/server v2 (la línea de especificación MCP 2026-07-28) con
esquemas estándar Zod v4; cada herramienta declara anotaciones de herramienta de especificación.
npm install
npm run build # tsc → dist/ (zero errors)
npm test # build + test/run-tests.mjs (unit tests, any Node ≥20)
npm run e2e # build + e2e/run.mjs: live MCP ↔ Playwright integration suite
Las pruebas cubren el analizador de informes (JSON de Playwright de muestra, adjuntos de trazas), utilidades de rutas
(rutas de Windows y macOS, sandboxing), el detector de proyectos (fixtures de directorios temporales: descubrimiento de
configuración, múltiples configuraciones, instalación faltante, escaneo de archivos de prueba), los
helpers compartidos de herramientas, el lector de trazas (trace.zip sintético: error, acción fallida, instantánea DOM,
análisis de solicitudes fallidas *.network, eventos de consola de error/advertencia), el diff de imágenes
(round-trip PNG, regiones, cambio de color, cambios de dimensiones), el analizador de cambios
(extracción de selectores, rutas git + mtime), la lógica de veredicto flaky
(firmas de fallo, CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING / NO TESTS RAN),
el puente HTTP (token, modo restringido, lista permitida de Host), las regresiones de
seguridad (escapes de sandbox, contrabando de argumentos, escrituras de enlaces simbólicos, inyección de código,
rangos SSRF, limpieza de entorno, límites de decodificación), el manifiesto .mcpb y los archivos de configuración MCP.
Suite de integración (npm run e2e)
Las pruebas unitarias prueban la lógica; la suite de integración prueba el bucle. Inicia el servidor
real sobre stdio contra una aplicación fixture en vivo y un proyecto de Playwright bajo
e2e/fixture/, luego lo maneja exactamente como un cliente MCP y afirma ~40 comportamientos
que solo aparecen de extremo a extremo:
- handshake de inicialización, 8 herramientas, anotaciones de herramienta de especificación y esquemas de entrada de objetos,
- inspección DOM en vivo, validación de selectores CSS (coincidencias, cero coincidencias, sintaxis de motor, errores de análisis), detección de servidor muerto,
- regresión visual: línea base → comparación sin cambios → detección de diff
blue → red, - estadísticas de aprobado/fallido/
run-testy líneas de metadatoslastFailed, - diagnósticos de traza
get-failure: DOM en el fallo, la solicitud de red 404, el mensajeconsole.error, diagnóstico y próximos pasos, - reintento automático que convierte un fallo de primera ejecución en
PASSED (1 flaky), - veredicto
diagnose-flakyFLAKY (2 de 3 ejecuciones) con reintentos deshabilitados, generate-e2e-testescribiendo su andamiaje, más rutas de error (ruta de prueba faltante, herramienta desconocida, servidor inalcanzable).
La primera ejecución necesita el navegador una vez: npx playwright install chromium.
CI ejecuta la suite en Ubuntu y Windows (ver .github/workflows/ci.yml).
Prueba el ejemplo
Con Playwright instalado en tu proyecto:
npx playwright test examples/sample-test.spec.ts
o pide a tu agente que llame a run-test con
"testFiles": ["examples/sample-test.spec.ts"] — accede a la página pública
example.com, por lo que verifica navegadores, red y el pipeline
MCP de una sola vez.
Licencia
MIT