playwright-secure-mcp
Wrapper alrededor del servidor MCP de Playwright con el objetivo de mantener los secretos fuera del alcance de la IA.
Documentación
playwright-secure-mcp
Un servidor MCP en Crystal que actúa como proxy transparente del servidor MCP de Playwright (@playwright/mcp) y añade manejo seguro de contraseñas. Su objetivo: un valor secreto resuelto nunca llega accidentalmente al LLM.
Cómo funciona
- El binario habla MCP JSON-RPC 2.0 sobre stdio con el cliente (el host LLM) y lanza
@playwright/mcpcomo un proceso hijo stdio, reenviando casi todos los mensajes sin cambios. - Añade cuatro herramientas secretas al
tools/listupstream: tres herramientas de descubrimiento que listan o encuentran elementos LOGIN de 1Password utilizables en la página actual del navegador, ybrowser_type_secret, que escribe un campo de un elemento elegido en la página. Cerrar el navegador (browser_close) vacía la caché local de elementos. Ver Herramientas secretas. - Cada mensaje que fluye de vuelta al cliente pasa por un redactor que reemplaza cada secreto resuelto — incluyendo sus variantes codificadas en URL, Base64, escapadas en HTML y escapadas en JSON — con el token literal
«REDACTED». Los secretos se detectan dondequiera que aparezcan: instantáneas de página, volcados de solicitudes de red, mensajes de consola y texto de error.
Herramientas secretas
Descubrimiento: listar o encontrar elementos para la página actual
Tres herramientas buscan elementos LOGIN de 1Password y devuelven solo aquellos utilizables en la página actual del navegador: el proxy lee el location.href de la página por sí mismo (el llamador nunca proporciona una URL) y conserva un elemento solo cuando una de sus URLs coincide con la página por host y prefijo de ruta. Si la URL actual no se puede determinar, el descubrimiento falla con un error. Los resultados son un arreglo JSON de identidades de elementos más metadatos de campos no secretos — vault, item, title, urls, tags, fields (id, label, type, purpose, section), y sections — nunca un valor de campo. Los tres aceptan un vault opcional (ID o nombre) para acotar la búsqueda.
| Herramienta | Argumentos requeridos | Resultado |
|---|---|---|
browser_list_items | (ninguno) | Todos los elementos LOGIN utilizables en la página actual |
browser_find_items_by_name | item (título o ID) | Elementos coincidentes, filtrados a la página actual |
browser_find_items_by_tag | tag | Elementos que llevan la etiqueta, filtrados a la página actual |
Escritura: browser_type_secret
Refleja la herramienta browser_type upstream, pero en lugar de un valor literal text toma las coordenadas 1Password del secreto:
- Requeridos:
element,ref(como enbrowser_type),vault(ID de bóveda 1Password),item(ID de elemento 1Password),field(p. ej.usernameopassword) - Opcionales:
submit,slowly(como enbrowser_type)
El proxy resuelve el campo desde el elemento en caché (obteniendo el elemento de 1Password bajo demanda cuando no está en caché), descifra el valor localmente y emite una llamada interna browser_type al servidor upstream con el valor resuelto. La escritura se rechaza a menos que la página actual esté en el conjunto de URLs del elemento (la misma coincidencia de host + prefijo de ruta que el descubrimiento), y se rechaza cuando la URL de la página actual no se puede determinar.
Duración de la caché
Los elementos descubiertos — con sus valores de campo cifrados — se almacenan en caché en memoria, de una sola escritura. Llamar a la herramienta browser_close upstream vacía esta caché (el cierre aún se reenvía al navegador como de costumbre); de lo contrario, vive durante la vida del proceso.
Flujo de trabajo: encontrar, luego escribir
- Navega a la página de inicio de sesión, luego llama a una herramienta de descubrimiento — p. ej.
browser_list_items— para obtener los IDsvaultyitemde un elemento utilizable en esa página. - Llama a
browser_type_secretcon esos IDs y elfieldpara escribir.
Instalación
Homebrew (macOS y Linux)
Instala desde el tap de Homebrew. La fórmula instala el binario precompilado desde la última versión de GitHub (las compilaciones de macOS están firmadas y notarizadas):
brew install jochenseeber/tap/playwright-secure-mcp
Esto coloca playwright-secure-mcp en tu PATH. Aún necesita la CLI de 1Password (op) y un servidor MCP de Playwright — ver Requisitos.
Para compilar desde el código fuente en su lugar, ver Compilación.
Requisitos
- Crystal
>= 1.20 - La CLI de 1Password (
op), con sesión iniciada pnpmonpmpara descargar@playwright/mcpbajo demanda, o un binario de servidor MCP de Playwright preinstalado
Compilación
rake setup
rake build
rake build escribe un binario de depuración en bin/<profile>-<mode>/playwright-secure-mcp (p. ej. bin/darwin-arm64-system-dynamic-debug/…) y un enlace simbólico bin/playwright-secure-mcp a la última compilación. Usa rake "build[release]" para un binario de lanzamiento. Ejecuta rake -T para listar todas las tareas disponibles.
Opciones
| Opción | Predeterminado | Significado |
|---|---|---|
--package-manager | pnpm | pnpm (pnpm dlx), npm (npx -y) o none (preinstalado) |
--mcp-version | latest | @playwright/mcp etiqueta/rango de versión (ignorado cuando none) |
--mcp-bin | mcp-server-playwright | Binario preinstalado; implica --package-manager none |
--command | (ninguno) | Anulación explícita del comando upstream |
--op-command | op | Binario de la CLI de 1Password |
--account-from-git | (ninguno) | Leer el correo de la cuenta desde DIR/.git/config (user.email) |
--account | (ninguno) | Cuenta de 1Password (abreviatura, correo de inicio de sesión o ID de cuenta) |
--account-email | (ninguno) | Correo de la cuenta de 1Password |
--token-tag | (ninguno) | Etiqueta de elemento de 1Password cuyo campo credential contiene un token de cuenta de servicio |
--require-hardware-key | (desactivado) | Rechazar iniciar sin protección de clave Secure Enclave/TPM |
--version | (ninguno) | Imprimir la versión y salir |
-- <args...> | (ninguno) | Argumentos adicionales reenviados al servidor upstream |
Las tres opciones de cuenta se resuelven en una sola cuenta pasada a op mediante --account; cuando se proporciona más de una, la precedencia es --account-from-git > --account-email > --account. Con --token-tag, la cuenta resuelta se usa una vez al inicio (op interactivo) para obtener el campo credential del elemento etiquetado, y ese valor se usa luego como OP_SERVICE_ACCOUNT_TOKEN para toda resolución de secretos posterior — en ese modo, --account no se pasa a op read. Sin --token-tag, cada op read usa la cuenta resuelta directamente.
Configuración del cliente MCP
{
"mcpServers": {
"playwright": {
"command": "/path/to/bin/playwright-secure-mcp",
"args": ["--", "--headless"]
}
}
}
Modelo de seguridad
- El secreto resuelto viaja
op→ este proceso → hijo upstream → navegador. Nunca está presente en nada que el LLM haya enviado, y nunca está presente sin redactar en nada que el LLM reciba. - Los elementos revelados se almacenan en caché en memoria durante la vida del proceso (o hasta que el navegador se cierra mediante
browser_close) en una bóveda ofuscada: cada valor de campo está cifrado con AES-256-CBC bajo una clave de datos aleatoria por proceso con un IV aleatorio nuevo por entrada. La clave de datos en sí está protegida por hardware cuando es posible — ver Protección de la clave de caché. - Advertencia: la bóveda es ofuscación / defensa en profundidad, no un límite de seguridad. Con el nivel de respaldo en memoria, la clave de cifrado vive en la misma memoria del proceso que el texto cifrado, por lo que derrota la inspección casual del montón, el escaneo estilo
stringsy el registro accidental de texto plano — pero no a un atacante con acceso completo a la memoria del proceso. Un nivel respaldado por hardware elimina la clave de larga duración de la memoria del proceso, pero ver las limitaciones a continuación.
Protección de la clave de caché
Al inicio, el proxy elige el mejor nivel de protección disponible para la clave de datos AES-256 de la bóveda y registra la elección:
- Secure Enclave (macOS, hardware): se genera una clave P-256 efímera y no extraíble dentro del Secure Enclave, y la clave de datos se envuelve con ECIES bajo ella. La clave envuelta se desenvuelve en el enclave por lote criptográfico y la clave en texto plano se pone a cero después; la clave de larga duración nunca existe en la memoria del proceso ni en disco.
- TPM 2.0 (Linux, hardware): la clave de datos se sella dentro del TPM de la plataforma mediante la biblioteca ESYS de tpm2-tss sobre
/dev/tpmrm0y se desella transitoriamente por lote criptográfico, luego se pone a cero. El binario enlaza tpm2-tss, que se asume presente en el host. - Llavero del kernel (Linux, no hardware): la clave de datos se almacena en el llavero del kernel y AES se ejecuta en el kernel mediante un socket AF_ALG, por lo que la clave nunca vuelve a entrar en la memoria del proceso — pero está respaldada por el kernel, no por hardware. Requiere Linux ≥ 5.4.
- En memoria (respaldo): una clave simple por proceso, con una advertencia de inicio de que la protección respaldada por hardware no está disponible.
En Linux, el orden es TPM → llavero → en memoria. Pasa --require-hardware-key para fallar de forma segura: el proxy se niega a iniciar a menos que se inicialice un nivel respaldado por hardware (Secure Enclave / TPM). El nivel de llavero del kernel no satisface --require-hardware-key.
Requisito de implementación (macOS): el Secure Enclave solo se puede usar cuando el binario distribuido está firmado con el entitlement apropiado (acceso a Secure Enclave / llavero). Un binario sin firmar no puede generar una clave de enclave (Security.framework falla con OSStatus -26276) y cae al respaldo de la clave en el proceso — o se niega a iniciar bajo --require-hardware-key.
Limitaciones:
- La clave de datos desenvuelta está en la memoria del proceso transitoriamente por lote criptográfico, luego se pone a cero con el mejor esfuerzo.
- El texto plano del secreto descifrado aún transita por la memoria del proceso durante la redacción y la escritura (fuera de alcance; requeriría un sidecar).
- El costo de ruta crítica por mensaje con el Secure Enclave es de ~2–20 ms (un desenvuelto de clave por lote de mensajes).
Pruebas
rake spec
rake lint