a48e262371
Documenta los cambios de la v0.8.0 en el app.md del browser_mcp: - Bump de versión 0.7.0 -> 0.8.0 y descripción (45 -> 46 tools, mención del modo de velocidad de sesión). - Sección Tools (46): añade browser_set_mode en el grupo Sesión. - Capability growth log: entrada v0.8.0 detallando el flag de velocidad, el settle adaptativo, la escritura insertText en auto, el poll del puerto en launch_profile, los enable cacheados, wait_load por evento, el timeout de sendCDP y las nuevas CdpInsertText/CdpTypeRefFast, con los números del smoke contra Chrome 9333.
351 lines
22 KiB
Markdown
351 lines
22 KiB
Markdown
---
|
|
name: browser_mcp
|
|
lang: go
|
|
domain: infra
|
|
version: 0.8.0
|
|
description: "Servidor MCP que expone control total del navegador via CDP (46 tools: navegación, DOM, cookies, iframes, teclado/scroll, diálogos, estado de sesión, selección determinista de pestaña, modo de velocidad de sesión (browser_set_mode: 'auto' rápido por defecto / 'human' sigiloso anti-detección), lectura compacta texto/AX nativa + bucle percibir→actuar por #ref con auto-observe, percepción y lectura de texto dentro de iframes, click por coordenadas, screenshot devuelto como image content que el LLM ve, y gestión del ciclo de vida de Chromium por perfil: listar masters en ejecución, lanzar un perfil concreto con o sin CDP, y cerrar limpio) reusando funciones del dominio browser del registry con un pool de conexiones CDP vivas. Por defecto opera sobre un Chrome aislado (puerto 9333) separado del navegador diario."
|
|
tags: [mcp, browser, cdp, automation, scraping]
|
|
e2e_checks:
|
|
- id: build
|
|
cmd: "cd projects/web_scraping/apps/browser_mcp && go build -o browser_mcp ."
|
|
timeout_s: 120
|
|
- id: unit
|
|
cmd: "cd projects/web_scraping/apps/browser_mcp && go test -count=1 ./..."
|
|
timeout_s: 120
|
|
- id: leak_no_orphans
|
|
cmd: "cd projects/web_scraping/apps/browser_mcp && go test -c -o /tmp/bmcp_e2e.test . && systemd-run --user --quiet --collect --unit=bmcp_e2e_ci --wait -p Type=oneshot --setenv=BMCP_E2E=1 -p StandardOutput=journal /tmp/bmcp_e2e.test -test.run TestE2E -test.v"
|
|
timeout_s: 180
|
|
severity: warning
|
|
uses_functions:
|
|
- chrome_launch_go_browser
|
|
- cdp_connect_go_browser
|
|
- cdp_close_go_browser
|
|
- cdp_navigate_go_browser
|
|
- cdp_list_tabs_go_browser
|
|
- cdp_new_tab_go_browser
|
|
- cdp_close_tab_go_browser
|
|
- cdp_activate_tab_go_browser
|
|
- cdp_nav_back_go_browser
|
|
- cdp_nav_forward_go_browser
|
|
- cdp_wait_load_go_browser
|
|
- cdp_wait_idle_go_browser
|
|
- cdp_get_html_go_browser
|
|
- cdp_evaluate_go_browser
|
|
- cdp_screenshot_go_browser
|
|
- cdp_click_go_browser
|
|
- cdp_click_human_go_browser
|
|
- cdp_click_text_go_browser
|
|
- cdp_type_text_go_browser
|
|
- cdp_find_by_text_go_browser
|
|
- cdp_find_ref_by_text_go_browser
|
|
- cdp_wait_element_go_browser
|
|
- cdp_press_key_go_browser
|
|
- cdp_scroll_go_browser
|
|
- cdp_handle_dialog_go_browser
|
|
- cdp_set_cookie_go_browser
|
|
- cdp_get_cookies_go_browser
|
|
- cdp_delete_cookies_go_browser
|
|
- cdp_clear_cookies_go_browser
|
|
- cdp_list_frames_go_browser
|
|
- cdp_eval_in_frame_go_browser
|
|
- cdp_get_frame_html_go_browser
|
|
- cdp_save_storage_state_go_browser
|
|
- cdp_load_storage_state_go_browser
|
|
- cdp_get_text_go_browser
|
|
- cdp_get_text_in_frame_go_browser
|
|
- cdp_connect_target_go_browser
|
|
- cdp_get_ax_outline_go_browser
|
|
- cdp_screenshot_bytes_go_browser
|
|
- cdp_click_ref_go_browser
|
|
- cdp_type_ref_go_browser
|
|
- cdp_hover_ref_go_browser
|
|
- cdp_click_xy_human_go_browser
|
|
uses_types: []
|
|
framework: ""
|
|
entry_point: "main.go"
|
|
dir_path: "projects/web_scraping/apps/browser_mcp"
|
|
repo_url: ""
|
|
---
|
|
|
|
# browser_mcp
|
|
|
|
Servidor MCP (Model Context Protocol) en Go que expone el control de navegador via CDP
|
|
del registry `fn_registry` como tools MCP. Cualquier cliente MCP (Claude Code, otros
|
|
agentes) puede manejar un Chrome/Chromium vivo: navegar, leer el DOM, hacer clicks,
|
|
gestionar cookies, evaluar JavaScript, operar iframes y persistir/restaurar sesiones.
|
|
|
|
Clona el patrón de `apps/registry_mcp/` (librería `github.com/mark3labs/mcp-go` v0.52.0,
|
|
`server.NewMCPServer` + `server.ServeStdio`, tools con `mcp.NewTool` + handlers tipados
|
|
via `mcp.NewTypedToolHandler`, transporte stdio por defecto + HTTP opcional con `--http`,
|
|
slog a stderr porque stdout pertenece al JSON-RPC).
|
|
|
|
## Arquitectura: pool de conexiones CDP
|
|
|
|
A diferencia de `registry_mcp` (que abre la DB una vez), `browser_mcp` mantiene un
|
|
**pool de conexiones CDP vivas** indexado por puerto (`pool.go`). Razón:
|
|
`browser.CdpConnect(port)` hace un handshake WebSocket contra una tab "page" de Chrome
|
|
(~50-200ms) y esa conexión ES una sesión viva (soporta `Page.*`, `Runtime.*`, `Input.*`).
|
|
El agente llama muchas tools seguidas (navigate → wait → click → eval); reconectar en
|
|
cada tool pagaría el handshake repetidamente y perdería estado entre tools (los event
|
|
handlers persistentes, como el de `handle_dialog`, viven mientras la conexión esté viva).
|
|
Por eso reusamos la conexión por puerto.
|
|
|
|
- `connPool.get(port)` devuelve la conexión cacheada o abre una nueva.
|
|
- `connPool.drop(port)` cancela el handler de diálogo (si lo hay) y cierra la conexión.
|
|
- `connPool.connectTarget(port, match)` descarta la conexión actual y reconecta a un target
|
|
determinista (por id o substring de URL). Es lo que usa `tab_select` para fijar la pestaña.
|
|
- `connPool.setCancel(port, cancel)` registra el cancel del auto-handler de `handle_dialog`.
|
|
- `connPool.closeAll()` se ejecuta con `defer` en `main()`.
|
|
- `deps.withConn(port, fn)` ejecuta `fn` con la conexión del pool y, si el error indica
|
|
conexión muerta (`isConnErr`: connection close, broken pipe, use of closed, ws read, EOF),
|
|
descarta la conexión y reintenta UNA vez (Chrome pudo cerrar la tab entre tools).
|
|
|
|
Toda tool con argumento `port` usa `portOr(a.Port)` (default 9333). Las tools de tabs
|
|
(`tab_list`, `tab_new`, `tab_close`, `tab_activate`, `tab_select`) usan el endpoint HTTP `/json`
|
|
de CDP directamente (host `localhost`), no el pool, porque no requieren una sesión WebSocket viva.
|
|
|
|
## Seguridad: Chrome aislado por defecto (puerto 9333)
|
|
|
|
**El default del MCP es operar sobre su PROPIO Chrome aislado, no sobre el navegador diario.**
|
|
|
|
En este ecosistema el chromium diario del usuario tiene CDP habilitado globalmente en el
|
|
puerto **9222** (via `/etc/chromium.d/cdp`). Si el MCP usara 9222 por defecto, el agente
|
|
podría manipular pestañas ajenas del usuario (banca, correo). Para evitarlo:
|
|
|
|
- `portOr` devuelve **9333** por defecto (no 9222) — el Chrome dedicado del MCP.
|
|
- `browser_launch` sin `user_data_dir` usa un perfil DEDICADO y aislado:
|
|
`<tmp>/browser_mcp_userdata` (se crea si hace falta) en el puerto 9333.
|
|
- Para adjuntarte deliberadamente al navegador diario, pasa `port: 9222` explícito en cada
|
|
tool. Hazlo solo con cuidado.
|
|
|
|
## Tools (46)
|
|
|
|
### Sesión (`tools_session.go`)
|
|
- `browser_launch` (MUTA) — lanza Chrome con CDP. args: port, headless, user_data_dir, url.
|
|
- `browser_connect` — abre/poolea la conexión CDP del puerto. args: port.
|
|
- `browser_disconnect` — cierra y descarta la conexión del puerto (no mata Chrome). args: port.
|
|
- `browser_set_mode` — fija el modo de velocidad de sesión del puerto: `auto` (default, rápido) o `human` (sigiloso anti-detección). args: port, mode. Cada tool de acción puede overridearlo con su arg `mode`.
|
|
|
|
### Ciclo de vida por perfil (`tools_lifecycle.go`)
|
|
Gestionan los Chromium del USUARIO por perfil (`Personal`, `Work`, ...), distintos del Chrome
|
|
de automatización aislado de `browser_launch`. Las instancias lanzadas aquí NO se registran en el
|
|
pool: son de uso humano y sobreviven a la muerte del MCP; se cierran explícitamente con
|
|
`browser_close`.
|
|
- `browser_list` — lista los procesos MASTER de Chromium en ejecución (con `--user-data-dir`,
|
|
SIN `--type=`). Para cada uno: pid, profile, user_data_dir, cdp_port, has_cdp. Devuelve JSON
|
|
array. Read-only. args: (ninguno).
|
|
- `browser_launch_profile` (MUTA) — lanza Chromium para un perfil concreto en la pantalla del
|
|
usuario, usando el binario REAL `/usr/lib/chromium/chromium` (salta el wrapper). Con `cdp=false`
|
|
(default) NO añade flags de remote-debugging — necesario para perfiles humanos (Google mantiene
|
|
la sesión; con CDP la trata como automatizada y la tira). Con `cdp=true` añade
|
|
`--remote-debugging-port` + `--remote-allow-origins=*`. Detecta DISPLAY/XAUTHORITY de la sesión
|
|
XFCE y lanza DESACOPLADO (setsid). Si un master ya posee el user_data_dir, Chromium reenvía la
|
|
apertura a él (`note` en el resultado). args: profile (requerido), user_data_dir
|
|
(default `~/.config/chromium-cdp`), url, cdp (default false), cdp_port (default 9222).
|
|
- `browser_close` (MUTA) — cierra un master limpio. Lo localiza por `profile`, `cdp_port` o `pid`.
|
|
Envía SIGTERM, espera hasta 10s, y SIGKILL como último recurso (indicado en `method`). Devuelve
|
|
{closed, pid, method}. args: uno de profile, cdp_port o pid.
|
|
|
|
### Navegación + tabs (`tools_nav.go`)
|
|
- `tab_navigate` (MUTA) — `Page.navigate`. args: port, url.
|
|
- `tab_list` — lista targets via `GET /json`. args: port.
|
|
- `tab_new` (MUTA) — abre tab via `PUT /json/new`. args: port, url.
|
|
- `tab_close` (MUTA) — cierra tab por ID. args: port, tab_id.
|
|
- `tab_activate` — pone tab en foreground. args: port, tab_id.
|
|
- `tab_select` — fija la pestaña sobre la que operan las siguientes tools, eligiéndola por id
|
|
o por substring de su URL (determinista). Usar tras `tab_list` para no operar sobre la
|
|
pestaña equivocada. args: port, match.
|
|
- `nav_back` (MUTA) — atrás en el historial. args: port.
|
|
- `nav_forward` (MUTA) — adelante en el historial. args: port.
|
|
- `page_wait_load` — espera el evento load. args: port, timeout_ms (default 10000).
|
|
- `page_wait_idle` — espera red idle. args: port, timeout_ms (default 15000).
|
|
|
|
### Lectura (`tools_read.go`)
|
|
- `page_get_html` — HTML serializado (truncado a 200000 chars). args: port.
|
|
- `page_get_text` — texto visible (innerText) de la página o de un elemento (selector CSS),
|
|
truncado a `max_bytes`. Preferir sobre `page_get_html` cuando solo necesitas leer contenido
|
|
— no revienta el contexto. args: port, selector (opcional), max_bytes (default 20000).
|
|
- `page_perceive` — outline indentado y accionable del árbol de accesibilidad (roles, nombres,
|
|
`#ref`): la forma compacta de que el agente "perciba" la página sin reventar el contexto.
|
|
**Nativo en Go** sobre la conexión CDP viva del pool (`cdp_get_ax_outline_go_browser`) — ya
|
|
no lanza subprocess `fn run` ni levanta el venv de Python. Para elegir la pestaña usa `tab_select`
|
|
ANTES (la conexión del pool ya está fijada a esa pestaña); el campo `tab_id` queda obsoleto y se
|
|
ignora (se conserva por compatibilidad). Si se pasa `frame_id`, percibe DENTRO de ese iframe
|
|
(obtén el id con `frame_list`). args: port, tab_id (obsoleto), frame_id (opcional), max_chars (default 20000).
|
|
- `page_eval_js` (MUTA) — `Runtime.evaluate`. args: port, expression.
|
|
- `page_screenshot` — captura la página y la **devuelve como image content** para que el LLM vea los
|
|
píxeles (vía `cdp_screenshot_bytes_go_browser`, sin tocar disco). Si se pasa `path`, además guarda la
|
|
imagen en ese archivo; el image content se devuelve siempre. Útil cuando el outline de `page_perceive`
|
|
no basta (canvas, mapas, layouts visuales): mira la captura y actúa con `dom_click_xy`. args: port,
|
|
path (opcional), full_page.
|
|
|
|
### DOM (`tools_dom.go`)
|
|
- `dom_click` (MUTA) — click por selector. args: port, selector.
|
|
- `dom_click_human` (MUTA) — click con movimiento humano. args: port, selector.
|
|
- `dom_click_text` (MUTA) — click sobre el primer elemento con ese texto. args: port, text.
|
|
- `dom_type` (MUTA) — escribe texto en el elemento enfocado. args: port, text.
|
|
- `dom_find_by_text` — devuelve un selector CSS único para un texto visible. args: port, text.
|
|
- `dom_wait_element` — espera a que aparezca un selector. args: port, selector, timeout_ms (default 10000).
|
|
- `dom_click_ref` (MUTA) — click humanizado por `#ref` (backendDOMNodeId del outline de `page_perceive`) + auto-observe. args: port, ref, mode.
|
|
- `dom_type_ref` (MUTA) — enfoca el `#ref` y escribe texto + auto-observe. args: port, ref, text.
|
|
- `dom_hover_ref` (MUTA) — hover humanizado por `#ref` + auto-observe. args: port, ref, mode.
|
|
- `dom_click_xy` (MUTA) — fallback de click por coordenadas absolutas (x, y en CSS pixels del viewport) con
|
|
movimiento humanizado por defecto. Pensado para usarse sobre lo que el agente VE en `page_screenshot`
|
|
cuando el outline no basta (canvas, mapas, layouts visuales); prefiere `dom_click_ref` cuando el elemento
|
|
aparece en el outline. Devuelve el outline actualizado (auto-observe). args: port, x, y, mode.
|
|
|
|
#### Bucle percibir→actuar (por `#ref`)
|
|
|
|
`page_perceive` devuelve un outline accionable (generado de forma nativa en Go
|
|
sobre la conexión CDP viva) donde cada elemento lleva un `#ref` estable (su
|
|
`backendDOMNodeId`). Las tools `dom_click_ref` / `dom_type_ref` / `dom_hover_ref`
|
|
actúan directamente sobre ese `#ref` — no necesitas resolver un selector CSS.
|
|
Tras la acción esperan un settle breve (400ms) y **devuelven el outline
|
|
actualizado** (auto-observe, truncado a 8000 chars), cerrando el bucle
|
|
percibir→actuar:
|
|
|
|
```
|
|
page_perceive → outline con #ref de cada elemento
|
|
dom_click_ref → click humanizado + outline nuevo tras la acción
|
|
dom_type_ref → escribe + outline nuevo
|
|
```
|
|
|
|
Cuando el elemento no aparece en el outline (canvas, mapas, layouts puramente
|
|
visuales), el fallback es **mirar** con `page_screenshot` (que devuelve la imagen
|
|
al LLM) y **actuar** por coordenadas con `dom_click_xy`, que también devuelve el
|
|
outline tras el click.
|
|
|
|
Las tools `*_ref` y `dom_click_xy` aceptan `mode` (`human` por defecto con
|
|
Bézier+jitter anti-bot, `fast` para scraping masivo, `instant` sin movimiento de
|
|
ratón). La humanización es el default en todas para no facilitar la detección.
|
|
|
|
### Input (`tools_input.go`) — todas MUTA
|
|
- `press_key` — presiona una tecla nombrada (Enter/Tab/Escape/ArrowDown/...). args: port, key.
|
|
- `scroll` — scroll por (delta_x, delta_y). args: port, delta_x (default 0), delta_y (default 300).
|
|
- `handle_dialog` — arma un auto-handler de diálogos JS (vive en la conexión del pool). args: port, accept (default true), prompt_text.
|
|
|
|
### Cookies (`tools_cookies.go`)
|
|
- `cookie_get` — todas las cookies como JSON. args: port.
|
|
- `cookie_set` (MUTA) — set cookie. args: port, name, value, domain, path, http_only.
|
|
- `cookie_delete` (MUTA) — borra cookies por nombre. args: port, name, domain.
|
|
- `cookie_clear` (MUTA) — borra todas las cookies. args: port.
|
|
|
|
### Iframes (`tools_frames.go`)
|
|
- `frame_list` — lista frames con sus IDs. args: port.
|
|
- `frame_eval` (MUTA) — evalúa JS dentro de un frame. args: port, frame_id, expression.
|
|
- `frame_get_html` — HTML de un frame (truncado a 200000). args: port, frame_id.
|
|
- `frame_get_text` — texto visible (innerText) de un iframe, truncado a `max_bytes`. Para leer
|
|
contenido atrapado dentro de un iframe — `page_get_text` solo cubre el documento de nivel superior.
|
|
args: port, frame_id, max_bytes (default 20000).
|
|
|
|
### Estado de sesión (`tools_storage.go`)
|
|
- `storage_save` — guarda cookies + localStorage a JSON. args: port, path.
|
|
- `storage_load` (MUTA) — carga cookies + localStorage desde JSON. args: port, path.
|
|
|
|
## Cómo lanzarlo
|
|
|
|
Transporte stdio (default, para clientes MCP):
|
|
|
|
```bash
|
|
cd projects/web_scraping/apps/browser_mcp
|
|
go build -o browser_mcp .
|
|
./browser_mcp
|
|
```
|
|
|
|
Transporte HTTP (Streamable HTTP):
|
|
|
|
```bash
|
|
./browser_mcp --http :7740 # bind 127.0.0.1:7740
|
|
./browser_mcp --http :7740 --bind 0.0.0.0 # requiere REGISTRY_API_TOKEN (bearer auth)
|
|
```
|
|
|
|
### Flag `--read-only`
|
|
|
|
Con `--read-only`, el servidor NO registra las tools mutantes (marcadas MUTA arriba):
|
|
solo expone las 20 tools de lectura/control (`browser_connect`, `browser_disconnect`, `browser_list`,
|
|
`tab_list`, `tab_activate`, `tab_select`, `page_wait_load`, `page_wait_idle`, `page_get_html`,
|
|
`page_get_text`, `page_perceive`, `page_screenshot`, `dom_find_by_text`, `dom_find_ref_by_text`,
|
|
`dom_wait_element`, `cookie_get`, `frame_list`, `frame_get_html`, `frame_get_text`, `storage_save`).
|
|
Útil para sesiones de inspección sin riesgo de modificar el estado del navegador.
|
|
|
|
## Omitido en v1
|
|
|
|
Funciones del dominio `browser` que NO se exponen como tools en esta versión, con su razón:
|
|
|
|
- **`cdp_har_record_go_browser`** — graba el tráfico de red (HAR). Requiere un callback de
|
|
larga duración (registrar handlers + un punto de "stop" que devuelve los datos
|
|
acumulados); no encaja en el modelo request/response de una tool MCP simple. Pendiente
|
|
de un diseño con tool de start + tool de stop.
|
|
- **`cdp_get_ax_tree`** — expuesto via la tool `page_perceive`. Desde v0.6.0 el outline se genera
|
|
de forma **nativa en Go** (`cdp_get_ax_outline_go_browser`) sobre la conexión CDP viva del pool;
|
|
ya no se invoca el pipeline Python `cdp_perceive_outline` por subprocess (`fn run`). El acceso al
|
|
árbol AX en bruto sigue sin exponerse: la tool devuelve directamente el outline accionable.
|
|
- **Funciones de perfiles Chrome (Bash: create/delete/appearance/reset)** — requieren que
|
|
Chrome esté CERRADO para modificar el `Local State` / `Preferences` del perfil; son
|
|
incompatibles con un MCP cuyo propósito es controlar un Chrome vivo. Quedan disponibles
|
|
como `fn run` aparte.
|
|
|
|
## Capability growth log
|
|
|
|
- v0.8.0 (2026-06-13) — Aceleración del manejo del navegador via CDP + flag de velocidad de
|
|
sesión. (1) Nueva tool `browser_set_mode` (45 → 46 tools): fija el modo de velocidad por puerto
|
|
en el pool — `auto` (default del MCP, rápido) vs `human` (sigiloso anti-detección). El modo se
|
|
resuelve por acción con `effectiveMode`: arg `mode` de la tool > modo de sesión > `auto`. (2) Settle
|
|
adaptativo: el sleep ciego fijo de 400ms tras cada acción mutante (`dom_click_ref`/`dom_type_ref`/
|
|
`dom_hover_ref`/`dom_click_xy`) pasa a `settleForMode` — 60ms en `auto`, aleatorio 250-650ms en
|
|
`human` (ritmo no-máquina), 0 en `instant`. (3) `dom_type_ref` ahora tiene arg `mode`: en `auto`
|
|
usa `CdpTypeRefFast` (`Input.insertText`, un solo round-trip) y en `human` teclea carácter a
|
|
carácter (`CdpTypeRef`) con pausas aleatorias. (4) `browser_launch_profile` reemplaza el `sleep(1s)`
|
|
ciego por un poll del puerto CDP (`waitCDPPort`). Cambios en el dominio `browser` del registry que
|
|
aprovecha el MCP: `Accessibility.enable`/`Network.enable`/`Page.enable` cacheados por conexión
|
|
(`ensureAX`/`ensureNetwork`/`ensurePage` en `CDPConn`) — se eliminan round-trips redundantes en cada
|
|
percepción/espera; `cdp_wait_load` pasa de polling de `document.readyState` cada 200ms a esperar el
|
|
evento `Page.loadEventFired` (fast path si ya está `complete`); `sendCDP` adquiere timeout
|
|
(`cdpCmdTimeout` 30s) para no colgar el tool indefinidamente; nuevas `CdpInsertText` y
|
|
`CdpTypeRefFast` (camino rápido de escritura); el modo `auto` se añade al perfil de ratón
|
|
(`MouseProfileForMode`) como alias rápido de `fast`. Smoke contra Chrome 9333: percepción #2 con
|
|
enable cacheado 1.7ms (vs 3.7ms la #1), `wait_load` fast-path 245µs (vs ≥200ms del polling previo).
|
|
- v0.7.0 (2026-06-10) — Ciclo de vida de Chromium por perfil (`tools_lifecycle.go`). Tres tools
|
|
nuevas: `browser_list` (enumera los procesos master de Chromium leyendo `/proc/*/cmdline`,
|
|
filtrando por `--user-data-dir` presente y `--type=` ausente), `browser_launch_profile` (lanza un
|
|
perfil concreto con el binario REAL `/usr/lib/chromium/chromium` para saltar el wrapper, con/sin
|
|
CDP — sin CDP por defecto para que Google mantenga la sesión de perfiles humanos; detecta
|
|
DISPLAY/XAUTHORITY de la sesión XFCE y lanza desacoplado con setsid) y `browser_close` (localiza el
|
|
master por profile/cdp_port/pid, SIGTERM con espera de 10s, SIGKILL como último recurso). Las
|
|
instancias por perfil NO se registran en el pool: son de uso humano y sobreviven a la muerte del
|
|
MCP. 42 → 45 tools.
|
|
- v0.6.0 (2026-06-06) — Percepción visual y de iframes + perceive nativo. (1) `page_perceive` se
|
|
generó hasta ahora por subprocess `fn run cdp_perceive_outline` (Python); ahora es **nativo en Go**
|
|
sobre la conexión CDP viva del pool (`cdp_get_ax_outline_go_browser`) — mata el subprocess, el venv
|
|
y la dependencia del binario `fn` en runtime (se eliminó `resolveRoot`/`exec.Command`). (2) Acceso a
|
|
datos dentro de iframes: nueva tool `frame_get_text` (innerText de un iframe, `cdp_get_text_in_frame_go_browser`)
|
|
y nuevo parámetro `frame_id` en `page_perceive` para percibir DENTRO de un iframe. (3) Click por
|
|
coordenadas absolutas: nueva tool `dom_click_xy` (`cdp_click_xy_human_go_browser`), humanizada por
|
|
defecto, pensada para actuar sobre lo que el LLM ve en una captura. (4) `page_screenshot` ahora
|
|
**devuelve la imagen como image content** (vía `cdp_screenshot_bytes_go_browser` + `mcp.NewToolResultImage`)
|
|
para que el LLM vea los píxeles; `path` pasa a ser opcional (si se da, además guarda a disco). (5) El
|
|
auto-observe de las tools `*_ref` subió su truncado de 4000 a 8000 chars (outlines grandes se cortaban).
|
|
(6) Fix de seguridad documental: todas las descripciones del parámetro `port` que decían "Default 9222"
|
|
(el navegador diario del usuario) corregidas a "Default 9333" (Chrome aislado del MCP); el código ya
|
|
usaba 9333, la doc era falsa y podía inducir al modelo a tocar pestañas de banca/correo. 40 → 42 tools.
|
|
- v0.5.0 (2026-06-06) — Fix del leak de RAM (chromium huérfanos, apagón 06/06/2026). El pool
|
|
ahora registra el PID del Chrome que lanzó por puerto (`pids` map + setPID/getPID/clearPID/
|
|
launchedCount). `browser_disconnect` (drop) y el shutdown (closeAll) matan el grupo de proceso
|
|
completo SOLO si el PID está registrado (lo lanzó el MCP) — un Chrome externo (navegador diario
|
|
en 9222) nunca se mata, solo se cierra el WebSocket. `browser_launch` es idempotente por puerto,
|
|
reusa un Chrome ya vivo (`ChromeLaunch.ReuseExisting`, pid 0 = no relanza) y aplica un tope duro
|
|
de 4 instancias. Handler SIGTERM/SIGINT en main.go llama closeAll (los defers no corren con
|
|
señal). `withConn` retry usa `releaseConn` (suelta solo el WS) en vez de drop. Tests: pool_test.go
|
|
(lógicos) + pool_e2e_test.go (Chrome real, gate BMCP_E2E=1). e2e_checks añadidos.
|
|
- v0.3.0 (2026-06-06) — Cierre del bucle percibir→actuar. Nuevas tools `dom_click_ref`,
|
|
`dom_type_ref`, `dom_hover_ref`: actúan sobre el `#ref` (backendDOMNodeId estable) del
|
|
outline de `page_perceive` con humanización por defecto (Bézier+jitter) y auto-observe
|
|
(devuelven el outline actualizado tras la acción). Refactor: la generación del outline
|
|
se extrajo a `deps.perceiveOutline`/`perceiveOutlineTab`, reusado por `page_perceive` y
|
|
por las tools `*_ref`. 36 → 39 tools.
|
|
- v0.2.0 (2026-06-06) — P0 LLM-readiness. Seguridad: Chrome aislado por defecto (puerto 9333
|
|
+ perfil dedicado `<tmp>/browser_mcp_userdata`), separado del navegador diario en 9222.
|
|
Nuevas tools: `tab_select` (selección determinista de pestaña por id/URL), `page_get_text`
|
|
(lectura compacta de innerText), `page_perceive` (outline AX via `fn run cdp_perceive_outline`).
|
|
33 → 36 tools.
|