Playwright E2E MCP
Execute, depure e inspecione testes ponta a ponta do Playwright a partir de qualquer agente de IA: resultados estruturados com diagnósticos de falha em arquivo:linha, inspeção de DOM ao vivo, validação de seletores, diffs visuais e diagnóstico de testes instáveis.
Servidor MCP hospedado
npx add-mcp 'https://playwright-e2e-mcp.vercel.app/api/mcp'Instala no Claude Code, Codex, Cursor e outros
Documentação
playwright-e2e-mcp
Um servidor MCP que permite que agentes de IA executem, depurem e inspecionem testes Playwright de ponta a ponta — com resultados estruturados, diagnósticos acionáveis de falhas e inspeção de DOM ao vivo.
run-test ──▶ get-failure ──▶ inspect-page ──▶ validate-selector ──▶ fix ──▶ re-run
▲ │
└──────────────────────── list-tests ◀────────────────────────────────┘
Em vez de entregar ao agente a saída bruta do Playwright, este servidor transforma cada execução em resultados processáveis por máquina: estatísticas de aprovação/reprovação, mensagens por falha com file:line, um tipo de falha (asserção, timeout, travamento do navegador, erro de sintaxe, servidor de desenvolvimento morto, disco cheio…), e uma dica concreta de "como corrigir". Quando um teste falha porque um seletor não corresponde mais, o agente pode abrir a página ao vivo em um navegador headless, ver o DOM real com seletores CSS únicos e validar o seletor de substituição antes de executar novamente.
Demonstração
Endpoint hospedado — o que um round-trip de initialize + tools/list contra https://playwright-e2e-mcp.vercel.app/api/mcp retorna para um cliente que envia o token bearer (sem ele, apenas list-tests e get-failure são listados):

Uma execução de teste real — run-test servido via stdio por npx -y playwright-e2e-mcp contra o examples/sample-test.spec.ts incluído (saída real, sem edição):

