Configurei um plugin WordPress de produção sem abrir o navegador uma única vez. Login, configurações, posicionamento de widgets, upload de plugin, limpeza de cache, debugging – tudo pelo Claude Code.
Precisei configurar um plugin multilíngue no nosso blog WordPress de produção. O plugin é CM Multilingual, que construí com Claude Code em 2 dias. Isso normalmente significa: abrir o admin, fazer login, navegar até as configurações, clicar nas abas, configurar idiomas, adicionar widgets, testar o frontend, voltar, ajustar, testar novamente.
Em vez disso, digitei isto no Claude Code:
vamos adicionar o seletor de idioma e mostrar apenas posts daquele idioma na home
E o Claude fez o resto. Não gerando um script – mas usando o navegador de verdade.
Como o Chrome DevTools MCP lê a página
O Chrome DevTools MCP dá ao Claude acesso ao seu navegador através do Chrome DevTools Protocol. O Claude pode navegar páginas, ler o DOM como uma árvore de acessibilidade, clicar elementos, preencher formulários, fazer upload de arquivos, tirar screenshots e executar JavaScript.
Aqui está como a interação realmente funciona. Eu disse:
ei claude eu quero que você passe por todo o processo com este plugin, temos um tema preparado para ele. Você pode usar chrome devtools mcp
Claude começou listando as páginas abertas do navegador:
chrome-devtools - list_pages
⎿ ## Pages
1: chrome://new-tab-page/ [selected]
Nenhum WordPress aberto ainda. Então o Claude navegou para a página de login, tirou um snapshot do formulário:
chrome-devtools - take_snapshot
⎿ uid=2_5 textbox "Username or Email Address"
uid=2_7 textbox "Password"
uid=2_11 button "Log In"
Então preencheu os campos e clicou em login:
chrome-devtools - fill (uid: "2_5", value: "edy@codeminer42.com")
chrome-devtools - fill (uid: "2_7", value: "supersecretpassword123")
chrome-devtools - click (uid: "1_11")


