Skip to main content
Glama

blowsh-mcp

Servidor de Protocolo de Contexto Modelo para navegación de terminal compatible con JS mediante Browsh


¿Qué es blowsh-mcp?

blowsh-mcp es un servidor de Protocolo de Contexto Modelo (MCP) que expone el poder de Browsh —un navegador de terminal totalmente compatible con JavaScript— a cualquier agente de IA, agente de IDE o cliente MCP. Este proyecto permite que tu IA obtenga y renderice cualquier página web moderna, incluidas las que requieren JavaScript, y reciba el resultado como texto plano, HTML o Markdown fácilmente analizable.

Mnemotécnica: “blowsh” = servidor MCP impulsado por Browsh.


Related MCP server: openmcp

Características principales

  • Herramienta fetch_web: herramienta unificada para extraer texto plano legible, HTML o Markdown (tras el renderizado completo de JS). Admite extracción por selector CSS, límites de salida con max_chars y sondeo de estabilización de JS con wait_ms.

  • Herramienta search_web: descubre páginas mediante un motor de búsqueda renderizado (DuckDuckGo HTML con respaldo de Bing): resultados clasificados con URLs y fragmentos.

  • Herramienta extract_links: lista los hipervínculos (texto + URL absoluta) de cualquier página renderizada con JS para seguimiento de navegación.

  • Herramienta fetch_web_batch: obtiene hasta 10 URLs en una sola llamada con aislamiento de errores por URL.

  • Protección SSRF: rechaza solicitudes a direcciones de bucle local, privadas, link-local o reservadas (resueltas por DNS), protegiendo el navegador del lado del servidor.

  • Documentación de herramientas optimizada para IA: entradas, salidas y casos de uso ilustrados diseñados para una automatización fluida por parte del agente. Las herramientas lanzan errores estructurados con códigos de estado HTTP (isError en respuestas MCP).

  • Gestión robusta de Browsh: lanza Browsh una vez, lo mantiene en ejecución, reutiliza un singleton ligero en RAM/CPU y se apaga correctamente al salir.

  • Caché de renderizado en memoria con TTL: las obtenciones repetidas se sirven al instante sin volver a renderizar.

  • Diseñado para PaaS, Cloud, herramientas de IA locales y agentes de IDE.


Enlaces


Cómo funciona

  1. La IA/el agente realiza una solicitud MCP: fetch_web (URL única), search_web (consulta), extract_links (URL) o fetch_web_batch (hasta 10 URLs).

  2. blowsh-mcp lanza Browsh en modo servidor HTTP (en el primer uso) y lo reutiliza para todas las llamadas posteriores.

  3. blowsh-mcp solicita la salida sin procesar a Browsh, usando X-Browsh-Raw-Mode: PLAIN (para texto), DOM (para HTML), u obtiene HTML y luego lo convierte a Markdown.

  4. La página (tras la ejecución completa de JS) se devuelve como texto plano de terminal, DOM HTML enriquecido o Markdown limpio: la IA/el agente elige el tipo de salida según el procesamiento posterior.

  5. Los resultados se guardan en caché en memoria (TTL), por lo que las obtenciones repetidas son instantáneas; cada solicitud se verifica contra SSRF antes de llegar al navegador.


Inicio rápido (Docker — imagen precompilada)

La imagen se publica en GitHub Container Registry y se reconstruye automáticamente en cada push a main mediante GitHub Actions — no se necesita Firefox/Browsh/html2markdown en el host:

docker pull ghcr.io/mokhtarabadi/blowsh-mcp:latest
docker run --rm -i ghcr.io/mokhtarabadi/blowsh-mcp:latest

La bandera -i es obligatoria: el servidor MCP habla JSON-RPC a través de stdin/stdout. Manténla interactiva y canaliza las solicitudes, o apunta tu cliente MCP a ella (consulta Configuración de cliente IA más abajo).


Ejemplo de uso

