Playwright MCP con un build propio de Chromium
Configura un servidor Playwright MCP para lanzar un Chromium concreto con perfil y comprobar dentro de la sesión qué ejecutable arrancó.
BotBrowser Team
Quieres la documentación estructurada de Despliegue?
Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.
Un servidor Playwright MCP se sitúa entre un cliente de agente y un navegador, y el navegador que arranca lo decide una configuración que es fácil dejar sin inspeccionar. Con la configuración correcta, el agente controla el build y el perfil que eligió el operador. Con la configuración incorrecta, el servidor arranca su propio Chromium incluido e informa éxito, de modo que un agente puede completar una tarea entera contra un navegador que nadie pretendía usar. Las claves de configuración que transportan un ejecutable propio, la lectura de comprobación que demuestra qué binario arrancó y el modo de fallo en el que el argumento del perfil se descarta en silencio forman el núcleo operativo de la puesta en marcha. Playwright MCP es un proyecto de Microsoft con su propio ciclo de versiones, y la configuración descrita se apoya en su esquema publicado. BotBrowser proporciona soporte para executablePath y un argumento de perfil desde cualquier lanzador compatible con Playwright, y no incluye un servidor MCP propio, por lo que no puede corregir un servidor que nunca reenvía la opción.
TL;DR
- La ruta del ejecutable va en
browser.launchOptions.executablePath, no en una clave de nivel superior. El esquema de configuración de MCP anidaLaunchOptionsde Playwright bajobrowser, y una clave superior desconocida se ignora en lugar de rechazarse. - Existen otras dos rutas y son más fáciles de equivocar: el flag de CLI
--executable-pathy la variable de entornoPLAYWRIGHT_MCP_EXECUTABLE_PATH. Una sola ruta por despliegue impide que un valor obsoleto gane la precedencia. - El flag del perfil va en
launchOptions.argscomo elemento de array independiente, porque Playwright pasa cada elemento como argumento propio. - La prueba del binario se ejecuta dentro de la sesión:
navigator.userAgent, la ruta de proceso que informa el servidor y un marcador de página que expone el build propio. Un servidor caído al Chromium incluido responde las tres lecturas de forma distinta. - Una instancia de servidor MCP por perfil. Un perfil persistente queda bloqueado a una sola instancia de navegador, así que dos clientes que comparten un espacio de trabajo chocan en lugar de aislarse.
Contenido
- Dónde va la ruta del ejecutable
- Pasar el perfil sin perderlo
- Demostrar qué binario arrancó
- Modos de fallo y la rama de reserva
- Conclusión práctica
Dónde va la ruta del ejecutable
El archivo de configuración de MCP es un documento JSON con un objeto browser. Dentro de ese objeto, launchOptions tiene el tipo LaunchOptions de Playwright, el mismo tipo que un script directo pasa a browserType.launch. Ahí vive executablePath, y es el único anidamiento que el servidor lee.
{
"browser": {
"browserName": "chromium",
"launchOptions": {
"executablePath": "/opt/botbrowser/chrome",
"headless": true,
"args": ["--bot-profile=/etc/botbrowser/profile.enc"]
},
"contextOptions": {
"viewport": { "width": 1280, "height": 800 }
}
}
}
Tres propiedades de ese bloque pesan más que el resto. browserName sigue siendo chromium, porque un build propio de Chromium sigue hablando el protocolo de Chromium y los otros valores (firefox, webkit) enrutarían a un driver distinto. headless pertenece a launchOptions y no al lado de browserName, ya que el servidor reenvía el objeto completo a la llamada de lanzamiento. args es un array de cadenas separadas y cada elemento se convierte en un argumento; una sola cadena con un espacio no se divide.
| Ruta | Dónde va el valor | Gana sobre | Error típico |
|---|---|---|---|
| Archivo de configuración | browser.launchOptions.executablePath | Nada más, salvo que también exista un flag o una variable de entorno | Escribir executablePath en el nivel superior del archivo |
| Flag de CLI | --executable-path /path/to/chrome | El archivo de configuración | Suponer que el flag también define browserName |
| Variable de entorno | PLAYWRIGHT_MCP_EXECUTABLE_PATH=/path/to/chrome | El archivo de configuración | Un valor obsoleto heredado de un perfil de shell |
Las tres rutas son alternativas, no capas. Un despliegue que define el archivo y además exporta la variable de entorno tiene dos fuentes de verdad, y la que el servidor lee en último lugar determina el navegador. Una sola ruta elegida, con las otras dos sin definir en el entorno de lanzamiento, elimina esa ambigüedad.
Por qué una clave desconocida falla en silencio
El servidor valida la forma que conoce e ignora lo que no reconoce. Una configuración que coloca executablePath en el nivel superior, la escribe como executable_path o la anida bajo contextOptions en lugar de launchOptions produce un servidor que arranca con normalidad y un navegador que no es el previsto. El registro de arranque no lo dice necesariamente, porque desde la perspectiva del servidor la configuración era válida y el lanzamiento tuvo éxito.
Ese comportamiento explica que la lectura de comprobación de la sección siguiente no sea opcional. Tratar un arranque correcto como prueba del binario previsto es el fallo más fácil de pasar por alto, y falla en la dirección que importa: el agente trabaja, la tarea termina y el navegador era el equivocado.
Las opciones de contexto son otro objeto
contextOptions es un objeto distinto y lleva BrowserContextOptions, no LaunchOptions. El tamaño de viewport, el locale, la zona horaria, el esquema de color y los permisos van ahí. Mover executablePath a contextOptions produce una opción de contexto inválida que se ignora, y el navegador cae al build incluido.
La separación importa porque los dos objetos parecen intercambiables en un archivo JSON plano. Una comprobación previa al lanzamiento relee el archivo y verifica que browser.launchOptions.executablePath es una cadena que existe en disco y es ejecutable, y que browser.contextOptions no contiene ningún valor con forma de ruta.
Precedencia entre las tres rutas
Cuando más de una ruta define una ruta de ejecución, el resultado depende de cuál lee el servidor en último lugar, y ese orden no se adivina. El patrón seguro hace imposibles las otras dos: PLAYWRIGHT_MCP_EXECUTABLE_PATH sin definir en el entorno que arranca el servidor, y --executable-path ausente de la línea de comandos cuando el archivo ya lleva el valor.
Una comprobación concreta cuesta un comando en el entorno de lanzamiento: imprimir la variable y confirmar que está vacía antes de arrancar el servidor. Un perfil de shell que exporta la variable para otro proyecto es una causa habitual de un servidor que arranca el navegador incluido pese a un archivo correcto, porque las sustituciones de entorno se combinan después de leer el archivo de configuración, así que el valor heredado gana.
El mismo razonamiento se aplica a un script envoltorio que arma la línea de comandos. Si el envoltorio agrega --executable-path desde una variable vacía en un entorno, el flag puede desaparecer por completo y dejar el archivo como única fuente. Ese es el resultado deseable, y el envoltorio se escribe para omitir el flag cuando la variable no tiene valor.
Pasar el perfil sin perderlo
Un perfil no es una opción de lanzamiento que Playwright conozca. Es un argumento del navegador, así que viaja en launchOptions.args como elemento propio del array. Un script directo de Playwright lo escribe igual, y por eso el perfil es la pieza que más se pierde cuando un script que funciona se convierte en configuración MCP.
{
"browser": {
"browserName": "chromium",
"launchOptions": {
"executablePath": "/opt/botbrowser/chrome",
"args": ["--bot-profile=/etc/botbrowser/profile.enc", "--bot-locale=en-US"]
}
}
}
Cada argumento es un elemento de array sin comillas de shell alrededor. "--bot-profile=/etc/botbrowser/profile.enc" y "--bot-profile=/etc/botbrowser/profile.enc --bot-locale=en-US" no son equivalentes: el segundo es un único argumento con un espacio y el navegador lo recibe como un flag malformado en lugar de dos.
De dónde se lee el perfil
El archivo de perfil tiene que ser legible por el proceso que arranca el servidor, que no siempre es el proceso que inició el operador. Un servidor lanzado por un cliente de escritorio hereda el entorno de ese cliente, y un servidor lanzado dentro de un contenedor solo ve lo que se montó. Una ruta que funciona en una shell interactiva puede fallar en el lanzamiento MCP, y el fallo puede aparecer como un navegador que arranca con valores por defecto en lugar de como un error.
La ruta absoluta se resuelve una vez, en el mismo entorno que arranca el servidor, y se registra junto a la configuración. Las rutas relativas se resuelven contra el directorio de trabajo del servidor, que elige el cliente y rara vez se define a propósito.
Una instancia de servidor, un perfil
Un perfil persistente lo puede usar una sola instancia de navegador a la vez. Dos clientes MCP apuntados al mismo perfil, o un cliente y una sesión manual que comparten el mismo directorio de datos de usuario, entran en conflicto: uno de los dos no arranca o se adhiere al estado del otro. El interruptor de aislamiento cambia esto al mantener el perfil en memoria, pero también lo descarta al cerrar, así que es un modo distinto y no una corrección.
| Intención | Ajuste | Consecuencia |
|---|---|---|
| Un cliente, un perfil fijo | Perfil persistente más una instancia de servidor | El perfil queda bloqueado a esa instancia |
| Varios clientes en paralelo | Modo aislado o un directorio de datos de usuario distinto por cliente | Sin estado compartido; el perfil no sobrevive a un reinicio |
| Reutilizar un navegador ya en marcha | Conectar a un endpoint existente | El servidor no lanza el ejecutable configurado |
La tercera fila es la trampa de un despliegue con build propio. Conectarse a un endpoint existente omite por completo la ruta de lanzamiento, de modo que el executablePath de la configuración nunca se consulta. Un equipo que agrega un endpoint CDP para acelerar el arranque puede perder el build propio sin cambiar ninguna opción de lanzamiento.
Estado del perfil y qué pierde un reinicio
La diferencia entre un perfil persistente y uno aislado no es solo de almacenamiento. Un perfil persistente lleva cookies, almacenamiento local y el estado en caché que un sitio usa para reconocer a un visitante recurrente. Un perfil aislado arranca limpio cada vez que el navegador se cierra, así que una tarea que depende de una sesión iniciada tiene que inyectar ese estado de forma explícita en lugar de suponer que sobrevive.
Para una carga de monitoreo o de pruebas ese es el intercambio correcto, porque un arranque limpio hace comparables dos ejecuciones. Para una carga que debe mantenerse con sesión iniciada, el perfil persistente es obligatorio y la restricción de instancia única pasa a ser una condición operativa. Registrar el modo usado junto a la ruta del perfil evita que una comparación posterior entre una ejecución aislada y una persistente se interprete como diferencia de comportamiento.
Demostrar qué binario arrancó
La única comprobación fiable se ejecuta dentro de la sesión que el agente controla. Tres lecturas juntas distinguen el build previsto del respaldo incluido, y cada una es barata.
La primera es la cadena de user agent. Un build propio puede informar una versión de Chromium distinta de la del build incluido, o puede informar un user agent configurado que no corresponde a ningún build, así que esta lectura corrobora en lugar de decidir. Un Chromium incluido por Playwright informa la versión que trae el paquete instalado, y la diferencia se ve con una sola lectura de navigator.userAgent.
La segunda es la ruta del ejecutable que informa el proceso. Donde el build la expone, se lee desde la página; donde no, se lee de la lista de procesos del servidor en el host que lo arrancó. En cualquier caso el valor debe ser igual a la ruta de la configuración, carácter por carácter.
La tercera es un marcador que el build propio define y un build estándar no. Puede ser una propiedad extra en un objeto de API del navegador, una cadena de versión en un espacio de nombres del producto o un flag de capacidad documentado. El marcador es el más fuerte de los tres porque no lo puede producir una versión numéricamente parecida por coincidencia.
| Lectura | El build previsto responde | El respaldo incluido responde | Dónde se lee |
|---|---|---|---|
navigator.userAgent | La versión de Chromium del build propio | La versión incluida por Playwright | Cualquier página de la sesión |
| Ruta del ejecutable del proceso | La ruta configurada | Una ruta bajo la caché de Playwright | Lista de procesos del servidor, o lectura de página donde se exponga |
| Marcador del build propio | Presente | Ausente o por defecto | Un script de página que lee la propiedad concreta |
Una lectura que solo comprueba la primera es débil, porque un build propio puede compartir cadena de versión con el incluido. Una lectura que solo comprueba la tercera también es débil, porque prueba una capacidad y no la identidad del proceso que sirve la página. La ruta y el marcador forman la comparación principal, y el user agent actúa como corroboración.
Una lectura que el agente puede ejecutar
La comprobación no necesita un harness aparte. El cliente evalúa una expresión corta en la sesión y devuelve el resultado; el agente lo compara con la ruta configurada sin salir de la conversación. Lo que importa es que la comparación sea explícita y quede registrada, no que esté automatizada.
Tres valores por sesión: la ruta configurada, la ruta observada y el resultado del marcador. Una sesión con ruta coincidente y marcador presente corresponde al build previsto. Una sesión con ruta distinta es el respaldo, diga lo que diga el user agent.
Leer la ruta cuando el build no la expone
No todos los builds exponen su ruta de ejecutable al script de página, y un build que no la expone no es defectuoso. Donde la página no puede responder, la lista de procesos del host que arrancó el servidor y el proceso hijo correspondiente dan la respuesta. La relación padre-hijo es la parte que importa: una máquina puede ejecutar varios procesos de Chromium, y el relevante es el descendiente del servidor MCP, no un navegador abierto a mano.
Un marcador a nivel de página sigue siendo la señal positiva más barata, así que la propiedad estable se pregunta al proveedor del build en lugar de raspar una propiedad incidental. Un marcador que cambia entre versiones menores es peor que ninguno, porque produce un falso negativo con aspecto de respaldo.
Modos de fallo y la rama de reserva
Los fallos se agrupan en un conjunto pequeño, y cada uno tiene una firma distinta. Nombrarlos convierte el diagnóstico en una consulta en lugar de un experimento.
| Síntoma | Causa | Confirmación | Corrección |
|---|---|---|---|
| El navegador arranca, versión equivocada en el user agent | executablePath no leído | El archivo tiene la clave en el nivel superior o bajo contextOptions | Moverla a browser.launchOptions |
| El navegador arranca, ajustes del perfil ausentes | Flag de perfil descartado o malformado | args contiene una cadena con un espacio en lugar de elementos separados | Separar un elemento de array por flag |
| El servidor sale con un error de lanzamiento | La ruta configurada falta o no es ejecutable | La ruta no se resuelve en el entorno del servidor | Usar una ruta absoluta legible por el proceso que arranca el servidor |
| Un segundo cliente no arranca un navegador | Perfil persistente ya bloqueado | Los dos clientes apuntan al mismo directorio de datos de usuario | Aislar o dar a cada cliente su propio directorio |
| Build propio ignorado tras una aceleración del arranque | Se configuró un endpoint existente | La configuración todavía lista un endpoint | Quitar el endpoint para que se ejecute la ruta de lanzamiento |
Las dos primeras filas son las que producen un agente funcional contra el navegador equivocado, y también las que un registro de arranque no reporta. Las otras tres fallan con suficiente ruido para notarse, lo que las vuelve la mitad barata del problema.
Qué ve y qué no ve el cliente
Un cliente MCP ve las herramientas que el servidor expone: navegación, snapshot, clic, escritura y todo lo demás que publique. No ve la configuración de lanzamiento, el proceso que se arrancó ni los argumentos que se pasaron. Esa asimetría explica que la lectura de comprobación se solicite a través de la sesión en lugar de suponerse desde el cliente.
También explica por qué un cliente no detecta el respaldo por sí solo. El reparto de responsabilidades entre un bucle de agente y el proceso del navegador se trata en navegador headless para agentes IA, el script directo que esta configuración debe reproducir está en la guía de inicio de Playwright, y la forma plana del objeto de lanzamiento, con executablePath, args y headless, que espera un servidor basado en Puppeteer está en configuración del servidor MCP de Puppeteer. Desde su perspectiva el servidor funciona correctamente, porque efectivamente lanza un navegador y sirve herramientas contra él. La única parte que sabe qué navegador se pretendía es el operador que escribió la configuración.
Registro del resultado de una verificación
Una verificación que no se escribe se repite. La ruta configurada, la ruta observada, el resultado del marcador y la marca de tiempo se guardan juntos, de modo que una sesión posterior compare sin volver a deducir qué significaba un resultado correcto en ese momento. Cuando la configuración cambia, el registro hace visible el cambio en lugar de dejarlo silencioso.
Esa disciplina es la misma que necesita un lanzamiento directo de Playwright, y pesa más bajo un servidor MCP porque el lanzamiento queda una capa más lejos de quien escribió las opciones. El cliente no ve esa capa, así que el registro es la única evidencia durable de que la capa se configuró como se pretendía.
FAQ
¿Playwright MCP lee executablePath en el nivel superior del archivo de configuración?
No. El esquema anida LaunchOptions de Playwright bajo browser.launchOptions, y una clave de nivel superior no forma parte de esa estructura. El servidor ignora lo que no reconoce, así que una clave mal ubicada produce un arranque normal con el navegador incluido en lugar de un error de validación.
¿Un solo servidor MCP puede servir varios perfiles a la vez?
No mediante un único perfil persistente. Un perfil persistente queda bloqueado a una instancia de navegador, así que los clientes en paralelo necesitan el modo aislado o directorios de datos de usuario separados. El modo aislado mantiene el perfil en memoria y lo descarta al cerrar, lo que representa otro intercambio y no una forma de compartir un mismo perfil.
¿Basta un user agent coincidente para probar que arrancó el build correcto?
No. Un build propio puede informar la misma versión de Chromium que el incluido, así que una coincidencia de versión es corroboración y no prueba. La comparación decisiva es la ruta del ejecutable del proceso frente a la ruta configurada, junto con un marcador que solo expone el build propio.
Conclusión práctica
El ejecutable se escribe en browser.launchOptions.executablePath, cada flag de perfil y de locale ocupa su propio elemento de args, y una sola de las tres rutas que pueden definir la ruta queda activa. Después, antes de cualquier trabajo real, el agente relee la ruta del proceso y un marcador específico del build.
La siguiente acción dura una sesión: arrancar el servidor con la configuración, pedir al cliente que devuelva navigator.userAgent y la ruta de ejecutable observada, y comparar ambos valores con el archivo. Si la ruta coincide, la configuración queda probada. Si no coincide, el servidor ejecuta su Chromium incluido y cada resultado de esa sesión describe un navegador distinto del elegido. Dos superficies contiguas plantean el mismo problema de verificación: la configuración de un navegador headless para agentes de IA cubre el traspaso del agente al navegador, y la guía de inicio de Playwright cubre el script directo que la configuración MCP tiene que reproducir.
Sources
Este artículo forma parte de la guía: Despliegue y versión del navegador: mapa operativo
Artículos Relacionados
Servidor MCP de Puppeteer con un build propio
Primeros pasosNavegadores headless para agentes de IA
DespliegueAutomatización de navegador con Stagehand
Primeros pasosConfigurar browser-use con un navegador controlado
Primeros pasosPlaywright con perfiles de identidad coherentes
Primeros pasosPrimeros pasos con automatización de navegador: mapa inicial
Ejecuta la misma comprobación en BotBrowser
Carga un perfil, mantén dentro del navegador las señales que acabas de leer y confirma el resultado en tu propia máquina antes del despliegue.