É isso. Sem seletores CSS. Sem XPath. O Claude lê a árvore de acessibilidade (a mesma estrutura que leitores de tela usam) e identifica elementos pelo seu papel semântico e conteúdo.
Configurando idiomas em produção
Claude navegou para Settings > CM Multilingual. Um take_snapshot revelou o formulário de configurações. Claude selecionou “English” de um dropdown referenciando uid=2_134, clicou “Add Language”, viu o aviso sobre posts não atribuídos, clicou “Assign all to English”, então adicionou Portuguese.
Pude acompanhar através dos screenshots que Claude tirou a cada passo. Mas não precisei. Claude reportou o que encontrou e o que fez.
Após configurar ambos os idiomas, disse:
gostaria de ver você traduzindo um post usando IA, também quero que adicione um seletor de idioma na home page.
Claude navegou para a página Widgets, encontrou o widget “Language Switcher” na lista de widgets disponíveis (uid=1_322), clicou para expandir, selecionou “Sidebar” como destino, e clicou “Add Widget”. O widget apareceu com bandeiras e nomes dos idiomas.
Quando disse que o seletor deveria estar no topo da sidebar, não no final, Claude usou os controles de movimento na interface de widgets do WordPress para reordená-lo.
Fazendo upload de atualizações do plugin
Precisei fazer deploy de uma correção de código. Claude:
- Executou
npm run buildpara compilar o JS - Criou um arquivo zip com
zip -r ~/Downloads/cm-multilingual.zip ... - Navegou para Plugins > Add Plugin > Upload Plugin
- Fez upload do arquivo zip da minha pasta Downloads
chrome-devtools - upload_file (uid: "6_272", filePath: "/Users/edy/Downloads/cm-multilingual.zip")
⎿ File uploaded from /Users/edy/Downloads/cm-multilingual.zip.
- Clicou “Install Now”, depois “Replace current with uploaded”
- Limpou o cache via dropdown Caching na barra de ferramentas admin
Sem FTP. Sem SSH. Sem gerenciador de arquivos. Claude pegou um arquivo local, fez upload através da interface do WordPress, e substituiu o plugin rodando. Fizemos isso cinco vezes em uma sessão enquanto iterávamos nas correções.
O diagnóstico que não consegui encontrar sozinho
A homepage estava mostrando posts em português misturados com posts em inglês. Estava travado. Quando testei localmente com uma instalação limpa do WordPress (mesmo tema, apenas o plugin), tudo funcionou bem. Mas produção tinha dezenas de plugins, configurações de blocos customizadas, e camadas de caching. Encontrar onde a query estava sendo modificada naquele ambiente era um problema diferente. Disse:
está aparecendo em https://blog.codeminer42.com/
Claude navegou para a página Reading Settings e descobriu que o site usa uma página estática como front page (página #6982). Então abriu aquela página no editor de blocos e executou JavaScript para extrair a configuração do bloco Query Loop:
() => {
const content = wp.data.select('core/editor').getEditedPostContent();
return content.substring(0, 1000);
}


A resposta revelou que a homepage tem dois blocos Query Loop:
- Bloco 1:
taxQuery: {"category": [465]}– Banner Dev Weekly (1 post) - Bloco 2:
taxQuery: {"category": [21]}– Listagem principal de posts (apenas categoria “Posts”)
Nosso plugin estava substituindo o tax_query do bloco com o filtro de idioma, apagando o filtro de categoria. É por isso que posts Dev Weekly apareciam – a exclusão de categoria havia sumido.
É isso que faz o MCP funcionar. Uma instalação local limpa é fácil de navegar. Um site WordPress de produção com dezenas de plugins e blocos customizados é uma fera diferente. Claude navegou a bagunça, inspecionou o estado interno do editor de blocos através do wp.data, e encontrou a causa raiz em uma query. Aprendeu onde as coisas estavam mais rápido do que eu conseguiria.
Como um cookie oculto sobrescreveu silenciosamente a detecção de idioma
Após fazer deploy do filtro de idioma, a homepage começou a mostrar apenas posts em português. Disse:
a home page ainda está mostrando posts em português, você tem certeza que isso não pode ser configurado na página?
Claude verificou os cookies:
() => {
const cookies = document.cookie.split(';').map(c => c.trim());
return cookies.find(c => c.startsWith('cm_ml_lang='));
}
// Resultado: "cm_ml_lang=pt_BR"
Um cookie cm_ml_lang de uma visita anterior a /pt-br/ estava sobrescrevendo a detecção de idioma baseada em URL. Claude limpou o cookie, recarregou, e confirmou a correção. Atualizamos o código para usar detecção baseada apenas em URL para queries secundárias da front-page.
A configuração oculta
O link do seletor de idioma inglês estava apontando para /en/ em vez de /. Claude navegou para Settings > CM Multilingual > URLs:
chrome-devtools - take_screenshot
⎿ [Screenshot mostrando "Hide language prefix for default language" DESMARCADO]
Uma checkbox. Só isso. A configuração estava desmarcada em produção, mesmo estando marcada no nosso ambiente de dev local. Claude marcou, clicou “Save Changes”, e tanto os links do seletor quanto a detecção de idioma da homepage começaram a funcionar corretamente.
Sem MCP, eu estaria alternando Alt-Tab entre terminal e navegador, verificando páginas de configurações manualmente. Com MCP, Claude navegou diretamente para a configuração e leu o estado do formulário.
Testando o que o Facebook realmente vê vs. o que o navegador renderiza
Alguém compartilhou nossa homepage /pt-br/ e o preview mostrou o título e imagem de um post aleatório. Disse:
quando compartilho o link https://blog.codeminer42.com/pt-br/ ele mostra o preview de um post, não deveria ser assim
Claude começou inspecionando as meta tags OG no DOM via evaluate_script. Isso confirmou o problema – mas aí veio o insight chave: crawlers sociais não executam JavaScript. Precisávamos testar o que o Facebook realmente vê:
curl -s https://blog.codeminer42.com/pt-br/
-H 'User-Agent: facebookexternalhit/1.1' | grep -E 'og:title|og:image'
A correção passou por três iterações, cada uma seguindo o mesmo loop: editar PHP localmente, executar testes, buildar zip, upload via página Plugins (Claude fez o upload toda vez), limpar cache, curl para verificar. Primeiro o título/descrição, depois descobrindo que AIOSEO não tem filtro para og:image, então usando output buffering para substituir a URL da imagem no HTML bruto.
O que eu realmente digito
Aqui está o que as pessoas perguntam: escrevo prompts detalhados? Não. Aqui estão coisas reais que digitei durante a sessão:
- “vamos adicionar o seletor de idioma e mostrar apenas posts daquele idioma na home”
- “o seletor de idioma deve aparecer no início da sidebar, não no final. os leitores devem vê-lo”
- “acabei de publicar o post pt br, posso te dizer. está aparecendo em https://blog.codeminer42.com/“
- “não, não é. seletor de idioma, quando clico em English, vai para /en, deveria ser /”
- “faça” (quando Claude perguntou se deveria fazer upload)
Claude descobre o resto. Lê a página, identifica o que precisa acontecer, e executa. Quando algo não funciona, descrevo o sintoma e Claude diagnostica.
O que faz isso diferente de automação de navegador
Já usei Puppeteer, Playwright, Selenium. Isso não é automação – é colaboração.
Com Puppeteer, você escreve um script que assume que a estrutura da página não mudará. Se a interface admin for atualizada, seu script quebra. Com MCP, Claude lê a página a cada execução, adapta-se a mudanças na UI, e lida com diálogos inesperados. Para algo como “verificar o customizer do tema por opções de exclusão de categoria”, você precisaria codificar todo caminho DOM com antecedência no Puppeteer. Claude navegou lá, abriu cada seção, leu as opções, e reportou que não havia nenhuma.
Combinado com edição de código. Na mesma sessão, Claude editou arquivos PHP localmente, executou 156 testes PHPUnit, buildou o plugin, E fez upload para produção através do navegador. O loop de feedback entre escrever código e ver funcionando é instantâneo.
Árvore de acessibilidade, não seletores. Elementos são identificados por papel semântico e conteúdo (uid=1_11 button "Log In"), não por classes CSS ou caminhos DOM que quebram quando a página muda.
Configurando
O servidor MCP está em github.com/anthropics/anthropic-mcp-tools/chrome-devtools. Instale-o:
npm install -g @anthropic/chrome-devtools-mcp
Então adicione à sua configuração MCP do Claude Code (.claude/settings.json ou .claude/settings.local.json):
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "@anthropic/chrome-devtools-mcp"]
}
}
}
Chrome precisa estar rodando com DevTools Protocol habilitado na porta 9222. Você pode iniciar manualmente:
open -na 'Google Chrome' --args
--remote-debugging-port=9222
--user-data-dir=/tmp/chrome-debug-profile
--no-first-run
--no-default-browser-check
Mas aqui está o problema – você vai esquecer. Sempre. E quando Claude tenta usar uma ferramenta chrome-devtools sem uma instância de debug rodando, falha silenciosamente ou gera um erro incompreensível. Então adicionei um hook do Claude Code que auto-inicia Chrome antes de qualquer chamada de ferramenta MCP:
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__chrome-devtools__",
"hooks": [
{
"type": "command",
"command": "if ! lsof -i :9222 -sTCP:LISTEN 2>/dev/null | grep -q '^Google'; then open -na 'Google Chrome' --args --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug-profile --no-first-run --no-default-browser-check >/dev/null 2>&1 & sleep 2; fi",
"timeout": 10,
"statusMessage": "Garantindo que Chrome debug está rodando..."
}
]
}
]
}
}
Isso vai no seu ~/.claude/settings.json sob a chave hooks. O matcher garante que só executa quando Claude está prestes a usar uma ferramenta chrome-devtools. O comando verifica se a porta 9222 já está escutando – se não, inicia uma instância Chrome debug fresca e aguarda 2 segundos para iniciar.
Problemas que enfrentei
O Chrome DevTools MCP ainda é relativamente novo. Aqui está o que realmente deu errado durante minhas sessões.
Screenshots muito grandes. O MCP tira screenshots constantemente para entender a página. Algumas páginas admin do WordPress produzem screenshots tão grandes que Claude dá erro com algo como “image too large”. Isso não aconteceu frequentemente, mas quando aconteceu tive que voltar a um ponto anterior na conversa, antes do screenshot gigante. Às vezes isso também não funcionava e tive que reabrir Claude Code completamente.
Pop-ups perdidos. Claude executa uma ação, um pop-up ou toast de erro aparece por um segundo, mas Claude estava executando um comando sleep ou esperando outra coisa. Quando verifica a página novamente, o pop-up sumiu e Claude não tem ideia do que aconteceu. Tive que intervir e dizer “apareceu um pop-up de erro” ou “verifique o console” para voltar ao rumo.
Esquecendo de verificar Network/Console. Claude nem sempre pensa em olhar as requisições de rede do navegador ou logs do console. Foca na página visível. Quando algo falhava silenciosamente – nenhum erro visível, apenas comportamento errado – tive que cutucá-lo: “verifique o console”, “verifique a aba network”, “olhe os logs.”
Funciona bem. Claude não preenche campos mais rápido que você, e também não “vê” a página mais rápido. Mas funciona numa velocidade boa o suficiente, e a vantagem real é que cada passo está integrado com o agente de codificação. Se Claude clica um botão e nada acontece, tenta outra coisa. Pode ler o console e já verificar o código para descobrir o que está acontecendo. Enquanto está fazendo sua coisa, você pode focar em outros trabalhos.
Quando fica perdido – perdeu um pop-up, esqueceu de verificar o console – você redireciona. Pense em pair programming onde você é o navegador, e Claude está dirigindo o browser. Não precisa assistir cada segundo, mas você verifica de vez em quando.
Por que continuo usando
O loop. Claude edita código, roda testes, builda um zip, faz upload para produção, limpa o cache, navega para a página, verifica se funciona, e se não, diagnostica por quê – tudo numa conversa. “A homepage está mostrando posts em português” leva a inspecionar cookies, limpá-los, verificar a correção, atualizar o código, e fazer redeploy. Sem Alt-Tab, sem esquecer o que estava debugando.
Obrigado pela leitura!
We want to work with you. Check out our Services page!

