TL;DR Una línea para instalarlo, y a partir de ahí pide el cambio y la comprobación en la misma frase. Claude abre la página, mide lo que acaba de escribir con
browser_evaluatey lo vuelve a intentar hasta que cuadra. Lo que cierra el bucle no es la captura de pantalla: es la medición. El árbol de accesibilidad te dirá que el botón está ahí y se llama bien. Solo la medida te dice que es blanco sobre blanco.
Todas las guías de Playwright MCP terminan donde empieza lo interesante. Te enseñan el comando de instalación, te listan las herramientas y ahí lo dejan, como si tener el servidor conectado fuera el logro. No lo es. El logro es lo que cambia en tu forma de pedir las cosas cuando Claude puede mirar el resultado de su propio cambio.
La diferencia con verificar al final es de tiempo, no de herramienta. Si lo que quieres es una auditoría puntual cuando ya has terminado, /run y /verify ya vienen dentro de Claude Code y hacen justo eso: leen el diff, levantan la app y comprueban si el cambio se nota. Esto es otra cosa. Esto es darle el instrumento antes de que empiece, para que las dos o tres vueltas de corrección ocurran mientras trabaja, sin que tú entres en medio.
Resultado:
> Cambia el botón de pago al color de marca y comprueba
en localhost:3000 que se lee sobre el fondo
⏺ Edit src/checkout.css
⏺ browser_navigate http://localhost:3000
⏺ browser_snapshot
- button "Pagar ahora" [ref=e5]
⏺ browser_evaluate getComputedStyle(btn)
{ color: "rgb(255, 255, 255)",
background: "rgb(255, 255, 255)" }
Contraste 1:1. El botón existe pero no se ve.
⏺ Edit src/checkout.css
⏺ browser_evaluate getComputedStyle(btn)
{ color: "rgb(15, 23, 42)",
background: "rgb(217, 128, 73)" }
Contraste 6.06:1. Pasa AA.
Dos ediciones y una comprobación entre medias, sin que nadie se lo pidiera por segunda vez.
Instalación
claude mcp add playwright -- npx @playwright/mcp@latest
claude mcp list
La segunda línea es la que importa. Si no aparece playwright: ... ✔ Connected, lo demás no existe:
playwright: npx @playwright/mcp@latest - ✔ Connected
Por defecto se instala en el proyecto en el que estés. Si lo quieres en todos, añade --scope user. En un repo de backend puro estorba, así que el ámbito por proyecto suele ser la elección sana, la misma lógica que aplica a cuántos MCP merecen un slot.
Qué le estás dando exactamente
Veinticuatro herramientas, en la versión que tengo delante (1.63.0-alpha). Las que se usan todo el rato son cinco: browser_navigate, browser_snapshot, browser_evaluate, browser_click y browser_console_messages. El resto es superficie para casos concretos: formularios, red, pestañas, subida de archivos, teclado.
Lo relevante no es el número, es cómo mira la página. Playwright MCP no le pasa a Claude una imagen: le pasa el árbol de accesibilidad. Esto es una página entera vista desde dentro:
- generic [ref=e2]:
- heading "Checkout" [level=1] [ref=e3]
- paragraph [ref=e4]: "Total: 42,00 EUR"
- button "Pagar ahora" [ref=e5]
Tres líneas y media. Una captura de esa misma página cuesta dos órdenes de magnitud más de contexto y necesita un modelo que sepa mirar imágenes. Y aun así, la captura no te da un número: te da algo sobre lo que opinar.
Por qué la medición y no la captura
Ese árbol de arriba es real, sale de una página que escribí para probar esto. Léelo otra vez. El encabezado está. El total está. El botón está y se llama exactamente como debe llamarse.
La página está rota. El botón tiene el texto blanco sobre fondo blanco.
Nada en el árbol de accesibilidad lo dice, porque el árbol describe estructura, no apariencia. Un agente que solo mire ahí concluye que ha terminado, y tendrá razón dentro de lo que puede ver. La única forma de cazarlo es pedir la medida:
browser_evaluate
() => {
const b = document.querySelector('#pay');
const s = getComputedStyle(b);
return { color: s.color, background: s.backgroundColor };
}
{ "color": "rgb(255, 255, 255)",
"background": "rgb(255, 255, 255)" }
Ahí ya no hay interpretación posible. Dos valores idénticos son dos valores idénticos, y Claude corrige sin discutir.
De aquí sale la única regla que de verdad importa cuando le das un instrumento a un agente: el instrumento tiene que devolver un número o un booleano, no una descripción. Una captura para que la mire produce una opinión. Un getComputedStyle produce un hecho. Sobre el hecho itera solo; sobre la opinión te pregunta a ti.
Pide el cambio y la comprobación juntos
El cambio de hábito es una frase, y es toda la propuesta de este tip:
Sube el interlineado del card de precios a 1.6 y comprueba
en localhost:3000 que el texto no desborda el contenedor.
En vez de:
Sube el interlineado del card de precios a 1.6.
La segunda versión termina contigo abriendo el navegador. La primera termina con Claude abriéndolo, midiendo scrollHeight contra clientHeight y arreglando el desbordamiento que ha provocado, antes de decirte nada.
La condición de parada la pones tú, en esa misma frase. Sin un criterio explícito el agente sigue puliendo, que es el fallo clásico de cualquier bucle de este tipo. Si la tarea es larga o la vas a repetir, /goal existe justo para eso.
El navegador es un caso, no la idea
Playwright MCP es el instrumento cuando lo que haces vive detrás de una URL. La idea de debajo no tiene nada que ver con el frontend: lo que hace que un agente converja es tener una forma de comprobar su propio trabajo que no dependa de que tú se lo confirmes.
| Lo que estás tocando | El instrumento que cierra el bucle |
|---|---|
| Una página o una app web | Playwright MCP (browser_evaluate, browser_console_messages) |
| Una API | curl al endpoint que has tocado, y el código de estado |
| Una función de dominio | El test que falla primero y pasa después |
| Un fichero que se renderiza (SVG, imagen, PDF) | Un script que mida el resultado, no un vistazo |
| Rendimiento | Una pasada de Lighthouse con un umbral concreto |
Es el mismo patrón con distinta piel. Si tu bucle es contra un diseño de Figma, ya está escrito: Figma y Chrome MCP montan exactamente esto con la spec como fuente de verdad. Lo que cambia con Playwright es que no necesitas ni Figma ni un diseño de referencia. Te basta con la afirmación que has hecho en el prompt.
Yo lo tengo escrito como regla en mi CLAUDE.md desde hace meses, con estas palabras: nunca des una tarea por terminada sin demostrar que funciona. Y en la skill con la que genero las imágenes de LinkedIn no hay ningún "míralo a ver qué tal": hay un script que mide el recorte, el margen del pie y la distancia entre bloques, y devuelve OK o MAL. Las dos cosas son este tip aplicado fuera del navegador.
Cuatro cosas que te van a pasar el primer día
file:// está bloqueado. Si le pasas la ruta de un HTML suelto, el servidor responde Error: Access to "file:" protocol is blocked. Necesitas algo sirviendo por HTTP, aunque sea python3 -m http.server.
Arranca en modo con ventana. Por defecto abre un navegador visible, que en una sesión larga es un baile de ventanas. Si prefieres que no aparezca, instálalo con la bandera:
claude mcp add playwright -- npx @playwright/mcp@latest --headless
La página se sirve de caché y la medición no cambia. Me pasó escribiendo este tip: edité el CSS, volví a medir y salieron los mismos valores. El fichero ya estaba corregido, el navegador servía la copia anterior. Si dos vueltas seguidas devuelven exactamente lo mismo, sospecha de la caché antes que del cambio, y navega con un parámetro distinto en la URL.
La consola cuenta errores que no son tuyos. En mi prueba reportó Console: 1 errors y el error era un 404 del favicon. Cuando le pidas que mire la consola, dile qué considera un fallo de verdad.
Referencia
| Herramienta | Para qué la usas en el bucle |
|---|---|
browser_navigate |
Abrir la URL donde vive el cambio |
browser_snapshot |
Ver la estructura de la página en texto, no en píxeles |
browser_evaluate |
Sacar el número que decide si está bien o mal |
browser_console_messages |
Cazar el error de runtime que no se ve en la interfaz |
browser_click |
Llegar hasta el estado donde el cambio se manifiesta |
| Comando | Qué hace |
|---|---|
claude mcp add playwright -- npx @playwright/mcp@latest |
Lo instala en el proyecto actual |
claude mcp add playwright --scope user -- npx @playwright/mcp@latest |
Lo instala en todos tus proyectos |
claude mcp list |
Comprueba que sale ✔ Connected |
claude mcp remove playwright |
Lo quita del proyecto |
Si dudas entre esto y las otras formas de darle un navegador a Claude, la comparación de la extensión de Chrome contra Chrome DevTools MCP sigue siendo válida, y Playwright entra por el mismo lado que el segundo: navegador limpio, sin tus cookies, sin tus sesiones abiertas.
Requisitos
- Node instalado, porque el servidor se ejecuta con
npx - La app corriendo por HTTP en algún puerto
- Playwright descarga su navegador la primera vez que lo lanzas
Documentación oficial: Connect Claude Code to tools via MCP · Playwright MCP