Desde Claude, Cursor o cualquier agente compatible con MCP:

{
  "tool": "search_web",
  "params": { "query": "bitcoin price today", "max_results": 5 }
}
// → Ranked results with URLs + snippets → feed top URL to fetch_web

{
  "tool": "fetch_web",
  "params": { "url": "https://coindesk.com/price/bitcoin/", "type": "plain" }
}
// → Returns readable plain text (live price as text table, etc)

{
  "tool": "fetch_web",
  "params": { "url": "https://coindesk.com/price/bitcoin/", "type": "markdown", "selector": "main", "wait_ms": 3000 }
}
// → Markdown of <main> only, after JS settles ("# Bitcoin Price\n\n| Time | Price | ...")

{
  "tool": "extract_links",
  "params": { "url": "https://example.com", "limit": 20 }
}
// → [{"text": "Learn more", "url": "https://iana.org/domains/example"}, ...]

{
  "tool": "fetch_web_batch",
  "params": { "urls": ["https://a.com", "https://b.com"], "type": "markdown" }
}
// → Per-URL results; a failing page never fails the batch

La IA recibe:

  • Con type: plain: texto legible puro (tablas, listas, contenido principal; ideal para NLP/resúmenes o ingesta de contexto de terminal).

  • Con type: html: el marcado HTML completo, después de todo el JavaScript. Úsalo para analizar elementos, construir grafos de enlaces, scraping complejo, etc.

  • Con type: markdown: una versión limpia en Markdown, ideal para fragmentos de contexto de LLM, pipelines semánticos y consumos/flujos de trabajo compatibles con IA.

  • Los errores están estructurados: las respuestas MCP establecen isError: true con un mensaje FetchError que incluye el estado HTTP cuando está disponible.


Estructura del proyecto

  • src/server.ts — servidor MCP que expone herramientas.

  • src/browshManager.ts — lanza, supervisa y apaga Browsh.

  • src/tools/fetchWeb.ts — implementación de la herramienta fetchWeb (plain, html, markdown; selector/max_chars/wait_ms).

  • src/tools/searchWeb.ts — search_web (parser de DuckDuckGo HTML + respaldo de Bing).

  • src/tools/extractLinks.ts — extract_links (hipervínculos del DOM renderizado).

  • src/tools/fetchWebBatch.ts — fetch_web_batch (multi-URL, aislamiento de errores por URL).

  • src/tools/html2markdownManager.ts — envoltorio para el CLI de html2markdown.

  • src/ssrf.ts — protección SSRF (bloquea destinos privados/de bucle local/reservados).

  • src/cache.ts — caché de renderizado en memoria con TTL.

  • src/extract.ts — extracción de contenido principal, ayudantes de selector, truncamiento.

  • src/errors.ts — FetchError + formato de mensaje.

  • README.md — este archivo.

  • Dockerfile — contenedor multi-etapa (compila TS, incluye Firefox, Browsh, html2markdown).

  • .github/workflows/docker-publish.yml — CI/CD: compila y publica la imagen en ghcr.io en main/v*.

  • .env — anulaciones de configuración. Consulta .env.example para todas las opciones.


Instalación

Requisitos:

  • Node.js >= 20.18

  • Firefox instalado y en PATH

  • Browsh CLI instalado y en PATH

  • html2markdown CLI instalado y en PATH

    • En Debian/Ubuntu, instálalo con:

      wget -O /tmp/html2markdown.deb "https://github.com/JohannesKaufmann/html-to-markdown/releases/download/v2.5.2/html2markdown_2.5.2_linux_amd64.deb"
      sudo apt-get install -y /tmp/html2markdown.deb
      rm /tmp/html2markdown.deb
    • O usa el binario precompilado para tu sistema operativo desde la página de lanzamientos.

¿Prefieres Docker? Omite por completo las instalaciones en el host: la imagen multi-etapa incluye Firefox, Browsh y html2markdown. El camino más rápido es la imagen publicada (ghcr.io/mokhtarabadi/blowsh-mcp:latest, consulta Inicio rápido); para compilarla tú mismo:

docker build -t blowsh-mcp:latest .
docker run --rm -i blowsh-mcp:latest
git clone https://github.com/mokhtarabadi/blowsh-mcp.git
cd blowsh-mcp
npm install
npm run build

Ejecutar el servidor MCP

Después de compilar, inicia el servidor con:

node dist/server.js

Reemplaza dist/server.js con la ruta correcta si el resultado de tu compilación difiere.

Crea un archivo .env según sea necesario para la configuración. Por ejemplo:

MCP_TRANSPORT=stdio
BROWSH_FIREFOX_PATH=/usr/bin/firefox-esr
HTML2MARKDOWN_PATH=html2markdown
CACHE_TTL_MS=300000
BROWSH_REQUEST_TIMEOUT_MS=30000
ALLOW_PRIVATE_URLS=false
NODE_ENV=production
  • BROWSH_FIREFOX_PATH te permite personalizar el ejecutable de Firefox que usa Browsh durante la operación headless/HTTP.

  • HTML2MARKDOWN_PATH te permite especificar una ruta personalizada al binario html2markdown (por defecto: html2markdown en PATH).

  • CACHE_TTL_MS, BROWSH_REQUEST_TIMEOUT_MS y ALLOW_PRIVATE_URLS ajustan respectivamente la caché de renderizado, el tiempo de espera por solicitud y la protección SSRF.

  • El puerto/host HTTP de Browsh NO es configurable.


Documentación del proyecto

Archivo

Público

Propósito

AGENTS.md

Agentes

Reglas operativas, salvaguardas, ciclo de vida de tareas

DESIGN.md

Todos

Lenguaje de diseño de respuestas/salidas MCP

docs/architecture.md

Desarrolladores

Visión general del sistema, cableado de componentes

docs/data_model.md

Desarrolladores

Esquemas de entrada/salida de herramientas y modelo de errores

docs/conventions.md

Desarrolladores

Estándar de fecha/hora, directrices SOLID

CHANGELOG.md

Todos

Historial de versiones (Keep a Changelog)

tasks/

Equipo

Archivos de tareas Kanban (backlog → archive)

Este README es el punto de entrada orientado al usuario; las reglas orientadas al agente están en AGENTS.md y son de lectura obligatoria antes de cualquier implementación.


API de herramientas

Nombre

Parámetros

Caso de uso/Descripción para IA

fetch_web

{ url, type: "plain"|"html"|"markdown"|"pdf", selector?, max_chars?, wait_ms? }

Obtiene una página tras el renderizado JS como texto/HTML/Markdown. selector (CSS) extrae solo el elemento coincidente; max_chars limita la salida; wait_ms sondea hasta que JS se estabilice. type: pdf descarga el PDF directamente (máx. 20 MB) y extrae el texto mediante pdftotext; selector/wait_ms/max_chars no aplican.

search_web

{ query: string, max_results?: number, page?: number, enrich?: boolean }

Busca en la web (DuckDuckGo HTML + Bing renderizado de forma concurrente) y devuelve [{title, url, snippet, fetched_at}]. page del 1 al 10 para paginación; enrich: true reemplaza los 3 primeros fragmentos con contenido Markdown obtenido (presupuesto de 45 s). fetched_at es época UTC en ms para detectar obsolescencia. Alimenta las URLs de los resultados a fetch_web/extract_links.

extract_links

{ url: string, limit?: number }

Devuelve todos los hipervínculos ({text, url}, absolutos) presentes en una página renderizada con JS, para seguir la navegación sin volcados completos del DOM.

fetch_web_batch

{ urls: string[], type: "plain"|"html"|"markdown", selector?, max_chars?, wait_ms? }

Obtiene hasta 10 URLs en una sola llamada (consciente de caché). Devuelve por URL {url, ok, content|error}: un fallo nunca afecta al lote.

