Playwright MCP
Playwright MCP en Render
Implementa Playwright MCP en Render con un clic. Obtén un servidor de MCP alojado con Chromium headless que tus herramientas de IA puedan usar a través de HTTP: sin instalar un navegador local ni npx en cada máquina.
https://github.com/user-attachments/assets/0f31c279-f2e0-431f-a854-50677bd800c5
Qué hace
Playwright MCP es un servidor del Model Context Protocol que permite a un LLM abrir un navegador real, navegar, hacer clic, escribir y leer páginas mediante instantáneas de accesibilidad estructuradas (no capturas de pantalla). Normalmente se ejecuta localmente con npx @playwright/mcp. Esta plantilla lo ejecuta como un único servicio web de Render, de modo que cualquier cliente MCP pueda conectarse a una URL HTTPS compartida.
Es un envoltorio fino sobre la imagen oficial mcr.microsoft.com/playwright/mcp (Chromium headless ya incluida), sin cambios en el código fuente. El envoltorio añade los flags que Render necesita (--headless, --no-sandbox, además de --port y --allowed-hosts desde el entorno) y un pequeño control de acceso bearer token delante del servidor, porque Playwright MCP no tiene autenticación propia.
Autenticado por defecto. Playwright MCP no tiene autenticación en modo HTTP e incluye una herramienta equivalente a RCE; por eso esta plantilla no lo publica directamente: las peticiones deben llevar
Authorization: Bearer $MCP_TOKEN, y Render genera ese token por ti en el momento del despliegue. Lee Seguridad para saber qué protege y qué no.
Para ver la lista completa de herramientas, opciones de configuración y configuración de clientes, consulta el README upstream.
Related MCP server: WebControl
Arquitectura
Un único servicio web de Render ejecuta la imagen oficial de Playwright MCP detrás de un controlo de acceso bearer token. Un cliente MCP se comunica por Streamable HTTP con /mcp a través del borde TLS de Render; el controlo de acceso verifica el token y reenvía el resto al servidor MCP en loopback, que maneja un Chromium headless en el mismo contenedor y devuelve instantáneas de accesibilidad.
┌─────────────┐ HTTPS /mcp ┌────────────────────────────────────────────────┐
│ MCP client │ ──────────────► │ Render web service (Docker, standard plan) │
│ (Claude, │ + Bearer │ │
│ Cursor, …) │ token │ render-entrypoint.sh │
│ │ │ │ reads PORT, allowed hosts │
│ │ Streamable │ ▼ │
│ │ ◄────────────── │ render-auth-proxy.mjs :$PORT (public) │
└─────────────┘ snapshots │ │ 401 unless the Bearer token matches │
│ ▼ │
│ node /app/cli.js 127.0.0.1:8931 (loopback) │
│ │ │
│ ▼ │
│ headless Chromium (baked into base image) │
└────────────────────────────────────────────────┘Cómo se ensambla un despliegue:
Archivo | Rol |
Blueprint. Declara el único servicio web de Docker, su plan/región, la variable de entorno | |
Envoltorio fino sobre | |
Lee | |
PID 1. Node de pura librería estándar, sin dependencias: rechaza cualquier petición sin | |
El límite de tamaño del control de acceso, mantenido separado porque es la única pieza con estado que vale la pena comprobar por sí sola: tope de ventana fija para los intentos de autenticación fallidos, contados en todos los clientes. Lo importa el proxy, por lo que | |
Compila la imagen y prueba el envoltorio de extremo a extremo: falla cerrado sin | |
Documenta los mismos parámetros para ejecutar el contenedor localmente. |
Propiedades clave:
Envolatorio fino, sin fork de la herramienta. La versión de Playwright MCP está fijada por la etiqueta de la imagen base en
Dockerfile.render; las actualizaciones son tocar esa etiqueta en una línea (consulta Actualización de Playwright MCP).Sin base de datos, sin disco que llenar. El único secreto,
MCP_TOKEN, lo generó Render en el despliegue. El navegador mantiene por defecto el perfil persistente de upstream, por lo que los inicios de sesión se mantienen entre peticiones durante toda la vida de la instancia; útil para un servidor tuyo solo, como asume está plantilla (consulta Configuración).Autenticada y con cierre ante faltas. El controlador de acceso lo añade esta plantilla, no upstream. Si no se establece
MCP_TOKEN, el contenedor se niega a iniciarse, así que no hay configuración en la que el servidor quede expuesto sin autorización (consulta Seguridad).
Requisitos previos
Para desplegar, necesitas:
Una cuenta de Render — crear una es gratis; el propio servicio se ejecuta en el tipo
standardde pago (consulta Despliegue).Una cuenta de GitHub, para hacer un fork de este repositorio (el botón Deploy lee
render.yamlde un repositorio que sea tuyo).
No se necesitan claves de API ni cuentas de terceros. El único secreto, MCP_TOKEN, se genera automáticamente al desplegar: solo tienes que copiarlo en tu cliente MCP (consulta Despliegue).
Para ejecutarlo también en local (opcional — consulta Ejecución local):
Docker con BuildKit (Docker Desktop 4.6 o superior, o compatible con 4. or Docker Engine 23+).
Dockerfile.renderusa una directiva# syntax=yCOPY --chmod, ambas funciones de BuildKit.Un cliente MCP al que apuntarlo (p. ej., Claude Code, Cursor), o simplemente
curl.
No necesita Node.js ni Playwright ni un Chromium local: la imagen base ya incluye todo eso.
Despliegue
Haz clic en Deploy to Render arriba (o bifurca este repositorio y crea un nuevo Blueprint a partir de él).
Render lee la información del blueprint de permitir Render y aprovisiona un único servicio web Docker (
playwright-mcp) en el planstandard.Espera a que el despliegue pase a live (en línea). Tu servidor estará en
https://<tu-servicio>.onrender.com/mcp.Copia
MCP_TOKENde la página Environment del servicio en el Dashboard de Render; Render lo generó por ti. Tu cliente MCP debe enviarlo comoAuthorization: Bearer <token>(consulta Usar la aplicación); sin él, cada petición tendrá un401.Antes de apuntar algo sensible, lee Seguridad. The token is the only thing between the Internet and the code execution in this container, so treat it like the password — and further tighten it if possible.
Sizing del plan: Chromium headless con memoria (OOM) en el nivel gratuito /
starter(512 MB), así que el blueprint usa por defectostandard(2 GB). Cambia a un plan inferior solo si has confirmado que tu carga funciona con menos.
Usando la aplicación
Apunte cualquier cliente MCP al endpoint /mcp de tu servicio y envía MCP_TOKEN como token saltador. Por ejemplo, con Claude Code:
claude mcp add --transport http playwright https://<your-service>.onrender.com/mcp \
--header "Authorization: Bearer <your-MCP_TOKEN>"O el ciente de la configuración:
{
"mcpServers": {
"playwright": {
"url": "https://<your-service>.onrender.com/mcp",
"headers": {
"Authorization": "Bearer <your-MCP_TOKEN>"
}
}
}
}Si el cliente devuelve un 401, la cabecera falta o el token no coincide con el valor actual del Dashboard.
Puedes pedirle a tu asistente que navegue… por ejemplo: "Abre example.com y dame el título de la página y el encabezado principal."… que combine a las herramientas de Playwright MCP contra tu navegador alojado y devuelva ese resultado.
Ejecutar (o) el proyecto local
Opcional, el camino de despliegue anterior no necesita nada de esto. Útil si quieres modificar render-entrypoint.sh y ver el efecto antes de enviar.
git clone https://github.com/render-examples/playwright-mcp-render.git
cd playwright-mcp-render
cp .env.example .env # then set MCP_TOKEN, e.g. to `openssl rand -hex 32`
docker build -f Dockerfile.render -t playwright-mcp-render .
docker run --rm --env-file .env -p 10000:10000 playwright-mcp-renderCuando esté listo, el contenedor imprime el Listening on … de upstream y luego el [auth] Bearer-token gate listening … del controlador, **ese orden es clave porque el controlador mantiene el puerto público cerrado hasta que el servidor detrás acepta, ** y que el último line es el that indica que el servicio eshttps://usable. (La línea [startup] de arriba imprime una URL https:// — ese esquema es para el despliegue; localmente usa http://.) Verifica el estado con un handshake de MCP: exporta el mismo token que pusiste en .env primero, para que la cabecera siguiente se resuelva:
curl -sS -X POST http://localhost:10000/mcp \
-H "Authorization: Bearer $MCP_TOKEN" \
-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"}}}'Deberías obtener un bloque serverInfo que nombre de CLI Playwright, o si el Authorization salta, 401 Unauthorized. Entonces, apunta un cliente a http://localhost:10000/mcp igual que lo harías con la dirección del despliegue.
MCP_TOKENes la única variable de entorno que debes suministrar; el contenedor se cae sin ella sin más. El resto de.enves comodidad: fuera de Render no hayRENDER_EXTERNAL_HOSTNAME, así que la entrada usaPORT=10000y--allowed-hosts *como valor por defecto.
¿Prefieres no ejecutar Docker? Upstream sirve el mismo servidor directamente: npx @playwright/mcp@latest --port 10000 — ten en cuenta that this is whatever npm publishes, esnoor esa, la etiqueta que fija la plantilla, y además no incluye el control de acceso (que es aportación de esta plantilla). Ese camino tampoco es lo que Render despliega, así que verifica tus cambios dentro del contenedor antes de hacer el push.
Configuración
Todo se define en render.yaml y el archivo de entorno .env.example documenta los mismos parámetros para ejecutar en localmente.
Variable | Default | Para qué |
|
| El puerto en el que se expone el gate por el que Render enruta. |
| generado por Render | Obligatorio. Token para pasarlas en cada petición a través de la cabecera |
|
| Puerto loopback del servidor MCP detrás del control el. Enhanced only if there is a collision with something inside the container. |
.env.example también lista PLAYWRIGHT_MCP_HOST, PLAYWRIGHT_MCP_HEADLESS y PLAYWRIGHT_MCP_NO_SANDBOX. Estos parámetros solo importan cuando ejecutas el servidor directamente (fuera de esta imagen) — en Render, render-entrypoint.sh siempre pasa las banderas CLI equivalentes, y las banderas CLI tienen prioridad, así que configurarlos en el panel de Render no tiene ningún efecto. La única excepción es PLAYWRIGHT_MCP_ALLOWED_HOSTS, que el entrypoint sí respeta.
El entrypoint limita la comprobación de host del servidor al nombre de host onrender.com de tu propio servicio automáticamente mediante RENDER_EXTERNAL_HOSTNAME de Render. Si añades un dominio personalizado, las solicitudes dirigidas a él serán rechazadas por la comprobación de host hasta que definas PLAYWRIGHT_MCP_ALLOWED_HOSTS (separado por comas, por ejemplo, myapp.com,myapp.onrender.com; * desactiva la comprobación).
Estado del perfil del navegador
El entrypoint no pasa ninguna bandera de perfil, por lo que obtienes el valor predeterminado de Playwright MCP: un perfil persistente en el sistema de archivos del contenedor (~/.cache/ms-playwright/mcp-*). Merece la pena conocer dos consecuencias:
Los inicios de sesión sobreviven entre llamadas — normalmente es lo que quieres. Autentícate una vez a través del navegador alojado y las sesiones posteriores reutilizarán la sesión. Cada cliente que apunte a la URL comparte ese único perfil, así que esto asume que el servicio es tuyo (consulta Seguridad). No se adjunta ningún disco, por lo que el perfil se borra al reiniciar o volver a implementar.
Clientes concurrentes pueden entrar en conflicto. El proyecto de origen señala que un perfil persistente "solo puede ser usado por una instancia del navegador a la vez, por lo que los clientes MCP concurrentes que compartan el mismo espacio de trabajo entrarán en conflicto" — así que dos editores apuntando a una misma URL pueden colisionar. Escalar a más de una instancia también le da a cada instancia su propio perfil.
Para modificar cualquiera de estos comportamientos, edita render-entrypoint.sh:
Quieres | Añade |
Un perfil nuevo en memoria por sesión, descartado al final |
|
Un perfil que sobrevive a redespliegues (sesiones guardadas) | un Render Disk junto con |
Seguridad
Lo que estás ejecutando realmente
Playwright MCP expone browser_run_code_unsafe, descrito en el proyecto de origen como: "Ejecuta un snippet de código de Playwright. No seguro: ejecuta JavaScript procesado y arbitrario en el proceso del servidor de Playwright y es equivalente a RCE." En la versión fija, está enumerado bajo Core automation, no entre las capacidades opcionales, y --caps solo habilita capacidades adicionales (vision, pdf, devtools) — quindi no puede eliminar este tool, y ninguna bandera descarta herramientas individuales. Cualquier persona que pueda llamar a este servidor puede ejecutar código en tu contenedor como el usuario del contenedor, y llegar a tus otros servicios de Render a través de la red privada.
El proyecto de origen no incluye el inicio de autenticating en modo HTTP, lo que es defendible cuando el servidor es npx en el loopback de tu portátil. En Render its afford a public URL, so this template add the missing door.
Qué hace la plantilla al respecto
render-auth-proxy.mjs es lo único que escucha en $PORT. Responde 401 a cualquier solicitud sin Authorization: Bearer $MCP_TOKEN y reenvía el resto al servidor MCP, que se une a 127.0.0.1 y nobody se publica. Específicamente:
Falla de forma segura (cierre por defecto). Sin
MCP_TOKENno hay inicio: no hay deliberadamente ninguna bandera de para desactivar la comprobación, por lo que ninguna mala configuración deja al servidor anónimo.Secreto generado, no predeterminado.
render.yamlusagenerateValue: true, de modo que cada servicio recibe su propio token, generado una vez cuando se crea el servicio y estable a través de los redespliegues, por lo que los clientes siguen funcionando: además hay no que no hay credencial común en este repo que pueda filtrarse.Comparación de tiempo constante de los resúmenes SHA-256, así que la comprobación no filtra el token byte a byte, y un prefijo del token no se acepta.
Nunca registra el token. Los rechazos solo loguean el método, la ruta y el código
401— nada de lo que presenta el cliente.Limita él la adivinanza. Los intentos fallidos comparten un presupuesto global: diez en un minuto y el resto de la ventana obtiene
429conRetry-After, más una sola línea de registro en lugar de una po cada intento. El presupuesto solo se gasta con solicitudes que iban a ser rechazadas de todos modos, así que un token válido no está sujeto a ello nunca — el bloqueo no puede apuntarte a ti, y siempre puedes volver a entrar mientras un atacante está bloqueado. No es deliberadamente por cliente: esta puerta da servicio a un único secreto compartido, por lo que lo que vale la pena garantizar es un techo total a la velocidad de adivinanza, y un límite por dirección no proporciona esto — el enemigo que va rotando direcciones cada vez consigue una nueva presupuesto.Detiene el token en la puerta. El encabezado
Authorizationno se reenvía al MCP, junto con los encabezados hop-by-hop que un proxy está obligado a eliminar. Las actualizaciones de conexión (WebSocket y similares) se contestan con501en vez de proxyse, ya que el transporte MCP nunca necesita una.
Lo que no hace
Esto es una puerta, no defensa en profundidad. No aísla el RCE, no limita lo que puede hacer una persona autenticada, ni te da identidad por cliente: cualquiera que con el token es el mismo principal, y el límite de tasa anterior frena la adivinanza, no el mal uso de un token que ya se filtró. Si puedes, añade una capa más fuerte encima:
Limita quién puede llegar a este servicio. Las reglas de IP entrante restringidas a tus direcciones conocidas (planes Scale y Enterprise) significan que un token robado no se puede usar desde cualquier otro lugar.
No lo expongas al público. Si su cliente MCP es otro servicio de Render, cambie
type: webeeatype: pservenrender.yamlpara que se transforme en un servicio privado — sin URL pública, esencialmente más seguro, y el token sigue aplicando. Tenga en cuenta que no recibeRENDER_EXTERNAL_HOSTNAME, así que la comprobación de host vuelve a*y el banner de inicio imprime una URLlocalhost; alcáncelo a través de la red privada en la que reside.
Trata el token como una contraseña. Manténgalo fuera de configuraciones y rastreadores de incidencias; roundí celo en el panel de control si se pudiera haber filtrado (un despliegue revise el nuevo valor) y suspenda o elimine el servicio. Después de usar, no lo utilice más.
Cuídalo. Los logs del servicio y las métricas son cómo se darías cuenta de un uso que no iniciaron; las líneas
401significan que alguien está llamando.
Una consecuencia de ese presupuesto compartido que se debe conocer antes de depurar: mientras el atacante gasta el presupuesto, una solicitud con el token incorrecto obtiene 429 en vez de 401. Cualquiera puede mantenerlo vacío indefinidamente: con diez solicitudes rechazadas por minuto ¿Y si alguien? Quien; así que esto puede ser a un servicio que recibe escaneos de fondo, este puede ser un estado normal en lugar de inusual. Si es una prueba con un token que parece obsoleto (por ejemplo, rotado en el Dashboard, o copiado de un servicio antiguo), el código de estado no te dirá eso, y la solución es revisar el token y no aguardar el Retry-After. La petición con el token correct no se ve afectada en ningún caso, lo que hace que aceptar este compromiso sea razonable: cualquiera puede agotar el presupuesto, pero el bloqueo que produce no puede apuntarse contra ti.
La verificación de host que el entrypoint configura (ver Configuración) es una comprobación del encabezado Host contra el rebote de captura de DNS (DNS rebinding) — no control de acceso. Esta no impide que una petición directa con el token válido llegue.
Preparación de la versión de Playwright MCP
La versión queda fijada en un solo lugar: la etiqueta de la imagen base en Dockerfile.render. Para subirla, cambia etiqueta y actualiza la imagen base, ejecuta commit y vuelve a implementar (las imágenes runtime: docker no se despliegan cuando se mueve; un nuevo despliegue tira de la nueva imagen base).
Luego vuelve a comprobar las dos afirmaciones en Seguridad contra el README del proyecto original con la nueva etiqueta: si browser_run_code_unsafe sigue siendo una herramienta de automatización básica no opcional, y si --caps solo sigue agregando capacidades. Actualiza igualmente el enlace permanente de esa sección a la nueva etiqueta, ya es la única otra parte donde aparece una versión literal, y el enlace permanente ha de llevar una.
Después vuelve a verificar la puerta de enlace, ya que depende de la superfície HTTP del projecto. npm run test:wrapper cubre la lógica de la propia puerta en unos segundos sin Docker (el presupuesto de errores, el proxy que responde con 401/429/200, con un upstream espejo), y ./render-smoke-test.sh compila la imagen nueva y la comprueba de extremo a extremo (401 sin el encabezado, 429 tras repetidos intentos con tokens defectuosos, una conexión con el token correcto, una llamada real a la herramienta mediante el tránsito SSE, cierre limpio). El CI ejecuta lo dos en cada PR, así que que que tú abrعامi una PR es equivalente. Si el proyecto finalmente publica ayuda autenticación de verdad, prueba a usarla y borra render-auth-proxy.mjs; este archivo solo existe para llenar ese vacío.
No es una versión que debas mantener sincronizada: el campo
versionenpackage.json. Este repo es un fork de microsoft/playwright-mcp, por lo que ese campo es el propio letrero de la versión de npm del proyecto — — y el despliegue nunca lo ve (usa,Dockerfile.rendersolo copiarender-entrypoint.sh,render-auth-proxy.mjsyrender-auth-limiter.mjs). Espera que se difiera de la etiqueta de la imagen; déjalo como esta.
Basado en icrosos/playwright-mcp · Se despliega en render.
Maintenance
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
Stealth web browser for agents: search, fetch, click, download and type in persistent MCP sessions.
Live browser debugging for AI assistants — DOM, console, network via MCP.
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Reliable web access for AI agents: smart HTTP, rotating proxies, and full-browser rendering.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to automate web tasks such as browsing, clicking, typing, and taking screenshots via the Model Context Protocol.1MIT
- FlicenseNot gradedqualityCmaintenanceHeadless browser automation for LLM agents via REST API or MCP tools. Enables navigating pages, reading structured content, clicking elements, filling forms, and executing JavaScript.
- AlicenseBqualityAmaintenanceEnables browser automation through the Model Context Protocol, allowing AI agents to control Chrome, Firefox, or Edge for tasks like navigation, clicking, typing, and screenshots.3986MIT

Browseagent MCPofficial
AlicenseAqualityDmaintenanceEnables AI agents to control web browsers through the Model Context Protocol, supporting navigation, clicking, typing, and screenshots.12101MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/erlanov2023e/playwright-mcp-render-mt8x2ig6'
If you have feedback or need assistance with the MCP directory API, please join our Discord server