La mayoría de las plataformas de IA se conectan a servicios externos a través de APIs REST. Eso funciona para datos estructurados — leer un contacto de CRM, crear un ticket de Jira — pero pierde todo lo que sucede dentro del navegador. El borrador de correo en Gmail, el hilo de Slack que está leyendo, el formulario medio completado en ServiceNow.
Construimos una extensión de navegador que cierra esta brecha usando el Model Context Protocol (MCP). Esta publicación cubre las decisiones de arquitectura, los problemas que encontramos y cómo funciona el sistema de extremo a extremo.
El problema: el estado del navegador es invisible para las APIs
Las APIs le dan registros de base de datos. No le dan lo que está en pantalla. Un representante de ventas componiendo un correo de seguimiento en Gmail tiene contexto que ninguna API puede capturar — el tono, los párrafos a medio escribir, las pestañas abiertas junto a él. Queríamos que los flujos de trabajo de IA operaran sobre este contexto vivo del navegador de la manera en que un asistente humano sentado junto a usted lo haría.
Vista general de la arquitectura
La extensión está construida sobre WXT 0.20 (Manifest V3) con Svelte 5 y TypeScript. Implementa un cliente MCP que se conecta al servidor de JieGou vía WebSocket, exponiendo más de 60 herramientas de automatización de navegador que los flujos de trabajo de IA pueden invocar.
El flujo de mensajes se ve así:
Servidor MCP → WebSocket → Background Service Worker → Content Script → Página
Cuando una receta o flujo de trabajo necesita interacción con el navegador, envía una llamada de herramienta JSON-RPC 2.0 a través de la conexión WebSocket. El worker de fondo de la extensión la enruta al ejecutor de herramienta apropiado, que inyecta un content script en la pestaña activa y devuelve el resultado.
Puente WebSocket
El proxy WebSocket maneja autenticación, latidos, reconexión y renovación de tokens.
La autenticación ocurre al conectar — el cliente envía un mensaje authenticate con un token JWT. El servidor lo valida y comienza a aceptar llamadas de herramientas.
Los latidos se ejecutan cada 15 segundos a nivel de aplicación (sin depender de pings del protocolo WebSocket). Si un pong no llega en 5 segundos, la conexión se considera muerta y comienza la reconexión.
La auto-reconexión usa un retraso de 3 segundos en la desconexión con backoff exponencial. La renovación de token ocurre proactivamente 5 minutos antes del vencimiento del JWT vía un endpoint REST, para que la conexión nunca se interrumpa por credenciales expiradas.
Pipeline del ejecutor de herramientas
Todas las herramientas extienden una clase BaseBrowserToolExecutor que proporciona helpers comunes: injectContentScript() con deduplicación ping/pong, sendMessageToTab(), getActiveTabOrThrow() y gestión del foco de pestañas.
Las herramientas se agrupan en varias categorías:
Interacción con la página — click_element, fill_form_field, select_dropdown, check_box, scroll_page y navigate. Estas operan sobre elementos DOM identificados por selectores CSS o IDs de referencia auto-generados.
Lectura de contenido — read_page analiza el DOM y asigna IDs de referencia estables a elementos interactivos. Así es como la IA “ve” una página — obtiene texto estructurado con referencias clicables en lugar de HTML crudo.
Extractores específicos de plataforma — web_fetcher tiene parsers especializados para Gmail, Slack, Jira, Salesforce, ServiceNow y HubSpot. En lugar de scraping genérico del DOM, estos entienden la estructura de markup de cada plataforma y extraen datos limpios y tipados.
Internos del navegador — javascript ejecuta código arbitrario vía Chrome DevTools Protocol Runtime.evaluate, network_capture monitorea tráfico HTTP, screenshot captura el viewport o elementos específicos, y gif_recorder crea grabaciones animadas de interacciones multi-paso.
Scripts inyectados: ejecutándose en el mundo de la página
La parte más complicada de la arquitectura son los scripts inyectados. Los content scripts se ejecutan en un mundo aislado — pueden leer el DOM pero no pueden acceder al contexto JavaScript de la página, al estado de componentes React ni a los internos del framework.
Tenemos 16 módulos TypeScript que se empaquetan como IIFEs vía un plugin esbuild personalizado y se inyectan en el mundo MAIN. Esto les permite acceder a internos de React, llamar APIs a nivel de página e interactuar con routers de aplicaciones de una sola página.
La inyección usa deduplicación ping/pong para evitar inyectar el mismo script dos veces en una pestaña, y los resultados fluyen de vuelta a través de window.postMessage al content script, luego hasta el background worker.
Lo que aprendimos
Los service workers de Manifest V3 son efímeros. Pueden ser terminados en cualquier momento por el navegador. Tuvimos que hacer la conexión WebSocket resiliente a reinicios del service worker — reconectando de forma transparente sin perder llamadas de herramientas pendientes.
El parsing específico de plataforma supera al scraping genérico. Nuestra primera versión usaba extracción de DOM genérica para todo. El HTML de Gmail está profundamente anidado y cambia entre actualizaciones. Escribir parsers dirigidos para cada plataforma (6 hasta ahora) mejoró dramáticamente la confiabilidad y calidad de datos.
MCP es un buen protocolo para esto. La base JSON-RPC 2.0 con descubrimiento tools/list e invocación tipada tools/call es lo suficientemente simple de implementar pero lo suficientemente estructurada como para ser confiable. Hemos encontrado que es más fácil de extender que construir un protocolo personalizado.
Qué sigue
Estamos trabajando en expandir manejadores específicos de plataforma, mejorar la confiabilidad de targeting de elementos durante la navegación de aplicaciones de una sola página, y explorar formas de compartir definiciones de herramientas con el ecosistema MCP más amplio.
Si está construyendo integraciones MCP o herramientas de automatización de navegador, nos encantaría saber qué patrones le han resultado útiles. El protocolo todavía es joven y la comunidad está descubriendo las mejores prácticas juntos.