Valores devueltos

  • type: plain: texto legible, ejecutado con JS, estilo terminal (o cadena de error).

  • type: html: cadena de marcado HTML posterior a JS (o cadena de error). Con selector, solo el HTML del elemento coincidente.

  • type: markdown: conversión a Markdown del contenido principal o del elemento seleccionado (o cadena de error). Se conservan enlaces, encabezados, listas y la estructura de la página para un contexto compatible con IA.

  • type: pdf: texto plano extraído del documento PDF (mediante pdftotext, límite de 20 MB).

  • Los errores están estructurados: una respuesta MCP con isError: true y un mensaje FetchError que incluye el estado HTTP cuando es posible conocerlo (nunca una cadena vacía silenciosa).


Variables de entorno

Configúralas mediante .env (se carga automáticamente) o el entorno:

Variable

Predeterminado

Descripción

BROWSH_FIREFOX_PATH

firefox

Binario de Firefox utilizado por Browsh (p. ej. /usr/bin/firefox-esr).

HTML2MARKDOWN_PATH

html2markdown

Ruta al binario html2markdown.

BROWSH_REQUEST_TIMEOUT_MS

30000

Tiempo de espera de solicitud por renderizado (ms).

PDF_MAX_BYTES

20971520

Tamaño máximo de archivo PDF en bytes para fetch_web type: pdf.

BROWSH_RECYCLE_REQUESTS

100

Número de solicitudes tras el cual se recicla el proceso del navegador.

BROWSH_IDLE_TIMEOUT_MS

600000

Tiempo de inactividad en ms antes de que el proceso del navegador se cierre (10 min).

CACHE_TTL_MS

300000

TTL de la caché de renderizado en memoria (ms).

ALLOW_PRIVATE_URLS

false

Establezca true para deshabilitar la protección SSRF para destinos loopback/privados.

MCP_TRANSPORT

stdio

Tipo de transporte (solo stdio implementado).

NODE_ENV

production

Entorno de Node.


Selección de herramientas guiada por IA

  • Comience con search_web: Para descubrir páginas, ejecute una consulta y elija las mejores URL de resultados; luego obténgalas.

  • Use fetch_web para páginas individuales: plain cuando necesite una salida legible rápida para resumir/clasificar; html para analizar elementos, enlaces o tablas; markdown para fragmentos de contexto aptos para LLM. Añada selector/max_chars/wait_ms para mantener la eficiencia de tokens y obtener contenido estable y relevante.

  • Use extract_links antes de rastreos profundos: Siga la navegación de forma económica en lugar de obtener DOM completos.

  • Use fetch_web_batch para múltiples fuentes: Una sola llamada en lugar de N idas y vueltas; los fallos se aíslan por URL.

Manejo de errores: Las herramientas lanzan FetchError y MCP devuelve isError: true con un mensaje procesable: los protocolos no válidos, los bloqueos de SSRF, los selectores sin coincidencias, los códigos de estado HTTP y los fallos de renderizado nunca son silenciosos.


Protocolo MCP: Configuración del cliente de IA

Antes de configurar su cliente de IA (Claude, Cursor, etc.), debe

  1. Instale las dependencias:    npm install

  2. Compile el proyecto:    npm run build

  3. Inicie el servidor MCP desde la salida compilada:    node dist/server.js

Ejemplo de configuración para Claude Desktop o Cursor:

{
  "mcpServers": {
    "blowsh": {
      "command": "node",
      "args": ["dist/server.js"],
      "env": {}
    }
  }
}

Ejemplo de configuración para opencode (proyecto opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "blowsh": {
      "type": "local",
      "command": ["docker", "run", "--rm", "-i", "ghcr.io/mokhtarabadi/blowsh-mcp:latest"],
      "enabled": true,
      "timeout": 120000
    }
  },
  "permission": { "blowsh_*": "allow" }
}

