Quando você diz ao Claude Code ou ao Cursor "abra esta página e leia o preço dos três primeiros produtos", o assistente quase sempre busca o HTML bruto da página. Se o preço é carregado com JavaScript, sobra um esqueleto vazio. O Playwright MCP fecha essa lacuna: coloca um navegador real atrás do assistente e oferece os cliques e a digitação como chamadas de ferramenta. A instalação é uma linha só. As perguntas vêm depois: de qual IP o navegador sai, onde se escrevem o usuário e a senha do proxy, e o agente pode ir a qualquer site que quiser?
Neste artigo explicamos o que é o Playwright MCP e como ele funciona, a diferença entre a árvore de acessibilidade e a captura de tela, a instalação em quatro clientes comuns, as flags que realmente ajudam, o ajuste de proxy (inclusive proxy com autenticação), a restrição de origens com --allowed-origins e por que essa restrição não conta como fronteira de segurança. Conferimos as flags no dia da redação no README oficial e na saída de --help. Os exemplos foram executados com @playwright/mcp 0.0.82 por meio de um proxy de teste local.
O que é Playwright MCP?
O Playwright MCP é, na definição do repositório oficial, um servidor de Model Context Protocol que oferece automação de navegador usando o Playwright. Ele tem duas partes. O Playwright é a biblioteca que controla Chromium, Firefox e WebKit a partir do código, e nós o detalhamos em O que é Playwright e como usá-lo com proxy. O MCP é o protocolo que conecta aplicações de IA a ferramentas externas de um jeito padronizado.
Não explicamos o protocolo de novo aqui. Basta saber isto: a aplicação do assistente (o host) inicia o servidor MCP como um processo local, o servidor anuncia a lista de ferramentas que tem e os esquemas delas, e o modelo chama essas ferramentas quando precisa. A separação entre host, client e server, os meios de transporte e os riscos no nível do protocolo estão em O que é MCP (Model Context Protocol)? Guia detalhado.
As ferramentas que o Playwright MCP oferece são ações de navegador: browser_navigate, browser_click, browser_type, browser_fill_form, browser_snapshot, browser_take_screenshot, browser_tabs e outras do tipo. Na versão 0.0.82 a instalação padrão anunciou 25 ferramentas. Quando acrescentamos --caps=vision,pdf, vieram também o clique por coordenadas e a geração de PDF, e o número subiu para 32. A diferença em relação a escrever você mesmo um script de navegador é que quem decide os passos é o modelo: você informa o objetivo, e o modelo escolhe qual link clicar olhando para a página. O funcionamento geral do loop de um agente está em Agentes de IA: planejamento, ferramentas e memória.
Como o Playwright MCP funciona?
Uma requisição passa, do começo ao fim, por estes passos:
- A aplicação host executa o comando da configuração:
npx @playwright/mcp@latest. O servidor se conecta por stdio e anuncia a lista de ferramentas. - Você escreve uma tarefa em linguagem natural. O modelo chama a ferramenta
browser_navigatecom o endereço. - O servidor inicia o navegador na primeira chamada de ferramenta. Sem
--browser, no nosso teste abriu o Google Chrome instalado no sistema; a janela fica visível por padrão e é ocultada com--headless. - Quando a página carrega, o servidor gera o endereço da página, o título e um snapshot da árvore de acessibilidade. Na 0.0.82 a resposta de
browser_navigatesalvou esse snapshot como arquivo YAML no diretório.playwright-mcpda pasta de trabalho e devolveu o caminho, enquantobrowser_snapshotdevolveu a árvore diretamente dentro da resposta. - Cada elemento da árvore tem uma referência:
link "Travel" [ref=e21]. O modelo indica por essa referência o elemento em que quer clicar:browser_click,target: e21. - O servidor executa a ação com o Playwright e mostra na resposta também o código que rodou:
await page.getByRole('link', { name: 'Travel' }).click();. Em seguida volta o snapshot da nova página e o loop continua.
Graças a essa linha de código, você pode transformar depois a exploração do agente em um script comum de Playwright. A flag --codegen escolhe a linguagem dessa saída (typescript, python, java, csharp ou none).
Por que a árvore de acessibilidade é mais útil do que a captura de tela?
A árvore de acessibilidade é a estrutura que o navegador gera para os leitores de tela. Pela definição da MDN, ela carrega quatro informações para cada elemento: nome, descrição, papel e estado. O Playwright exporta essa árvore como YAML; os detalhes do formato estão na documentação de aria snapshots. O snapshot da nossa página de teste (books.toscrape.com) começava assim:
- generic [active] [ref=e1]:
- banner [ref=e2]:
- generic [ref=e5]:
- link "Books to Scrape" [ref=e6] [cursor=pointer]:
- /url: index.html
- text: We love being scraped!
# ... (resumido)
- list [ref=e19]:
- listitem [ref=e20]:
- link "Travel" [ref=e21] [cursor=pointer]:
- /url: catalogue/category/books/travel_2/index.htmlNesse texto o modelo lê diretamente o que é link, o que é botão e o que é caixa de texto. Na captura de tela ele precisa extrair a mesma informação dos pixels e depois estimar as coordenadas do ponto a clicar.
Árvore de acessibilidade (browser_snapshot) | Captura de tela (browser_take_screenshot) | |
|---|---|---|
| Dado que vai para o modelo | Texto (YAML) | Imagem (PNG ou JPEG) |
| Precisa de modelo com visão? | Não | Sim |
| Como o elemento é apontado? | Pelo valor ref, com exatidão | Por coordenadas, se --caps=vision estiver ativo |
| Detalhe que não aparece | Cor, layout, conteúdo de uma imagem | A função de elementos sem nome acessível |
| Trabalho em que se encaixa | Navegação, formulários, leitura de dados | Verificação visual, revisão de design |
A descrição da própria ferramenta diz a mesma coisa: não dá para executar ações com base na captura de tela; para ações usa-se o snapshot. Mesmo assim, não pense que o texto sai de graça. No nosso teste a página inicial da lista de livros gerou uma árvore de cerca de 32 mil caracteres, e os esquemas das 25 ferramentas chegaram perto de 20 mil caracteres. São contagens de caracteres; o equivalente em tokens varia conforme o modelo e nós não medimos. O README é franco nesse ponto: para agentes de programação que trabalham com uma base de código grande, ele recomenda o caminho do Playwright CLI, que não carrega no contexto os esquemas de ferramentas nem a árvore, e posiciona o MCP para trabalhos que exigem estado persistente do navegador e raciocínio passo a passo sobre a página. --snapshot-mode=none desliga o snapshot automático nas respostas, e --mobile faz abrir as páginas móveis, que são mais leves.
Como instalar o Playwright MCP?
Você só precisa do Node.js 18 ou mais recente e de um cliente compatível com MCP. O pacote não é instalado à mão; o cliente o executa com npx a cada inicialização. A entrada que o README chama de "configuração padrão" é a mesma na maioria dos clientes:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}O lugar em que essa entrada é escrita muda conforme o cliente:
| Cliente | Instalação |
|---|---|
| Claude Code | claude mcp add playwright npx @playwright/mcp@latest |
| Claude Desktop | A entrada padrão é adicionada ao arquivo claude_desktop_config.json, aberto em Settings → Developer → Edit Config |
| Cursor | Cursor Settings → MCP → Add new MCP Server, tipo command, comando npx @playwright/mcp@latest |
| VS Code | O comando code --add-mcp ou .vscode/mcp.json; nesse arquivo a chave superior é servers, não mcpServers |
Se você for passar flags ao servidor no Claude Code, coloque -- no meio. De acordo com a documentação de MCP do Claude Code, tudo o que vem depois do hífen duplo é repassado ao comando do servidor sem alteração:
claude mcp add --scope project playwright -- npx @playwright/mcp@latest --headless --isolated--scope project grava a entrada no arquivo .mcp.json na raiz do projeto; se você adicionar o arquivo ao repositório, a equipe usa o mesmo ajuste. Quando testamos o comando, o arquivo ficou com a versão com flags da entrada padrão acima. Você pode conferir a conexão com claude mcp list ou, dentro de uma sessão, com /mcp. Os detalhes do lado do VS Code estão na documentação de MCP do VS Code.
A tag @latest baixa a versão atual a cada inicialização. O pacote muda rápido: os nomes de flags deste artigo pertencem à 0.0.82. Se você quer o mesmo comportamento em toda a equipe, fixe a versão (@playwright/mcp@0.0.82) e olhe a saída de npx @playwright/mcp@latest --help antes de atualizar.
Quais flags são as mais úteis?
A saída de ajuda da 0.0.82 lista cerca de cinquenta opções. As que aparecem no uso diário são estas:
| Flag | O que faz |
|---|---|
--headless | Executa o navegador sem janela. O padrão é com janela |
--browser <nome> | chrome, firefox, webkit ou msedge |
--isolated | Mantém o perfil na memória e não grava em disco; ao fechar a sessão os cookies somem |
--user-data-dir <caminho> | Diretório do perfil persistente |
--storage-state <caminho> | Carrega cookies iniciais e armazenamento local em uma sessão isolada |
--proxy-server <endereço> | Servidor proxy: http://servidor:3128 ou socks5://servidor:8080 |
--proxy-bypass <domínios> | Domínios que não passam pelo proxy, separados por vírgula |
--allowed-origins <lista> | Origens que o navegador pode requisitar, separadas por ponto e vírgula |
--blocked-origins <lista> | Origens a bloquear; é avaliada antes da lista de permissão |
--caps <lista> | Recursos extras: vision, pdf, devtools |
--config <caminho> | Arquivo de configuração JSON |
--timeout-navigation <ms> | Tempo limite de navegação, 60000 por padrão |
Cada flag tem uma variável de ambiente correspondente (como PLAYWRIGHT_MCP_PROXY_SERVER e PLAYWRIGHT_MCP_ALLOWED_ORIGINS). Testamos a variável do proxy e ela deu o mesmo resultado que a flag.
Como configurar proxy no Playwright MCP?
Para um proxy que não pede credenciais, ou seja, quando o seu IP de saída foi adicionado à whitelist de IP no painel, uma única flag resolve:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--headless",
"--isolated",
"--proxy-server=http://pr.proxynet.io:8000",
"--proxy-bypass=localhost,127.0.0.1"
]
}
}
}Rodamos essa configuração com o nosso proxy de teste local: cada página aberta pelo agente caiu no log do proxy como uma linha CONNECT. Já o domínio que colocamos na lista de --proxy-bypass nunca apareceu no log, ou seja, conectou direto. Se você está testando o seu servidor de desenvolvimento local, não esqueça a entrada localhost; caso contrário, o agente tenta chegar à página da sua própria máquina pelo proxy.
SOCKS5 também funciona: --proxy-server=socks5://pr.proxynet.io:1080. No nosso teste a página abriu e o servidor SOCKS5 recebeu o nome de domínio, ou seja, a resolução de DNS ficou do lado do proxy. No SOCKS5 não há suporte a usuário e senha; o motivo é o Chromium, e os detalhes estão no artigo sobre Playwright com proxy que citamos acima. O lado de produto está na página de Proxies SOCKS5.
Você pode confirmar que o proxy está mesmo em uso perguntando ao agente: "Abra https://httpbin.org/ip e escreva o IP que aparece." Se o endereço devolvido não for o seu próprio IP, o tráfego está passando pelo proxy.
Como definir um proxy com usuário e senha?
O primeiro caminho que vem à cabeça é embutir as credenciais no endereço: --proxy-server=http://user:pass@pr.proxynet.io:8000. Não funciona. Quando testamos, o servidor iniciou, mas a primeira navegação voltou com este erro:
Error: browserBackend.callTool: net::ERR_INVALID_AUTH_CREDENTIALS at https://httpbin.org/ipNo log do proxy vimos que a requisição chegou sem credenciais e recebeu um 407. O erro foi o mesmo quando não escrevemos credencial nenhuma. Ou seja, a flag carrega apenas o esquema, o servidor e a porta.
A solução é o arquivo de configuração. O campo browser.launchOptions do JSON passado com --config é repassado às opções de inicialização do próprio Playwright, e o objeto proxy fica ali:
{
"browser": {
"isolated": true,
"launchOptions": {
"headless": true,
"proxy": {
"server": "http://pr.proxynet.io:8000",
"username": "user",
"password": "pass"
}
}
},
"network": {
"allowedOrigins": ["https://books.toscrape.com", "https://httpbin.org"]
}
}A entrada do lado do cliente só aponta para o arquivo:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--config=playwright-mcp.json"]
}
}
}Testamos essa dupla com o nosso proxy local que exige usuário e senha: o navegador recebeu primeiro um 407, enviou as credenciais e a página abriu. Escrever o caminho do arquivo como caminho absoluto é mais seguro, porque o diretório em que o cliente inicia o servidor varia conforme a aplicação.
Como a senha vai ficar em um arquivo em texto puro, tome dois cuidados: não adicione o arquivo ao repositório e, se possível, crie um usuário de proxy separado para esse trabalho. Se você não quer escrever a senha em lugar nenhum, com a whitelist de IP você volta à instalação de uma flag só da seção anterior. A comparação dos dois métodos está em Autenticação de proxy: user:pass ou whitelist de IP.
Como restringir as origens que o agente pode visitar?
Dar um navegador a um modelo significa que cada página lida pode sussurrar instruções para ele. Como funciona a injeção indireta de prompt e por que uma lista de permissão é mais sólida do que uma lista de bloqueio, explicamos em Acesso seguro à web para LLMs: limites e permissões. O Playwright MCP oferece uma implementação pronta dessa ideia:
"args": [
"@playwright/mcp@latest",
"--allowed-origins=https://books.toscrape.com;https://httpbin.org"
]Uma origem é formada por esquema, domínio e porta; a lista é separada por ponto e vírgula. O equivalente no arquivo de configuração é o array network.allowedOrigins, que aceita curinga de porta no formato http://localhost:*. --blocked-origins faz o contrário e é avaliada primeiro; usada sem lista de permissão, todo endereço que não está na lista continua aberto.
No nosso teste, um agente que tentou ir a um endereço fora da lista recebeu esta resposta: net::ERR_BLOCKED_BY_CLIENT. Uma imagem de fora da lista que colocamos dentro de uma página permitida também não carregou, ou seja, a regra cobre os sub-recursos além da navegação.
Três observações mostram o que esse aviso significa na prática:
- Redirecionamentos passam pela lista. Quando um endereço local da lista de permissão redirecionou com
302para um site fora da lista, a página abriu e o agente leu o conteúdo. - Ainda assim pode ser aberta uma conexão com o endereço bloqueado. Vimos uma linha
CONNECTno log do proxy para o domínio bloqueado. A página não carregou, mas o navegador se conectou àquele servidor. - O tráfego de segundo plano do próprio navegador não está sujeito à regra. As requisições do Chrome aos serviços de atualização e de contas passaram pelo proxy independentemente da lista. Se você paga o tráfego por GB, essas requisições também entram na conta.
Entre as ferramentas padrão estão também browser_evaluate e browser_run_code_unsafe. A descrição da segunda é clara: executa JavaScript arbitrário no processo do servidor e equivale a execução remota de código. O acesso ao sistema de arquivos é limitado por padrão à pasta de trabalho e os endereços file:// ficam bloqueados; --allow-unrestricted-file-access remove esse limite, então não use a menos que seja necessário.
A fronteira de verdade você monta do lado de fora: rode o agente em uma conta de usuário separada ou em um contêiner, separe-o das suas sessões pessoais com --isolated, não desligue a etapa de aprovação das chamadas de ferramenta e, se possível, faça uma segunda checagem de domínios no proxy de saída. As flags não substituem essas camadas, elas se somam a elas.
Perfil e sessão: persistente ou isolado?
O modo padrão é o perfil persistente: cookies e dados de login ficam guardados em disco, e na sessão seguinte o agente continua de onde parou. O diretório do perfil é derivado da pasta de trabalho do cliente, então projetos diferentes recebem perfis separados. O README traz um aviso: um perfil persistente só pode ser usado por um navegador de cada vez. Se você for abrir dois clientes no mesmo projeto, dê ao segundo --isolated ou um --user-data-dir separado.
--isolated inicia cada sessão limpa e apaga tudo quando o navegador fecha. Em trabalhos de leitura de dados esse é o padrão certo. Se você precisa testar a sua própria aplicação com login feito, exporta os cookies uma vez e carrega com --storage-state; o formato está na documentação de autenticação do Playwright. Esse arquivo carrega as suas chaves de sessão, então proteja como uma senha. O terceiro modo é conectar-se com --extension ao Chrome que já está aberto. O agente passa a ter acesso a todas as suas abas com login feito, por isso escolha esse caminho só se souber bem o que está fazendo.
Casos de uso
- Checagem de localização: fazer o agente percorrer como o seu site aparece a partir de um país específico. Você aponta o proxy para o ponto de saída daquele país e pede ao agente que relate itens como idioma, moeda e aviso de cookies. Os detalhes estão na página da solução de localização; nas checagens que pedem a aparência de uma conexão doméstica real usa-se Proxies residenciais.
- Teste exploratório: fazer o agente percorrer um fluxo da sua própria aplicação e transformar o código de Playwright gerado em um teste permanente. A montagem de testes a partir de países diferentes está na página de testes de aplicativos.
- Leitura pontual de dados em página dinâmica: pegar alguns valores de uma página pública carregada com JavaScript. Para trabalho regular e de grande volume o agente sai caro; a estrutura permanente está na página da solução de extração de dados, e se o navegador é mesmo necessário está em Páginas estáticas e dinâmicas no web scraping.
- Depuração: com as ferramentas
browser_console_messagesebrowser_network_requestso agente lê os erros de console e as requisições de rede da página e faz um resumo para você.
Mesmo com um agente no comando, quem navega é um navegador e valem as mesmas regras: respeite o arquivo robots.txt e os termos de uso do site, prefira a API oficial quando existir e mantenha baixa a taxa de requisições. Não recomendamos plugins para burlar detecção. Por que os sites tentam distinguir visitantes automatizados, contamos em Por que os sites bloqueiam agentes de compras com IA?.
Erros comuns
| O que você vê | Causa | O que fazer |
|---|---|---|
net::ERR_INVALID_AUTH_CREDENTIALS | O proxy pede credenciais; elas não foram informadas ou foram embutidas no endereço | Escreva username e password no campo launchOptions.proxy do arquivo de --config |
net::ERR_PROXY_CONNECTION_FAILED | Endereço ou porta do proxy errados, ou a saída esbarra em um firewall | Teste o mesmo endereço com cURL |
net::ERR_BLOCKED_BY_CLIENT | O endereço está fora de --allowed-origins ou dentro de --blocked-origins | Adicione a origem à lista com esquema e porta |
| No segundo cliente o navegador não abre | O perfil persistente está travado por outro navegador | --isolated ou um --user-data-dir separado |
| O agente não alcança o seu servidor local | O tráfego de localhost também vai para o proxy | --proxy-bypass=localhost,127.0.0.1 |
Há também erros de hábito que não entram na tabela:
- Tratar a lista de permissão como medida de segurança. Um redirecionamento passa pela lista; monte o isolamento no nível de processo e de rede.
- Abrir o seu perfil pessoal do Chrome para o agente. O perfil em que estão as suas sessões de e-mail e de banco não deve ficar nas mãos de um modelo que lê conteúdo externo.
- Pedir captura de tela para toda tarefa. As ações já correm sobre o snapshot; a imagem serve só para verificação visual.
- Trabalho em equipe com
@latest. Os nomes das flags podem mudar de uma versão para outra; fixe a versão. - Deixar a varredura regular com o agente. Cada passo custa uma chamada ao modelo. Explore com o agente, transforme o código gerado em script e rode esse script.
Guia de decisão
| Necessidade | Recomendação |
|---|---|
| O assistente precisa ler uma página carregada com JavaScript | Playwright MCP, --headless --isolated |
| O agente precisa sair de um país específico | O ponto de saída daquele país com --proxy-server |
| Proxy com usuário e senha | launchOptions.proxy no arquivo de --config |
| Você não quer a senha em um arquivo | Whitelist de IP e --proxy-server sozinho |
| Limitar o agente a poucos sites | --allowed-origins, mais isolamento de processo e de rede |
| Agente de programação em base de código grande | O Playwright CLI que o README recomenda |
| Varredura diária de centenas de páginas | Não um agente, e sim um script escrito com a biblioteca Playwright |
| Aprender o protocolo e os riscos dele | Nosso guia de MCP |
Perguntas frequentes
O Playwright MCP é gratuito?
Sim. O pacote é publicado sob a licença Apache 2.0 e roda com npx sem custo. O gasto vem de dois lugares: os esquemas de ferramentas e os snapshots de página que o modelo processa, e o tráfego de proxy que você consome.
Qual é a diferença entre o Playwright MCP e a biblioteca Playwright?
Na biblioteca quem programa os passos é você, e o script segue o mesmo caminho toda vez que roda. No servidor MCP quem decide os passos é o modelo; você só informa o objetivo. O primeiro é barato e previsível para trabalhos repetidos, o segundo é rápido para exploração e tarefas pontuais. Os detalhes de proxy do lado da biblioteca (proxy por context, rotação, tabela de erros) estão no nosso artigo sobre Playwright com proxy.
Qual navegador ele usa? O Chrome precisa estar instalado?
Sem --browser, no nosso teste abriu o Google Chrome do sistema. Você pode trocar com --browser firefox, webkit ou msedge, ou apontar um executável de navegador específico com --executable-path.
É a mesma coisa que o Browser Use?
O objetivo é o mesmo: fazer um modelo usar um navegador. O Browser Use é uma biblioteca de agentes em Python independente e conduz o loop por conta própria. O Playwright MCP só oferece as ferramentas; quem conduz o loop é o assistente que você já usa (Claude Code, Cursor, VS Code).
Dá para usar com proxy rotativo?
Dá, mas um navegador abre muitas conexões para uma única página, e em um gateway que troca de IP a cada conexão essas conexões podem sair de endereços diferentes. Na leitura de páginas independentes isso não atrapalha. Se você não quer que o IP mude no meio de um fluxo de várias etapas, escolha Proxies de sessão fixa. Como a rotação funciona está em nosso artigo sobre rotação de IP.
Usar proxy faz as telas de verificação sumirem?
Não. O proxy só muda de qual IP a requisição sai. Os sinais deixados por um navegador controlado por automação e a taxa de requisições continuam iguais. O caminho duradouro é uma taxa razoável, páginas permitidas e, quando existir, a API oficial.
Em resumo
O Playwright MCP dá ao seu assistente um navegador real e faz com que ele leia a página como árvore de acessibilidade. A instalação é uma linha só: npx @playwright/mcp@latest. Para o proxy, --proxy-server basta; se forem necessários usuário e senha, embuti-los no endereço termina em ERR_INVALID_AUTH_CREDENTIALS, e o lugar certo é o objeto launchOptions.proxy do arquivo de configuração. --allowed-origins restringe o território do agente, mas não cobre redirecionamentos e, nas palavras da própria documentação, não é uma fronteira de segurança; monte o isolamento no nível de processo e de rede. Fixe a versão, explore com o agente e passe o trabalho repetido para um script. Os tipos de proxy adequados ao ponto de saída do seu agente estão em nossos serviços de proxy.




