Voltar as noticias
De mock-only-works para real-world-works: 48 horas de depuração do reCAPTCHA
MCP ProtocolMediaEN

De mock-only-works para real-world-works: 48 horas de depuração do reCAPTCHA

Dev.to - MCP·24 de maio de 2026

Primeiro, uma estrutura honesta: mk-qa-master é um servidor MCP de código aberto para engenheiros de QA. O solucionador de reCAPTCHA nele é um fallback de Nível 3 para testar seus próprios aplicativos quando o Nível 1 (as chaves de teste oficiais do Google) e o Nível 2 (flags de recurso / lista de permissões de IP) não estão disponíveis. Ele não é uma ferramenta para "burlar captcha". Ele se recusa a rodar em páginas de login do Google / Apple / Microsoft / Discord, independentemente da flag de consentimento. Com isso esclarecido…

Este é um diário sobre as 48 horas que levei para passar de "enviei um solucionador de reCAPTCHA, todos os testes unitários passaram" para "ele realmente funciona contra a demonstração real do Google." Quatro versões (v0.7.0v0.7.4), três intermediárias quebradas e um monte de lições que quero registrar antes de esquecer.

A configuração

A ideia por trás do solucionador é simples. Duas ferramentas MCP atômicas:

  • inspect_visual_challenge — encontra o iframe do captcha na página atual, tira uma captura de tela, retorna as coordenadas da grade de azulejos + uma captura de tela.
  • solve_visual_challenge — aceita a seleção de azulejos do cliente de IA (quais azulejos contêm ônibus, quais contêm faixas de pedestres, etc.), clica neles, pressiona Verificar, retorna o token.

O cliente de IA (Claude Code, Cursor, etc.) vê a captura de tela, decide quais azulejos correspondem ao prompt e chama a solução. O servidor é os olhos e as mãos; a IA é o cérebro. Modelos multimodais como Claude 4.7 são surpreendentemente bons nisso — eles foram treinados na web aberta, que tem muitas fotos de ônibus.

Até agora, tudo bem na teoria.

Dia 1 — v0.7.0 é lançado

A primeira versão foi lançada na segunda-feira. Ela detectou o reCAPTCHA iframe[src*="bframe"], tirou uma captura de tela, calculou as coordenadas dos azulejos dividindo a caixa delimitadora do iframe em uma grade de 3×3 ou 4×4 e clicou no centro de cada azulejo selecionado.

Os testes unitários passaram. O fixture de mock empacotado (uma página HTML autônoma que imita a estrutura do reCAPTCHA) funcionou de ponta a ponta. Eu escrevi um PRD, lancei uma versão, postei um Dev.to walkthrough. Foi ótimo.

A estrutura do fixture de mock era:

<table class="rc-imageselect-table">
  <tr><td>...</td><td>...</td><td>...</td></tr>
  ...
</table>

Seletores na impressão digital:

"tile_table_selector": ".rc-imageselect-table",
"tile_cell_selector": "td",

O que poderia dar errado?

Dia 2 — v0.7.1 adiciona hCaptcha

No dia seguinte, estendi a tabela de impressão digital para suportar hCaptcha. Mesma arquitetura — seletores diferentes. Nenhuma nova ferramenta MCP. Os testes permaneceram verdes. Eu me senti bem sobre o design: quando um fornecedor muda, você adiciona uma linha à tabela de impressão digital, e pronto.

Eu também não fiz um teste real para hCaptcha. (Voltaremos a isso.)

Dia 3 — v0.7.2: o primeiro "conserto"

Eu escrevi um pequeno script de dogfood — abri o Chromium, naveguei até https://www.google.com/recaptcha/api2/demo, cliquei no link para acionar um desafio de imagem, chamei inspect_visual_challenge, salvei a captura de tela, pedi à IA os índices dos azulejos, chamei solve_visual_challenge, vi se um token voltava.

A primeira execução retornou com status falhou. Perguntei ao usuário (neste caso: eu) o que ele viu no navegador. A resposta foi inquietante: "Eu disse para clicar 2, 5 e 8 — apenas 5 e 8 realmente foram destacados."

Eu investiguei a matemática das coordenadas. A abordagem de divisão do iframe dividiu o iframe completo em células de linhas × colunas. Mas o iframe contém um banner de cabeçalho (o texto do prompt) acima da grade e um rodapé (o botão Verificar) abaixo. Então:

  • Para uma grade de 3×3 em um iframe de 400×580 com cabeçalho ~130px e rodapé ~130px:
    • A grade real tem 320px de altura, ~106px por linha.
    • A divisão ingênua do iframe dá 193px por linha.
    • O centro computado da linha 0 cai no banner do cabeçalho.
    • O centro computado da linha 2 cai no rodapé.
    • Apenas a linha 1 acontece de estar aproximadamente correta.

Eu escrevi v0.7.2 para corrigir isso. Em vez de dividir o iframe, eu leria o bounding_box() real de cada célula do DOM via Playwright:

for index in range(tile_count):
    bb = cells.nth(index).bounding_box()
    if not is_real_dict(bb):
        # voltar para a divisão do iframe para fixtures de mock
        break
    candidate.append({"viewport_x": bb["x"], ...})

O teste unitário (contra o fixture de mock) imediatamente confirmou a correção. Eu aumentei para v0.7.2, abri um PR, mesclei, lancei, publiquei no PyPI. Pronto.

Dia 4 de manhã — espere, ainda está quebrado

No dia seguinte, executei o dogfood novamente. Saída do console para inspect:

"tiles": [
  {"index": 0, "viewport_x": 85, "viewport_y": 92,  "w": 133, "h": 193},
  {"index": 1, "viewport_x": 218,
Contexto Triplo Up

O desenvolvimento de soluções para reCAPTCHA pode impactar empresas brasileiras que dependem de testes de software. A capacidade de simular interações com captchas pode acelerar o desenvolvimento e a validação de aplicações web. Isso é especialmente relevante em um cenário onde a automação e a eficiência são cruciais.

Noticias relacionadas

Gostou do conteudo?

Receba toda semana as principais novidades sobre WebMCP.