La modalidad Docker no necesita binarios en el host; la imagen incluye Firefox, Browsh y html2markdown. Reinicie opencode después de guardar (la configuración se carga una vez al inicio).


Apagado ordenado

blowsh-mcp captura SIGINT/SIGTERM y garantiza que Browsh se cierre limpiamente: sin navegadores huérfanos.


Seguridad y consideraciones

  • El servidor ejecuta Browsh localmente y recupera contenido mediante HTTP localhost.

  • Protección SSRF: De forma predeterminada, fetch_web/search_web/extract_links/fetch_web_batch rechazan URL que resuelven a rangos de IP loopback, privados, de enlace local o reservados (verificados mediante DNS). Establezca ALLOW_PRIVATE_URLS=true para deshabilitarla; no se recomienda.

  • Sin exposición pública a menos que el servidor MCP HTTP/streamable esté explícitamente configurado.

  • Nunca exponga puertos a la web abierta sin firewall.

  • Utilice variables de entorno para secretos/configuración.


Extensión

Añada nuevas herramientas en src/tools/, expórtelas en src/server.ts, y documéntelas.
Los clientes de IA descubrirán automáticamente los docstrings.


Solución de problemas

  • Si fetchPlain devuelve 404 o no puede renderizar JS: compruebe que Firefox y Browsh están instalados y en el PATH.

  • Si Firefox no se encuentra o no se puede iniciar, establezca BROWSH_FIREFOX_PATH en .env para especificar la ruta completa a su instalación de Firefox.

  • El puerto y el host de Browsh son fijos: no hay ninguna opción de entorno ni de CLI para cambiarlos.

  • Para máxima seguridad, ejecútelo en un contenedor.


Licencia

MIT


Autor: Mohammad Reza Mokhtarabadi mmokhtarabadi@gmail.com

Available Tools

1 tool
fetch_webFetch Web (plain, html, markdown)A

Fetch a web page and return its content as plain text, HTML, or Markdown. Uses a JS-capable browser for dynamic sites.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesThe HTTP/HTTPS web URL to fetch
typeYesThe output type: plain, html, or markdown

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden for behavioral traits. It discloses the use of a JS-capable browser, which is critical for understanding behavior with dynamic sites. It does not mention rate limits or error handling, but the core behavioral trait is well covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loading the main purpose and adding the browser capability as a key differentiator. Every sentence earns its place without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 2 simple parameters, no output schema, and no annotations, the description is sufficient. It covers the purpose, output types, and a notable behavior (JS browser). Minor missing details like response size limits or timeout are not critical for a basic fetch tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with both parameters well described. The description adds 'plain text, HTML, or Markdown' but that is a restatement of the enum values. No additional nuance is provided beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (fetch a web page) and the resource (web page content), and specifies three output types (plain, HTML, Markdown). It distinguishes the tool by mentioning JS-capable browser for dynamic sites, which sets it apart from simple fetchers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool vs alternatives or when not to use it. Given no sibling tools are listed, it is minimally adequate but lacks context like 'use for public pages only' or 'prefer for dynamic content'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev1.0.0
    • First observedfetch_web

TDQS

A4.1/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of ambiguity between tools. The tool's purpose is clear and distinct.

Naming Consistency5/5

The single tool name 'fetch_web' follows a clear verb_noun pattern. With only one tool, there is no inconsistency to evaluate.

Tool Count3/5

A single tool is borderline for a server. While it serves a specific purpose, it feels thin compared to typical MCP servers that offer multiple related operations.

Completeness4/5

The tool provides core web fetching functionality with output format options. A minor gap might be the lack of custom headers or request methods, but agents can work around this for most use cases.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    F
    maintenance
    A Model Context Protocol server that enables AI agents to fetch live web content with JavaScript rendering, proxy rotation, and anti-bot evasion.
    9
    79 npm
    58
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to automate web tasks such as browsing, clicking, typing, and taking screenshots via the Model Context Protocol.
    1
    MIT