As imagens são renderizadas com node scripts/gen-demo-images.mjs: o cartão de execução de teste é uma captura real da saída; o cartão de endpoint é uma ilustração da listagem autenticada.
Instalação
Funciona com Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Freebuff e qualquer outro cliente MCP — escolha a rota que preferir:
| Rota | Como |
|---|---|
| npm (canônica, mais rápida) | npx -y playwright-e2e-mcp |
| MCP Registry (clientes com suporte a registry descobrem automaticamente) | io.github.trajectiq-ai/E2E — listagem |
| Qualquer cliente, sem conta npm | npx -y github:trajectiq-ai/E2E#v0.1.2 (fixe uma tag de release) |
| Claude Desktop, sem configuração de Node | clique duas vezes na extensão .mcpb |
| Clientes somente remotos (conectores ChatGPT) | https://playwright-e2e-mcp.vercel.app/api/mcp |
Detalhes e configuração por cliente: Instalação · Configuração do cliente MCP.
Ferramentas
| Ferramenta | Finalidade |
|---|---|
run-test | Executa testes Playwright e retorna estatísticas, falhas, diagnósticos e dicas |
get-failure | Análise aprofundada de uma falha: stack, esperado/real, snapshot do DOM no momento da falha (do trace do Playwright), próximos passos |
inspect-page | Abre uma URL sem interface gráfica e retorna o DOM renderizado: seletores, visibilidade, caixas, texto, saída do console, HTML |
list-tests | Lista testes disponíveis (file, line, título completo, projetos) com filtragem |
validate-selector | Verifica um seletor CSS em uma página ao vivo: validade, contagem de correspondências, exemplos de correspondências |
generate-e2e-test | Gera um teste Playwright a partir de uma descrição usando os seletores reais do projeto, descobertos a partir de alterações recentes de arquivos |
compare-visual-state | Regressão visual: captura de tela antes/depois de uma alteração e relata o que mudou e como as cores mudaram |
diagnose-flaky | Executa um teste com falha 2–10 vezes com novas tentativas desabilitadas e retorna um veredito com evidências: CONSISTENTLY FAILING, FLAKY ou NOT REPRODUCING |
run-test
| Argumento | Tipo | Descrição |
|---|---|---|
projectRoot | string | Diretório do projeto dentro da raiz configurada (padrão: diretório de trabalho do servidor) |
testFiles | string[] | Arquivos/diretórios relativos à raiz; file:line suportado. Omita para executar tudo |
grep | string | Executa apenas testes cujo título corresponda a esta regex |
browser | chromium | firefox | webkit | Projeto Playwright a executar (comparado com os nomes de projeto da configuração) |
headed | boolean | Janela do navegador visível |
timeoutMs | number | Limite rígido de tempo real para a execução (padrão 120000); toda a árvore de processos é encerrada após isso e resultados parciais são retornados |
testTimeoutMs | number | Timeout por teste passado ao Playwright |
workers / retries | number | Repassados ao Playwright |
config | string | Caminho do playwright.config ou índice baseado em 1 quando o projeto tem vários |
retryOnFailure | boolean | Repete automaticamente falhas uma vez antes de relatá-las (padrão true; ignorado quando retries está definido) |
lastFailed | boolean | Executa apenas testes que falharam na execução anterior (Playwright --last-failed) — o ciclo rápido de corrigir → executar novamente |
args | string[] | Flags extras do Playwright de uma lista permitida (--repeat-each=N, --max-failures=N, --update-snapshots, --shard=1/3, --trace=on, …); valores vão após = e são verificados, e flags que recebem um caminho, como --config ou --output, são rejeitadas |
Tratamento de flakiness: por padrão, o servidor injeta --retries=1 (a menos que a configuração já defina retries), então um teste que passa na nova tentativa é relatado como flaky, não como falha. Traces são capturados automaticamente (--trace=retain-on-failure) para que get-failure possa mostrar o DOM no momento da falha.
Exemplo 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 | Descrição |
|---|---|---|
index | number | Índice de falha baseado em 1 da última execução (padrão 1) |
projectRoot | string | Usado apenas ao reler o relatório armazenado |
Retorna a mensagem/quadro de código, esperado vs. real, stack, tipo de falha com um diagnóstico, a saída do console do teste, o snapshot do DOM do trace do Playwright (além da ação que falhou, seu seletor e o log de ações que levaram a ela), as requisições de rede que falharam (4xx/5xx, endpoints mortos, sem resposta — com método, URL, status e tipo de recurso), os erros/avisos do console que a página registrou antes da falha, e próximos passos numerados (re-executar este único teste por file:line, modo headed/debug, validate-selector quando a mensagem mencionar um locator, …).
inspect-page
| Argumento | Tipo | Descrição |
|---|---|---|
url | string | URL http(s) completa para abrir (obrigatório) |
projectRoot | string | Projeto cujo Playwright inicia o navegador |
selector | string | Inspeciona correspondências deste seletor CSS em vez do DOM inteiro |
waitFor | string | Aguarda um seletor (CSS ou text=…) antes de inspecionar |
waitUntil | load | domcontentloaded | networkidle | Condição de espera de navegação |
includeHtml | boolean | Inclui o HTML renderizado (limitado) |
maxHtmlChars | number | Limite de HTML, padrão 20000 |
timeoutMs | number | Limite geral, padrão 45000 |
Retorna o seletor CSS único de cada elemento, tag, visibilidade, caixa delimitadora, texto e atributos, além de mensagens do console capturadas (erros primeiro).
list-tests
| Argumento | Tipo | Descrição |
|---|---|---|
projectRoot | string | Diretório do projeto |
config | string | Caminho da configuração ou índice baseado em 1 |
testDir | string | Restringe a varredura a um diretório (deve permanecer dentro do projeto) |
filter | string | Filtro de substring sem diferenciar maiúsculas/minúsculas em file › title |
limit | number | Máximo de testes retornados, padrão 500 |
Usa playwright test --list quando o Playwright funciona e recorre a uma varredura de código-fonte (mantendo o motivo) quando a instalação ou um arquivo de spec está quebrado.
validate-selector
| Argumento | Tipo | Descrição |
|---|---|---|
url | string | Página ao vivo para testar (obrigatório) |
selector | string | Seletor CSS para validar (obrigatório) |
projectRoot | string | Projeto cujo Playwright inicia o navegador |
timeoutMs | number | Limite geral, padrão 45000 |
Vereditos: ✅ VALID — N matches (com uma amostra de correspondências), ✅ VALID — 0 matches (com conselhos de depuração), ❌ INVALID (erro de análise + correção), ou um aviso quando a entrada usa um mecanismo exclusivo do Playwright (text=, xpath=, >>, :has-text()), que não é CSS puro.
generate-e2e-test
| Argumento | Tipo | Descrição |
|---|---|---|
description | string | O que o teste deve cobrir (obrigatório) |
pageUrl | string | Página em que o teste começa (padrão: baseURL / webServer.url da configuração) |
testDir / file | string | Onde escrever o spec (padrão: testDir detectado + generated/<slug>.spec.ts); file deve terminar em .spec.* ou .test.* |
write | boolean | Escreve o arquivo no disco (padrão true) |
overwrite | boolean | Substitui um spec existente no caminho de destino; apenas specs que esta ferramenta gerou podem ser substituídos |
liveInspect | boolean | Verifica cruzadamente os seletores na página ao vivo (padrão ativado quando uma URL é conhecida) |
projectRoot / config | string | Como nas outras ferramentas |
Lê as alterações recentes do agente (git status, recorrendo a git diff HEAD~1, depois mtimes recentes), extrai os locators que esses arquivos realmente declaram (data-testid, getByRole, aria-label, placeholder, id, name, texto do elemento), classifica seletores verificados como ativos primeiro, escreve um spec construído a partir deles e relata cada seletor com sua fonte file:line.
compare-visual-state
| Argumento | Tipo | Descrição |
|---|---|---|
url | string | Página para capturar (obrigatório) |
name | string | ID da linha de base, ex.: checkout-page (letras, dígitos, . _ -) |
action | compare | baseline | compare (padrão) diffs; baseline recaptura a referência |
selector | string | Captura apenas este elemento |
fullPage | boolean | Captura a página inteira rolável |
tolerance | number | Percentual de pixels que podem diferir (padrão 0.1) |
pixelThreshold | number | Delta de canal por pixel considerado diferente (padrão 60) |
waitUntil / waitFor / timeoutMs | — | Como em inspect-page |
A primeira chamada salva uma linha de base em .pw-mcp/visual/ (adicione-a ao .gitignore, ou faça commit para comparações em CI). Chamadas posteriores relatam contagens de pixels alterados, regiões mescladas ((x, y) 120×40 — 1,200 px), a mudança média de cor ("azul → vermelho"), e escrevem uma imagem de diff destacada em vermelho para revisão.
diagnose-flaky
| Argumento | Tipo | Descrição |
|---|---|---|
testFiles | string[] | Testes para diagnosticar (file:line suportado). Padrão: os testes que falharam na execução mais recente |
runs | number | Vezes para executá-los, 2–10 (padrão 3) |
browser / headed / workers / config | — | Como em run-test |
timeoutMs | number | Limite rígido de tempo real por execução (padrão 120000) |
projectRoot | string | Diretório do projeto |
Cada execução é feita com --retries=0 e nova tentativa automática desabilitada, então cada resultado é evidência honesta. A resposta contém uma tabela por execução (status, duração, primeira falha), a contagem de assinaturas de erro normalizadas distintas, e um dos seguintes:
- ❌ FALHANDO CONSISTENTEMENTE — falhou em todas as execuções (mesmo erro → bug reproduzível, erros diferentes → ainda quebrado, apenas ruidoso). Corrija; não é flaky.
- ⚠️ FLAKY — algumas execuções passaram. Inclui contagens de
N of Me se as falhas compartilham uma assinatura (bug intermitente real) ou variam (instabilidade de timing/ambiente). - ✅ NÃO REPRODUZINDO — passou em todas as re-execuções; a falha original foi pontual.
A última execução é armazenada, para que get-failure possa analisá-la imediatamente depois.
Instalação
Requisitos:
- Node.js ≥ 20 (o servidor é construído no MCP SDK v2 — a linha de especificação
2026-07-28) - Um projeto com
@playwright/testinstalado e navegadores disponíveis (npx playwright install chromium)
Nenhuma conta npm necessária — instale direto do GitHub (o script prepare
compila dist/ automaticamente na instalação). Fixe uma tag de release: um
github:trajectiq-ai/E2E não fixado executa o que estiver no branch padrão naquele 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
Ou pegue o tarball empacotado da página GitHub Releases do repositório e instale-o localmente:
npm install -D https://github.com/trajectiq-ai/E2E/releases/download/v0.1.2/playwright-e2e-mcp-0.1.2.tgz
Listado no MCP Registry oficial como
io.github.trajectiq-ai/E2E — clientes que reconhecem o registry o descobrem lá, e cada
tag de release v* republica a entrada do CI via server.json.
Configuração do cliente MCP
Claude Code / genérico (escopo do projeto):
{
"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: adicione o mesmo bloco ao arquivo de configuração MCP deles.
O servidor usa seu diretório de trabalho como raiz do projeto; defina PW_MCP_PROJECT_ROOT
quando o cliente o iniciar em outro lugar (ex.: seu diretório home).
Codex / VS Code / CLIs do 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"]}'
Os padrões do Codex conflitam com este servidor: o primeiro lançamento clona o repositório e executa
tsc (medido em 30 s em um cache npx frio, contra um padrão de 10 s
do startup_timeout_sec), e uma execução do Playwright com novas tentativas excede o padrão de 60 s
do tool_timeout_sec. Aumente ambos em ~/.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 (um clique): baixe e clique duas vezes na Extensão de Desktop .mcpb
anexada ao último release —
o pacote inclui suas próprias dependências, então nenhuma configuração do Node é necessária. Na instalação,
ele pede que você escolha sua raiz do projeto (obrigatório, sem padrão: escolha a pasta
do projeto, não seu diretório home) e a conecta
ao PW_MCP_PROJECT_ROOT, para que as ferramentas apontem para um projeto real desde a primeira chamada.
Claude Code:
claude mcp add playwright-e2e -- npx -y github:trajectiq-ai/E2E#v0.1.2
Gemini CLI / Qwen Code: cole o bloco mcpServers acima em
.gemini/settings.json (Qwen Code: .qwen/settings.json) — ambos falam o mesmo
formato de configurações MCP.
Freebuff / Codebuff (escopo do projeto): este repositório inclui um
.agents/mcp.json commitado, então abrir o checkout no Freebuff
anexa o servidor em todo o workspace — nenhuma configuração global necessária. Seus próprios projetos
podem fazer o mesmo: coloque um mcp.json com o bloco acima no diretório .agents/
deles. O Freebuff pede que você confie no .agents/ de um repositório na primeira execução.
Todas as ferramentas incluem anotações de ferramenta MCP (readOnlyHint, destructiveHint,
idempotentHint, openWorldHint), para que os clientes possam mostrar avisos de segurança precisos
antes de executar qualquer coisa.
De um 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 hospedado (ChatGPT e clientes remotos)
Alguns clientes — conectores personalizados do ChatGPT especialmente — só aceitam servidores MCP HTTPS
remotos e se recusam a iniciar um processo npx local. Este repositório inclui um
bridge HTTP Streamable exatamente para esse caso:
| Endpoint | https://playwright-e2e-mcp.vercel.app/api/mcp |
| Transporte | MCP Streamable HTTP (JSON POST de entrada, JSON ou SSE de saída) |
| Autenticação | token bearer opcional (PW_MCP_HTTP_TOKEN); sem ele, apenas ferramentas somente leitura são servidas |
| Fonte | api/mcp.ts → src/http.ts |
O bridge executa o mesmo createServer() que o transporte stdio; o SDK
atende cada requisição com uma instância de servidor nova, que é o que uma função
serverless quer. test/http-bridge.test.mjs aciona o adaptador Node real via
node:http, então um bridge quebrado falha no CI, não no ChatGPT.
Aberto vs. protegido por token. Quando a implantação não tem PW_MCP_HTTP_TOKEN,
qualquer pessoa pode acessar a URL, então o bridge serve apenas list-tests e
get-failure, em modo restrito: list-tests escaneia fontes em vez de executar
playwright test --list (que executaria a configuração do projeto), chamadores
não podem escolher outro projectRoot, e nada inicia um processo, aciona um navegador
ou grava um arquivo. Defina PW_MCP_HTTP_TOKEN (pelo menos 16 caracteres; use um valor
aleatório) para servir todas as oito ferramentas a clientes que enviarem Authorization: Bearer <token>;
outras requisições recebem 401. Processos filhos iniciados via HTTP recebem apenas um ambiente na allowlist.
PW_MCP_ALLOWED_HOSTS (separado por vírgulas, * para qualquer) limita o
cabeçalho Host aceito; sem token e sem essa variável, apenas
nomes localhost e os hostnames Vercel da própria implantação são aceitos
(proteção contra DNS-rebinding).
Adicione ao ChatGPT: Configurações → Conectores → ative Avançado → Modo desenvolvedor → Criar conector personalizado → cole o endpoint acima → autenticação Nenhuma (ferramentas somente leitura).
O Codex também pode usar o transporte remoto em vez de iniciar npx, se você preferir
não enviar o Playwright para todas as máquinas:
codex mcp add playwright-e2e-remote --url https://playwright-e2e-mcp.vercel.app/api/mcp
O que esperar: list-tests funciona e relata as especificações incluídas na
implantação. Mesmo com um token, ferramentas que iniciam um navegador (run-test,
inspect-page, validate-selector, diagnose-flaky, …) não podem baixar
Chromium em uma função serverless, então elas retornam sua dica NO_PLAYWRIGHT
normal. Use a instalação stdio para execuções reais; o endpoint hospedado é para descoberta
e para clientes que não podem executar processos locais.
# 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"}}}'
Reimplante após uma mudança: mescle para main. A integração Git do Vercel implanta
cada push, então não há token para gerenciar e nenhum passo de CLI — observe o
status de commit Vercel para o resultado da implantação.
Configuração
| Variável de ambiente | Padrão | Propósito |
|---|---|---|
PW_MCP_PROJECT_ROOT | cwd do servidor | Raiz do projeto padrão para cada ferramenta |
PW_MCP_ALLOWED_ROOTS | — | Diretórios extras que um chamador pode passar como projectRoot (separados por :, ; no Windows). Qualquer coisa fora desses e da raiz padrão é rejeitada |
PW_MCP_HTTP_TOKEN | — | Apenas bridge HTTP: token bearer (16+ caracteres) que desbloqueia todas as ferramentas (veja acima) |
PW_MCP_ALLOWED_HOSTS | localhost + hostnames Vercel quando não há token | Apenas bridge HTTP: allowlist Host separada por vírgulas; * aceita qualquer |
PW_MCP_PASSTHROUGH_ENV | — | Apenas bridge HTTP: variáveis extras separadas por vírgulas passadas às execuções de teste (ex.: BASE_URL) |
PW_MCP_MAX_CHILDREN | 4 | Apenas bridge HTTP: quantas execuções de teste e sondas de navegador podem rodar ao mesmo tempo |
PW_MCP_BLOCK_PRIVATE_URLS | desligado (ligado para o bridge HTTP) | 1 faz as ferramentas de URL recusarem endereços loopback, rede privada e metadados de nuvem, incluindo redirecionamentos e subrecursos |
LOG_LEVEL | info | debug | info | warn | error | silent |
LOG_FORMAT | text | text ou json (estruturado) |
Os logs sempre vão para stderr — stdout é reservado para o protocolo MCP.
Fluxo de trabalho típico
generate-e2e-test{ "description": "checkout with a saved card" }— cria um spec a partir dos seus seletores reais (pulado se você escrever o teste você mesmo).list-tests— veja o que existe (tests/checkout.spec.ts:5 checkout › pays with card).run-test{ "testFiles": ["tests/checkout.spec.ts"] }— execute-o; obtenha estatísticas + falhas (testes instáveis são automaticamente tentados novamente uma vez antes de serem chamados de falhas).get-failure{ "index": 1 }— leia o quadro de código, esperado/real, o snapshot do DOM na falha do trace, as requisições de rede falhas, os erros de console da página e os próximos passos.- Se parecer relacionado a seletores:
inspect-page{ "url": "http://localhost:3000/checkout" }para ver o DOM real, entãovalidate-selectorpara provar que o seletor substituto funciona. - Após mudar CSS/componentes:
compare-visual-state{ "url": "…", "name": "checkout" }para detectar regressões visuais não intencionais. - Se uma falha parecer intermitente:
diagnose-flaky{ "runs": 3 }— obtenha o veredito de evidência (instável vs. consistentemente quebrado) antes de decidir o que corrigir. - Corrija o spec ou o aplicativo, então execute novamente apenas o que falhou:
run-test{ "lastFailed": true }, e repita até ficar verde.
Casos de borda tratados
| Situação | Comportamento |
|---|---|
| Playwright não instalado | Erro NO_PLAYWRIGHT com os comandos de instalação exatos para seu gerenciador de pacotes |
| Servidor de desenvolvimento não rodando | Falha classificada como server-unreachable / SERVER_NOT_RUNNING com uma dica "inicie seu servidor de desenvolvimento" (e conselho webServer) |
Teste excede timeoutMs | O grupo de processos é morto (SIGINT→SIGKILL no POSIX, taskkill /T /F no Windows) e resultados parciais são retornados |
| Navegador trava | Classificado como browser-crash com orientação de nova tentativa / reinstalação |
| Barras invertidas no Windows | Todos os caminhos normalizados lexicalmente (C:\a\..\b → C:/b); testado por unidade em ambas as plataformas |
| Testes instáveis | Testes com falha são automaticamente tentados novamente uma vez (--retries=1) antes de serem relatados; passes aparecem como instáveis com um aviso de estabilidade; diagnose-flaky decide instável-vs-quebrado com evidência de múltiplas execuções |
| Contexto de trace/DOM | --trace=retain-on-failure é passado automaticamente, então get-failure pode mostrar o DOM exato no momento da falha — além das requisições de rede falhas (logs *.network) e erros de console do mesmo trace |
| Re-execuções lentas após uma correção | run-test com lastFailed: true re-executa apenas os testes que falharam da última vez (--last-failed) |
Vários arquivos playwright.config | Retorna um menu numerado (MULTIPLE_CONFIGS); escolha com config: "2" ou um caminho |
| Erro de sintaxe em um spec | SYNTAX_ERROR com arquivo:linha; nada trava; list-tests cai para uma varredura de fonte |
| Cliente MCP desconecta | AbortSignal por requisição mata a execução; o fim do stdin aciona o desligamento, e cada árvore filha rastreada é morta à força (killActiveChildren) |
| Disco cheio | ENOSPC detectado → DISK_FULL com uma dica "liberar espaço"; o registro nunca lança exceções |
| Caminhos maliciosos | ../../etc/passwd, caminhos absolutos fora da raiz, um projectRoot fora das raízes permitidas, symlinks que saem da raiz, URLs e bytes nulos são rejeitados com INVALID_PATH; argumentos extras de CLI devem ser flags do Playwright na allowlist |
Notas de segurança
- Sem shell: O Playwright é iniciado como
node <playwright/cli.js> …com um array de argumentos — sem interpolação de comandos.argsextras são limitados a uma lista de permissões de flags do Playwright, cada uma com um valor verificado (--flag=value), então um chamador não pode trocar por outro--configou--outputou passar uma opção ao git através de--only-changed. Caminhos com um segmento começando com-são rejeitados, então um nome de arquivo de teste não pode ser lido como uma flag. - Sandbox de caminhos: caminhos do usuário devem permanecer dentro da raiz do projeto, verificados lexicalmente
e novamente com symlinks resolvidos. Um
projectRootfornecido pelo chamador deve estar dentro dePW_MCP_PROJECT_ROOT(ou uma entrada dePW_MCP_ALLOWED_ROOTS). - Código gerado:
generate-e2e-testapenas escreve arquivos*.spec.*/*.test.*, apenas sobrescreve specs cujo cabeçalho ele mesmo escreveu, nunca escreve através de um symlink, e escapa todo valor que coloca em strings ou comentários. - Ponte HTTP: ferramentas somente leitura, a menos que
PW_MCP_HTTP_TOKENesteja definido; processos filhos iniciados via HTTP recebem apenas um ambiente na lista de permissões (PATH,HOME, diretórios temporários, locale,CI,PLAYWRIGHT_*,npm_config_*sem credenciais embutidas, além de qualquer coisa emPW_MCP_PASSTHROUGH_ENV), no máximoPW_MCP_MAX_CHILDRENem execução por vez (um cliente desconectado libera seu slot imediatamente), e mensagens de erro internas não são retornadas aos clientes. A lista de permissões cobre apenas o ambiente do próprio filho: o código de teste roda como o mesmo usuário do SO, então no Linux ele ainda poderia ler o ambiente de inicialização do servidor a partir de/proc. É por isso que apenas detentores de tokens podem executar código do projeto; mantenha outros segredos fora do ambiente da ponte, ou execute-a sob um usuário separado. - Proteção SSRF: na ponte HTTP (ou com
PW_MCP_BLOCK_PRIVATE_URLS=1) as ferramentas de URL recusam hosts que resolvem para endereços loopback, privados, link-local/metadata ou reservados, e roteiam o navegador através de um proxy local que aplica a mesma verificação a cada salto de redirecionamento e subrecurso; formas IPv6 que incorporam um endereço IPv4 (mapeado, NAT64, 6to4, Teredo) também são bloqueadas, e o UDP WebRTC é desabilitado para que uma página não possa alcançar a rede contornando o proxy. Está desligado para stdio por padrão porque abrir servidores de desenvolvimentohttp://localhosté para isso que essas ferramentas servem. - Limpeza: arquivos temporários de relatório/script são gravados no diretório temporário do SO e removidos; processos filhos são rastreados e encerrados no desligamento. A descompressão de rastreamento tem um orçamento de tamanho por arquivo, e PNGs são limitados a 16.384 px por lado e 50 M pixels.
Desenvolvimento
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
Construído sobre @modelcontextprotocol/server v2 (a linha de especificação MCP 2026-07-28) com
esquemas padrão Zod v4; cada ferramenta declara anotações de ferramenta da especificação.
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
Os testes cobrem o analisador de relatórios (JSON de amostra do Playwright, anexos de rastreamento), utilitários de caminho
(caminhos Windows e macOS, sandboxing), o detector de projetos (fixtures de diretório temporário: descoberta de
configuração, múltiplas configurações, instalação ausente, varredura de arquivos de teste), os
helpers compartilhados de ferramentas, o leitor de rastreamento (trace.zip sintético: erro, ação falha, snapshot DOM,
análise de requisição falha *.network, eventos de erro/aviso de console), o diff de imagem
(round-trip PNG, regiões, mudança de cor, mudanças de dimensão), o analisador de mudanças
(extração de seletores, caminhos git + mtime), a lógica de veredito flaky
(assinaturas de falha, CONSISTENTLY FAILING / FLAKY / NOT REPRODUCING / NO TESTS RAN),
a ponte HTTP (token, modo restrito, lista de permissões de Host), as regressões de
segurança (fugas de sandbox, contrabando de argumentos, gravações via symlink, injeção de código,
faixas SSRF, limpeza de ambiente, limites de decodificação), o manifesto .mcpb e os arquivos de configuração MCP.
Suíte de integração (npm run e2e)
Testes unitários provam a lógica; a suíte de integração prova o ciclo completo. Ela inicia o servidor
real via stdio contra um aplicativo fixture ao vivo e um projeto Playwright sob
e2e/fixture/, então o conduz exatamente como um cliente MCP e verifica ~40 comportamentos
que só aparecem de ponta a ponta:
- handshake de inicialização, 8 ferramentas, anotações de ferramenta da especificação e esquemas de entrada de objeto,
- inspeção DOM ao vivo, validação de seletores CSS (correspondências, zero correspondências, sintaxe de engine, erros de análise), detecção de servidor morto,
- regressão visual: baseline → comparação inalterada → detecção de diff
blue → red, - estatísticas e linhas de meta de pass/fail/
run-testlastFailed, - diagnósticos de rastreamento
get-failure: DOM na falha, a requisição de rede 404, a mensagemconsole.error, diagnóstico e próximos passos, - nova tentativa automática transformando uma falha de primeira execução em
PASSED (1 flaky), - veredito
diagnose-flakyFLAKY (2 de 3 execuções) com novas tentativas desabilitadas, generate-e2e-testescrevendo seu scaffold, além de caminhos de erro (caminho de teste ausente, ferramenta desconhecida, servidor inacessível).
A primeira execução precisa do navegador uma vez: npx playwright install chromium.
CI executa a suíte no Ubuntu e Windows (veja .github/workflows/ci.yml).
Experimente o exemplo
Com o Playwright instalado no seu projeto:
npx playwright test examples/sample-test.spec.ts
ou peça ao seu agente para chamar run-test com
"testFiles": ["examples/sample-test.spec.ts"] — ele acessa a página pública
example.com, então verifica navegadores, rede e o pipeline MCP
de uma só vez.
Licença
MIT