Chromewright
Automação de navegador via Chrome DevTools Protocol
Documentação
chromewright
Chromewright é um servidor MCP de automação de navegador local-first construído sobre o Chrome DevTools Protocol (CDP). Ele expõe um navegador Chrome ou Chromium real a clientes MCP via stdio ou HTTP streamable em loopback, com ferramentas de alto nível para navegação, leitura de páginas, gerenciamento de abas, capturas de tela, emulação de viewport e interação limitada. A build padrão também inclui um navegador de terminal semântico e um companheiro MCP de loopback co-hospedado para seu estado de documento ao vivo.
Use o Chromewright quando um agente precisar de estado de navegador de um navegador real sem embutir uma pilha de automação Node.js ou escrever chamadas CDP brutas. O Chromewright não é um executor de testes de ponta a ponta; é uma camada de controle de navegador para agentes de IA e clientes MCP.
Quando usar o Chromewright
- Anexe um cliente MCP a um perfil Chrome ou Chromium existente em um endpoint DevTools.
- Inicie uma sessão de navegador local dedicada para trabalho de agente.
- Leia páginas por meio de snapshots, extração em markdown, inspeção direcionada e inventário de links.
- Navegue pelo DOM semântico de uma página localmente no terminal, com um companheiro MCP co-hospedado para seu documento ativo e estado de seleção.
- Conduza interações limitadas, como clique, entrada, seleção, passar o mouse, pressionar tecla, rolar e aguardar.
- Capture screenshots PNG gerenciados sem permitir que chamadores escolham caminhos de saída arbitrários.
- Reutilize handles
cursorcom escopo de revisão de snapshots em vez de depender apenas de seletores CSS.
Instalação
Chromewright requer Rust 1.88 ou mais recente quando você instala ou compila com Cargo.
Instale a partir do crates.io:
cargo install chromewright
Instale com Homebrew:
brew install bnomei/chromewright/chromewright
Instale a partir do código-fonte:
git clone https://github.com/bnomei/chromewright.git
cd chromewright
cargo install --path .
Você também pode baixar arquivos pré-compilados das GitHub Releases e colocar o binário chromewright no seu PATH.
Verifique se o binário está disponível:
chromewright --version
Saída esperada:
chromewright <version>
Quickstart
Este caminho inicia um perfil Chrome visível com DevTools habilitado e, em seguida, serve o Chromewright via HTTP em loopback em http://127.0.0.1:3000/mcp.
Pré-requisitos
chromewrightno seuPATH- Chrome, Chromium ou outro navegador compatível com CDP
- Um cliente MCP que suporte servidores HTTP streamable ou stdio
1. Inicie um perfil de navegador dedicado
No macOS, execute:
open -na "Google Chrome" --args \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/.chromewright-agent-profile"
Use um perfil dedicado quando não quiser que a automação do agente seja anexada à sua sessão de navegador pessoal. O modo de anexação padrão do Chromewright espera DevTools em http://127.0.0.1:9222.
2. Inicie o Chromewright
Execute o servidor HTTP streamable:
chromewright serve
Linha de log esperada:
Ready to accept MCP connections at http://127.0.0.1:3000/mcp
3. Conecte um cliente MCP
Para clientes configurados por JSON que suportam HTTP streamable:
{
"mcpServers": {
"chromewright": {
"transport": "streamable_http",
"url": "http://127.0.0.1:3000/mcp"
}
}
}
Para Codex via stdio, deixe o cliente iniciar o servidor:
[mcp_servers.chromewright]
command = "/absolute/path/to/chromewright"
enabled = true
Para Codex com o servidor HTTP de longa duração da etapa 2:
[mcp_servers.chromewright]
url = "http://127.0.0.1:3000/mcp"
enabled = true
4. Verifique com o cliente
Use seu cliente MCP para chamar tab_list. Uma sessão conectada deve retornar pelo menos uma aba com um tab_id estável. Se nenhuma aba ativa for útil, chame new_tab antes de chamar snapshot.
Modos de navegador
O Chromewright tem dois modos de navegador:
| Modo | Como iniciar | O que faz |
|---|---|---|
| Anexar | Execute chromewright ou chromewright serve sem flags de lançamento. | Conecta-se a http://127.0.0.1:9222 por padrão. |
| Anexar a outro endpoint | Passe --ws-endpoint <URL>. | Conecta-se a uma URL WebSocket de navegador ou uma origem HTTP DevTools, como http://127.0.0.1:9333. |
| Lançar | Passe qualquer flag de lançamento, como --user-data-dir, --headless, --executable-path ou --debug-port. | Inicia uma sessão de navegador local. O modo de lançamento é com interface gráfica, a menos que você passe --headless. |
Exemplos:
# Default: attach to http://127.0.0.1:9222 and serve MCP over stdio.
chromewright
# Serve streamable HTTP on the default loopback endpoint.
chromewright serve
# Serve streamable HTTP on a custom port and path.
chromewright serve --port 3333 --http-path /browser
# Attach to a different DevTools endpoint.
chromewright --ws-endpoint http://127.0.0.1:9333
# Launch a visible browser with a dedicated profile.
chromewright --user-data-dir /tmp/chromewright-profile
# Launch a headless browser and serve streamable HTTP.
chromewright --headless --user-data-dir /tmp/chromewright-profile serve
# Seed two managed tabs at startup. This works with attach, launch, serve, and tui modes.
chromewright --url https://example.com --url https://example.org serve
--url é repetível e semeia uma aba gerenciada separada para cada valor, na
ordem fornecida; a última aba semeada torna-se ativa. Aceita URLs absolutas
http:, https: e about:. URLs relativas, inseguras e relativas a protocolo
são rejeitadas antes que qualquer aba de inicialização seja aberta. No modo de anexação, as abas
existentes não são tocadas; apenas as abas semeadas tornam-se gerenciadas pelo chromewright.
Referência da CLI
| Opção ou comando | Padrão | Descrição |
|---|---|---|
chromewright | transporte stdio | Inicia o servidor MCP via stdio. |
chromewright serve | 127.0.0.1:3000/mcp | Inicia o servidor MCP via HTTP streamable em loopback. |
serve --port <PORT>, serve -p <PORT> | 3000 | Define a porta HTTP. |
serve --http-path <PATH> | /mcp | Define o caminho do endpoint HTTP. |
--ws-endpoint <URL> | http://127.0.0.1:9222 quando nenhuma flag de lançamento está presente | Conecta-se a uma URL WebSocket de navegador existente ou origem HTTP DevTools. Isso conflita com flags de lançamento. |
--headless | false | Lança um novo navegador em modo headless. |
--executable-path <PATH> | auto-detectado pelo backend do navegador | Usa um executável de navegador específico no modo de lançamento. |
--user-data-dir <DIR> | padrão do backend | Usa um diretório de perfil de navegador persistente no modo de lançamento. |
--debug-port <PORT> | auto-selecionado | Usa uma porta DevTools específica para um navegador lançado localmente. |
--url <URL> | nenhum; repetível | Semeia cada URL segura fornecida em sua própria aba gerenciada de inicialização. A última aba semeada é ativa. |
chromewright tui | (recurso tui, ativado por padrão) | Inicia o navegador de terminal semântico contra a mesma sessão de navegador. Sempre co-hospeda um companheiro MCP em loopback. |
tui --config <PATH> | $XDG_CONFIG_HOME/chromewright/tui.toml ou ~/.config/chromewright/tui.toml | Mapa de teclas TOML mais [theme] e [layout] opcionais. Um caminho explícito deve existir e ser analisado; um arquivo padrão ausente mantém as vinculações integradas. |
tui --companion-port <PORT> | 0 (efêmero) | Porta de loopback para o companheiro MCP co-hospedado via HTTP streamable. |
tui --companion-path <PATH> | /mcp | Caminho HTTP para o companheiro co-hospedado. |
--browser-session <reuse|restart> | reuse com --headless tui | Reutiliza ou substitui o navegador headless gerenciado do Chromewright. Válido apenas com --headless tui. |
Fonte: src/bin/mcp_server.rs.
Navegador de terminal (TUI)
A build padrão inclui um navegador de terminal semântico. Ele se anexa à mesma sessão de navegador do Chromewright e renderiza apenas conteúdo DOM semântico (não pixels, CSS ou layout do navegador).
# Attach to an existing DevTools endpoint (default http://127.0.0.1:9222).
chromewright tui
# Managed private headless Chrome for the normal terminal-browser flow.
chromewright --headless tui
Para conectar um cliente MCP ao companheiro co-hospedado, escolha um porta
de loopback fixa; a padrão 0 seleciona uma porta efêmera que o TUI não imprime.
chromewright --headless tui --companion-port 3334
[mcp_servers.chromewright_tui]
url = "http://127.0.0.1:3334/mcp"
enabled = true
O companheiro expõe oito ferramentas de coordenação tui_* e recursos semânticos
limitados. Os valores semantic_ref estão vinculados a uma revisão de documento; a captura ativa
mais as oito revisões anteriores são retidas, enquanto referências obsoletas ou
despejadas falham de forma fechada. As mensagens de atenção são limitadas a 512 caracteres.
Os recursos Markdown semânticos paginam em 32.000 caracteres por padrão e
limitam-se a 200.000; os recursos JSON falham em vez de retornar um documento truncado.
O cabeçalho é uma única barra semelhante a um navegador: ordinal de aba (2/5) à esquerda das setas de histórico, depois local/título, com um glifo de ciclo de vida à direita. As vinculações de teclado não são mostradas no terminal. Os padrões são compatíveis com Vimari. Sequências de múltiplas teclas, como gg e gi, aguardam o acorde completo; um prefixo não vinculado é rejeitado em vez de re-disparar a última tecla.
Mapa de teclas padrão
Padrões compatíveis com Vimari (foco no navegador), com aliases no estilo md-tui onde não colidem. Sobrepor uma ação substitui todas as suas sequências (primária + aliases).
| Chave | Nome da ação | Comportamento |
|---|---|---|
f / s | link_hints_follow | Entra no modo de dicas sobre links e controles de formulário visíveis no viewport; digite o rótulo de duas teclas. Links abrem na aba atual; campos de texto iniciam o modo de edição; outros controles são selecionados. Um rótulo por alvo (somente na primeira linha se houver quebra). (s = md-tui select-link.) |
F / S | link_hints_new_tab | Mesmos alvos que f; links abrem em uma nova aba (o modo de dicas permanece aberto para encadeamento até Esc). Alvos de formulário ainda selecionam/editam na aba atual. (S = md-tui select-link alt.) |
j / ↓ | scroll_down | Rola ou move a seleção um bloco para baixo. |
k / ↑ | scroll_up | Rola ou move a seleção um bloco para cima. |
h | scroll_left | Rolagem horizontal para a esquerda quando o conteúdo transborda. (Não é meia página do md-tui; tabelas/código do navegador precisam de pan.) |
l | scroll_right | Rolagem horizontal para a direita quando o conteúdo transborda. |
u / → | half_page_up | Move a visão meia página para cima (seleção inalterada). |
d / ← | half_page_down | Move a visão meia página para baixo (seleção inalterada). |
Ctrl-u | page_select_up | Move a seleção cerca de meia página para cima. |
Ctrl-d | page_select_down | Move a seleção cerca de meia página para baixo. |
gg | go_top | Salta para o topo do documento. (Um g único não está vinculado para que gi permaneça disponível.) |
G | go_bottom | Salta para o rodapé do documento. |
gi | focus_first_input | Foca o primeiro controle de formulário e inicia a edição. |
H / b | history_back | Voltar no histórico do navegador. (b = md-tui back.) |
L | history_forward | Avançar no histórico do navegador. |
r | reload | Recarrega a página ativa. |
[ | prev_tab | Alterna para a aba anterior do navegador. |
] | next_tab | Alterna para a próxima aba do navegador. |
x | close_tab | Fecha a aba atual. |
t | new_tab | Abre uma nova aba. |
o | open_url | Abre o prompt de entrada de URL com buffer vazio. Durante a edição, Tab / Shift-Tab aceita ou percorre o histórico local de URLs (o sufixo fantasma mostra a melhor correspondência). |
O | edit_url | Abre o prompt de entrada de URL pré-preenchido com o endereço atual (edite a partir do final). Mesma conclusão de histórico por Tab que o. |
/ | search | Inicia busca para frente por conteúdo semântico exato. (md-tui também vincula f à busca; mantemos f para dicas de link.) |
n | search_next | Repete a última busca para frente. |
N | search_previous | Repete a última busca para trás. |
Space | collapse | Recolhe ou expande o bloco selecionado. |
zw | toggle_wrap | Alterna quebra suave de linha (ativa por padrão). Quando ativa, linhas longas quebram no viewport e o pan horizontal de h/l fica desabilitado. |
zs | toggle_structure | Alterna prosa (padrão) vs projeção de estrutura. Prosa oculta o chrome de marcos/listas/grupos e achata o recuo; estrutura mostra contêineres estilo DOM. Recolhimento (Space) só funciona no modo estrutura. |
i | inspect | Abre um painel compacto de inspeção abaixo do bloco selecionado; o título é o caminho DOM completo (main > … > tag#id), o corpo tem campos de ação e ref/rev; segue a seleção até Esc. |
y | copy_block | Copia a seleção: URL de link/imagem (resolvida), caso contrário o texto renderizado do bloco (OSC 52). |
Y | copy_ref | Copia o semantic_ref opaco (OSC 52). |
Tab | tab_next | Próximo controle focalizável; grava o campo de saída no DOM vivo + patch do mesmo documento, depois move o foco. |
Shift-Tab | tab_prev | Controle focalizável anterior; mesmo comportamento de gravação ao sair que Tab. |
Enter | confirm | Entrada de texto: aplica o valor ao DOM vivo + patch do mesmo documento (sem envio necessário; busca ao vivo funciona). Caixa de seleção/rádio: alterna. Select: percorre opções. Botão de envio: grava campos preparados + clica + recaptura. Link/outro: ativa. |
Esc | escape | Sai do prompt, dica ou modo de inspeção. No modo Normal, também limpa o rodapé fixo /search (/{query} n/m). Após uma ação de página falha, dispensa Error de volta para Ready (a página retida permanece) para que as teclas voltem a funcionar. |
w | toggle_full_width | Alterna conteúdo em largura total vs a coluna content_max_width configurada (padrão 100, limitada por padrão). |
e | edit_external | Abre o markdown semântico da página atual em $VISUAL, depois $EDITOR, depois vi (somente leitura; o TUI suspende como o Nereid). |
q / Ctrl-c | quit | Sai do TUI. |
As dicas usam rótulos determinísticos de duas teclas do alfabeto asdfgqwertzxcvb (por exemplo aa, as), atribuídos a links e controles de formulário visíveis no viewport (um rótulo por alvo; pintado apenas na primeira linha quando um alvo quebra).
Após a navegação ou o follow de um link se estabilizar, um fragmento de URL como #section move a seleção do TUI para o componente correspondente (id, depois âncora nomeada), expande ancestrais recolhidos e o rola até a visualização. Fragmentos sem correspondência mantêm a seleção anterior.
O painel de conteúdo usa uma paleta de papéis ANSI-16 nativa do terminal (escada de títulos H1–H6 mais clara, links azuis, formulários ciano-claro, dicas amarelas) com seleção em vídeo reverso aplicada por último. As cores herdam o tema claro/escuro do terminal; substitua papéis individuais em [theme] em tui.toml. Por padrão, a área de markdown/conteúdo tem 1 coluna de padding esquerda/direita e está limitada a 100 colunas (centralizada; cabeçalho e rodapé permanecem em largura total); pressione w para largura total. Uma barra de rolagem de bloco estilo Amp de uma coluna fica à extrema direita da faixa de conteúdo. Substitua o layout em [layout] em tui.toml.
O modo de leitura padrão é prosa (semelhante a markdown): sem chrome de ▾ [main] / ol / grupo, linhas totalmente planas. Pressione zs para estrutura (contorno estilo DOM). Quebra (zw) e estrutura (zs) não aparecem na barra de cabeçalho; o feedback de alternância aparece na linha de status.
A busca segue a semântica do Vim: um novo /pattern começa após a seleção atual e envolve no final; n repete para frente, N repete para trás, e enviar um prompt / vazio repete o padrão anterior. O rodapé mostra a linha de comando enquanto digita (/…) e mantém /{pattern} n/m enquanto uma busca está ativa — pressione Esc no modo Normal para limpá-lo (Esc enquanto digita /… apenas cancela o prompt e mantém o padrão anterior para n/N). Dicas de link (f / F) também usam o rodapé (f as) em vez do cabeçalho. Colagem entre colchetes é aceita apenas em modos de URL, busca e entrada de formulário e é limitada a 4096 caracteres.
Keymap personalizado
Os vínculos podem ser substituídos por nome de ação. --config PATH tem precedência; se omitido, o Chromewright lê $XDG_CONFIG_HOME/chromewright/tui.toml, com fallback para ~/.config/chromewright/tui.toml. Um arquivo padrão ausente mantém os embutidos; um arquivo explicitamente solicitado deve ser analisado com sucesso.
# Only list keys you want to change. Unknown names or conflicting
# bindings abort startup rather than partially applying the overlay.
[keymap]
reload = "ctrl-r"
quit = "ctrl-q"
tab_prev = "shift-tab"
# Optional content-pane padding + column width (header/footer stay full width).
# Defaults: 1 col L/R, 0 row T/B, content_max_width = 100 (0 = always full).
# Press w to toggle full width vs the capped column.
[layout]
# content_padding_x = 1
# content_padding_y = 0
# content_max_width = 100
[theme]
# Optional ANSI names, reset, or #rrggbb — defaults already use a clear ladder.
# link = "blue"
# h1 = "lightblue"
# h2 = "green"
# h3 = "magenta"
# h4 = "cyan"
# h5 = "yellow"
# h6 = "lightred"
# form_control = "lightcyan"
# hint_label = "yellow"
As especificações de vínculo aceitam teclas únicas (r, space, esc, enter, tab), sequências de letras multi-tecla (gg, gi) e acordes com -, + ou separadores de espaço (ctrl-c, C-c, shift-tab). As teclas nomeadas suportadas incluem esc, enter, tab, backtab / shift-tab, backspace, teclas de seta, home, end, pageup / pgup, pagedown / pgdn, space e teclas de função como f1.
Papéis de tema: link, h1–h6, landmark, group, list, image, form_control, hint_label, muted, chrome_ready, chrome_loading, chrome_error, chrome_mode, attention_fg, attention_bg.
Chaves de layout: content_padding_x, content_padding_y (inserção simétrica apenas ao redor do painel de markdown/conteúdo), content_max_width (padrão 100; 0 desabilita o limite; w alterna total vs limitado).
A fonte da verdade para padrões é src/tui/keymap.rs e src/tui/action.rs.
Fluxo de trabalho da ferramenta
Um fluxo de trabalho típico de agente é:
- Chame
tab_listounew_tabpara estabelecer uma aba ativa. - Chame
snapshotpara ler a página atual e coletar nós acionáveis. - Prefira um
cursornovo desnapshotouinspect_nodeao mirar ações de acompanhamento. - Use
inspect_node,get_markdown,extractouread_linkspara leituras mais focadas. - Use
click,input,select,hover,press_key,scroll,waitou ferramentas de aba para interação limitada. - Chame
snapshotnovamente após navegação, ações que alteram o DOM, mudanças de viewport ou recuperação de alvo ambíguo.
snapshot suporta estes modos:
| Modo | Use quando |
|---|---|
viewport | Você quer a releitura local padrão do escopo visível atual. |
delta | Você quer a superfície local alterada quando existe um snapshot base anterior compatível. |
full | Você precisa de uma leitura exaustiva de toda a página. |
Ferramentas com alvo DOM aceitam um objeto público target:
{
"target": {
"kind": "selector",
"selector": "h1"
}
}
ou:
{
"target": {
"kind": "cursor",
"cursor": "<cursor from snapshot or inspect_node>"
}
}
Strings de seletor ainda são aceitas para compatibilidade por ferramentas que usam o tipo de alvo público, mas a forma de objeto é o contrato canônico.
Superfície de ferramentas MCP de produção
Sessões MCP de produção registram as ferramentas de alto nível padrão mais a ferramenta de operador protegida evaluate.
| Categoria | Ferramentas |
|---|---|
| Navegação | navigate, go_back, go_forward, wait |
| Interação e viewport | click, input, select, hover, press_key, scroll, set_viewport |
| Abas e ciclo de vida | new_tab, tab_list, switch_tab, close_tab, close |
| Leitura e inspeção | snapshot, inspect_node, get_markdown, extract, read_links |
| Artefatos gerenciados | screenshot |
| Diagnóstico de operador | evaluate |
evaluate executa JavaScript na página ativa e exige confirm_unsafe = true em cada chamada. Está disponível para diagnóstico e inspeção de escape hatch quando ferramentas limitadas não conseguem responder a uma pergunta específica da página.
Fonte: src/tools/core/mod.rs e src/browser/session.rs.
Capturas de tela e emulação de viewport
Use screenshot quando um chamador precisar de um artefato PNG gerenciado. A ferramenta aceita:
mode:viewport,full_page,elementouregionscale:deviceoucsstab_idopcionaltargetopcional para capturaselementregionopcional para capturasregionChamadas bem-sucedidas retornam metadados de artefatos gerenciados, incluindoartifact_uri,artifact_path,mime_type,byte_count, dimensões da imagem, dimensões CSS, proporção de pixels do dispositivo, escala de pixels,revealed_from_offscreene dados de recorte opcionais. Os chamadores não fornecem caminhos de saída.
Use set_viewport para emular breakpoints responsivos por meio do CDP. Chamadas bem-sucedidas retornam viewport_metrics_after; chamadas snapshot posteriores expõem as métricas em tempo real sob scope.viewport.
Limites de segurança
- O modo de anexação pode ver as abas, cookies e estado autenticado no perfil do navegador ao qual você se conecta.
- Use um perfil de navegador dedicado para trabalho de agente quando não quiser que a automação seja anexada a uma sessão pessoal do navegador.
evaluateexigeconfirm_unsafe = trueporque executa JavaScript arbitrário na página ativa.navigateenew_tabpermitemhttp:,https:,about:e caminhos relativos de mesma origem por padrão.data:,file:, outros esquemas absolutos e URLs relativas a protocolo exigemallow_unsafe = true.go_backego_forwardaplicam a mesma barreira de esquema inseguro e revertem movimentos de histórico rejeitados.close_tabexigeconfirm_destructive = trueantes de fechar uma aba ativa não gerenciada em uma sessão conectada.closeexigeconfirm_destructive = trueantes de expandir a limpeza da sessão conectada de abas gerenciadas para todas as abas.- Os alvos
cursorenode_reftêm escopo de revisão. Após navegação ou ações que alteram o DOM, atualize comsnapshot.
Métricas de operação
Resultados de ferramentas concluídas incluem metadados operation_metrics quando uma ferramenta registra métricas diferentes de zero. operation_metrics.output_bytes é opcional; aparece apenas quando um caminho de ferramenta mede o tamanho exato da saída serializada.
Os caminhos medidos podem incluir:
- contagem de avaliações do navegador
- iterações de polling
- contagem de extração de DOM e tempo de extração
- contagem do último nó do DOM
- tempo de renderização do snapshot
- contagem e tempo de reconstrução de handoff
- tamanho exato da saída serializada quando medido
Execute os testes focados de métricas de operação:
cargo test --locked --all-features operation_metrics
Desenvolvimento local
Compile a partir do código-fonte:
cargo build
Execute a suíte de testes normal:
cargo test
Execute a suíte de smoke do navegador a partir da raiz do repositório:
scripts/browser-smoke.sh
O script de smoke executa:
cargo test --test browser_smoke -- --nocapture
As verificações de smoke do navegador iniciam um navegador local e são destinadas a estações de trabalho de mantenedores. O CI cobre formatação, clippy, MSRV, cargo check, testes e empacotamento sem exigir um alvo de anexação de navegador ativo.
Âncoras de código-fonte
- Metadados do pacote e versão do Rust: Cargo.toml
- Flags e transportes da CLI: src/bin/mcp_server.rs
- Registro de ferramentas: src/tools/core/mod.rs
- Manipulador MCP: src/mcp/handler.rs
- Contrato público de alvo: src/contract/target.rs
- Contrato de captura de tela: src/tools/screenshot.rs
- Mapa de teclas padrão e ações da TUI: src/tui/keymap.rs, src/tui/action.rs
- Script de smoke do navegador: scripts/browser-smoke.sh
Licença
MIT