Skip to main content
Glama

blowsh-mcp

Сервер Model Context Protocol для терминального браузера с поддержкой JS на базе Browsh


Что такое blowsh-mcp?

blowsh-mcp — это сервер Model Context Protocol (MCP), который открывает возможности Browsh — полностью поддерживающего JavaScript терминального браузера — для любого AI-агента, IDE-агента или MCP-клиента. Этот проект позволяет вашему ИИ получать и отображать любые современные веб-страницы, в том числе требующие JavaScript, и получать результат в виде легко разбираемого обычного текста, HTML или Markdown.

Мнемоника: «blowsh» = MCP-сервер на базе Browsh.


Related MCP server: openmcp

Ключевые возможности

  • Инструмент fetch_web: единый инструмент для извлечения читаемого обычного текста, HTML или Markdown (после полного рендеринга JS). Поддерживает извлечение по CSS selector, ограничение вывода max_chars и опрос wait_ms для ожидания завершения JS.

  • Инструмент search_web: поиск страниц через отрендеренную поисковую систему (DuckDuckGo HTML с запасным вариантом Bing) — ранжированные результаты с URL и сниппетами.

  • Инструмент extract_links: выводит список гиперссылок (текст + абсолютный URL) с любой JS-отрендеренной страницы для последующей навигации.

  • Инструмент fetch_web_batch: загрузка до 10 URL за один вызов с изоляцией ошибок по каждому URL.

  • Защита SSRF: отклоняет запросы к loopback, частным, link-local или зарезервированным адресам (с резолвингом DNS), защищая серверный браузер.

  • AI-оптимизированная документация инструментов: входные и выходные данные, а также иллюстрированные примеры использования, предназначенные для бесшовной автоматизации агентов. Инструменты генерируют структурированные ошибки с HTTP-статус кодами (isError в ответах MCP).

  • Надёжное управление Browsh: запускает Browsh один раз, поддерживает его работу, переиспользует лёгкий по RAM/CPU синглтон, корректно завершает работу при выходе.

  • Кэш рендеринга в памяти с TTL: повторные запросы обслуживаются мгновенно без повторного рендеринга.

  • Разработан для PaaS, облака, локальных AI-инструментов и IDE-агентов.


Ссылки


Как это работает

  1. AI/агент отправляет MCP-запрос: fetch_web (один URL), search_web (запрос), extract_links (URL) или fetch_web_batch (до 10 URL).

  2. blowsh-mcp запускает Browsh в режиме HTTP-сервера (при первом использовании) и переиспользует его для всех последующих вызовов.

  3. blowsh-mcp запрашивает исходный вывод от Browsh, используя X-Browsh-Raw-Mode: PLAIN (для текста), DOM (для HTML), или получает HTML и затем преобразует его в Markdown.

  4. Страница (после полного выполнения JS) возвращается как терминальный обычный текст, насыщенный HTML DOM или чистый Markdown — AI/агенты выбирают тип вывода в соответствии с дальнейшей обработкой.

  5. Результаты кэшируются в памяти (TTL), поэтому повторные запросы выполняются мгновенно; каждый запрос проверяется на SSRF перед отправкой в браузер.


Быстрый старт (Docker — готовый образ)

Образ публикуется в GitHub Container Registry и автоматически пересобирается при каждом пуше в main через GitHub Actions — не требуется устанавливать Firefox/Browsh/html2markdown на хосте:

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

Флаг -i обязателен: MCP-сервер общается по JSON-RPC через stdin/stdout. Оставьте его интерактивным и передавайте запросы через конвейер или укажите ваш MCP-клиент на него (см. Конфигурация AI-клиента ниже).


Пример использования

Из Claude, Cursor или любого 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

AI получает:

  • С type: plain: чистый читаемый текст (таблицы, списки, основное содержимое; идеально для NLP/суммаризации или приёма в терминал).

  • С type: html: полная HTML-разметка после выполнения всего JavaScript. Используйте для разбора элементов, построения графа ссылок, сложного скрейпинга и т.д.

  • С type: markdown: чистая Markdown-версия — лучше всего подходит для контекстных блоков LLM, семантических конвейеров и AI-ориентированного потребления/рабочих процессов.

  • Ошибки структурированы: MCP-ответы устанавливают isError: true с сообщением FetchError, включающим HTTP-статус, когда он доступен.


Структура проекта

  • src/server.ts — MCP-сервер, предоставляющий инструменты.

  • src/browshManager.ts — Запуск, мониторинг и завершение Browsh.

  • src/tools/fetchWeb.ts — Реализация инструмента fetchWeb (plain, html, markdown; selector/max_chars/wait_ms).

  • src/tools/searchWeb.ts — search_web (парсер DuckDuckGo HTML + запасной вариант Bing).

  • src/tools/extractLinks.ts — extract_links (гиперссылки из отрендеренного DOM).

  • src/tools/fetchWebBatch.ts — fetch_web_batch (несколько URL, изоляция ошибок по каждому URL).

  • src/tools/html2markdownManager.ts — Обёртка для CLI html2markdown.

  • src/ssrf.ts — Защита SSRF (блокирует частные/loopback/зарезервированные цели).

  • src/cache.ts — Кэш рендеринга в памяти с TTL.

  • src/extract.ts — Извлечение основного содержимого, вспомогательные функции для selector, усечение.

  • src/errors.ts — FetchError + форматирование сообщений.

  • README.md — Этот файл.

  • Dockerfile — Многоступенчатый контейнер (собирает TS, включает Firefox, Browsh, html2markdown).

  • .github/workflows/docker-publish.yml — CI/CD: собирает и публикует образ в ghcr.io при пушах в main/v*.

  • .env — Переопределения конфигурации. Все опции см. в .env.example.


Установка

Требования:

  • Node.js >= 20.18

  • Firefox установлен и доступен в PATH

  • Browsh CLI установлен и доступен в PATH

  • html2markdown CLI установлен и доступен в PATH

    • На Debian/Ubuntu установите с помощью:

      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
    • Или используйте готовый бинарный файл для вашей ОС со страницы релизов.

Предпочитаете Docker? Полностью пропустите установку на хосте — многоступенчатый образ включает Firefox, Browsh и html2markdown. Самый быстрый путь — опубликованный образ (ghcr.io/mokhtarabadi/blowsh-mcp:latest, см. Быстрый старт); чтобы собрать его самостоятельно:

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

Запуск MCP-сервера

После сборки запустите сервер, используя:

node dist/server.js

Замените dist/server.js на правильный путь, если вывод вашей сборки отличается.

При необходимости создайте файл .env для конфигурации. Например:

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 позволяет настроить исполняемый файл Firefox, используемый Browsh во время headless/HTTP-работы.

  • HTML2MARKDOWN_PATH позволяет указать свой путь к бинарному файлу html2markdown (по умолчанию: html2markdown в PATH).

  • CACHE_TTL_MS, BROWSH_REQUEST_TIMEOUT_MS и ALLOW_PRIVATE_URLS настраивают соответственно кэш рендеринга, тайм-аут запроса и защиту SSRF.

  • HTTP-порт/хост Browsh не настраиваются.


Документация проекта

Файл

Аудитория

Назначение

AGENTS.md

Агенты

Правила работы, ограничения, жизненный цикл задач

DESIGN.md

Все

Язык дизайна ответов/вывода MCP

docs/architecture.md

Разработчики

Обзор системы, соединение компонентов

docs/data_model.md

Разработчики

Схемы ввода/вывода инструментов и модель ошибок

docs/conventions.md

Разработчики

Стандарт DateTime, рекомендации SOLID

CHANGELOG.md

Все

История версий (Keep a Changelog)

tasks/

Команда

Файлы задач Kanban (backlog → archive)

Этот README — пользовательская точка входа; правила для агентов находятся в AGENTS.md и обязательны к прочтению перед любой реализацией.


API инструментов

Имя

Параметры

AI Вариант использования/Описание

fetch_web

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

Загружает одну страницу после JS-рендеринга как текст/HTML/Markdown. selector (CSS) извлекает только соответствующий элемент; max_chars ограничивает вывод; wait_ms опрашивает до завершения JS. type: pdf загружает PDF напрямую (макс. 20 МБ) и извлекает текст через pdftotext — selector/wait_ms/max_chars не применяются.

search_web

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

Выполняет поиск в Интернете (DuckDuckGo HTML + Bing, рендеринг параллельно) и возвращает [{title, url, snippet, fetched_at}]. page 1–10 для пагинации; enrich: true заменяет первые 3 сниппета загруженным Markdown-содержимым (бюджет 45 с). fetched_at — время в UTC epoch мс для определения устаревания. Передавайте URL результатов в fetch_web/extract_links.

extract_links

{ url: string, limit?: number }

Возвращает все гиперссылки ({text, url}, абсолютные), присутствующие на JS-отрендеренной странице, для последующей навигации без полного дампа DOM.

fetch_web_batch

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

Загружает до 10 URL за один вызов (с учётом кэша). Возвращает по каждому URL {url, ok, content|error} — одна ошибка никогда не прерывает весь пакет.

Возвращает

  • type: plain: терминальный, выполненный через JS читаемый текст (или строка ошибки).

  • type: html: строка HTML-разметки после JS (или строка ошибки). С selector — только HTML соответствующего элемента.

  • type: markdown: преобразование основного содержимого или выбранного элемента в Markdown (или строка ошибки). Ссылки, заголовки, списки и структура страницы сохраняются для AI-ориентированного контекста.

  • type: pdf: извлечённый обычный текст из PDF-документа (через pdftotext, лимит 20 МБ).

  • Ошибки структурированы: MCP-ответ с isError: true и сообщением FetchError, включающим HTTP-статус, когда он известен (никогда не бывает молчаливой пустой строки).


Переменные окружения

Задайте их через .env (загружается автоматически) или через окружение:

Переменная

По умолчанию

Описание

BROWSH_FIREFOX_PATH

firefox

Бинарный файл Firefox, используемый Browsh (например, /usr/bin/firefox-esr).

HTML2MARKDOWN_PATH

html2markdown

Путь к бинарному файлу html2markdown.

BROWSH_REQUEST_TIMEOUT_MS

30000

Таймаут запроса на рендеринг (мс).

PDF_MAX_BYTES

20971520

Максимальный размер PDF-файла в байтах для fetch_web type: pdf.

BROWSH_RECYCLE_REQUESTS

100

Количество запросов, после которого процесс браузера перезапускается.

BROWSH_IDLE_TIMEOUT_MS

600000

Время простоя в мс до завершения процесса браузера (10 мин).

CACHE_TTL_MS

300000

TTL кэша рендеринга в памяти (мс).

ALLOW_PRIVATE_URLS

false

Установите true, чтобы отключить защиту SSRF для loopback/частных адресов.

MCP_TRANSPORT

stdio

Тип транспорта (реализован только stdio).

NODE_ENV

production

Среда Node.js.


Выбор инструментов с помощью ИИ

  • Начните с search_web: Чтобы обнаружить страницы, выполните запрос и выберите лучшие URL-адреса результатов; затем загрузите их.

  • Используйте fetch_web для отдельных страниц: plain — когда нужен быстрый читаемый вывод для суммаризации/классификации; html — для разбора элементов, ссылок или таблиц; markdown — для удобных для LLM фрагментов контекста. Добавляйте selector/max_chars/wait_ms, чтобы экономить токены и получать стабильный релевантный контент.

  • Используйте extract_links перед глубоким обходом: Следуйте по навигации без лишних затрат, вместо загрузки полных DOM-деревьев.

  • Используйте fetch_web_batch для нескольких источников: Один вызов вместо N обращений; сбои изолированы для каждого URL.

Обработка ошибок: Инструменты выбрасывают FetchError, а MCP возвращает isError: true с практическим сообщением — недопустимые протоколы, блокировки SSRF, несовпадающие селекторы, коды состояния HTTP и ошибки рендеринга никогда не остаются незамеченными.

Протокол MCP: настройка ИИ-клиента

Перед настройкой вашего ИИ-клиента (Claude, Cursor и т.д.) необходимо

  1. Установить зависимости: npm install

  2. Собрать проект: npm run build

  3. Запустить MCP-сервер из скомпилированного вывода: node dist/server.js

Пример конфигурации для Claude Desktop или Cursor:

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

Пример конфигурации для opencode (файл проекта 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" }
}

Docker-вариант не требует бинарных файлов на хосте; образ включает Firefox, Browsh и html2markdown. Перезапустите opencode после сохранения (конфигурация загружается один раз при запуске).

Плавное завершение работы

blowsh-mcp перехватывает SIGINT/SIGTERM и гарантирует чистое завершение Browsh — без осиротевших процессов браузера.

Безопасность и рекомендации

  • Сервер запускает Browsh локально и выполняет запросы через HTTP localhost.

  • Защита SSRF: По умолчанию fetch_web/search_web/extract_links/fetch_web_batch отказываются от URL-адресов, которые разрешаются в loopback, частные, link-local или зарезервированные IP-диапазоны (проверяется через DNS). Установите ALLOW_PRIVATE_URLS=true, чтобы отключить — не рекомендуется.

  • Нет публичного доступа, если явно не настроен MCP HTTP/streamable сервер.

  • Никогда не открывайте порты в открытый веб без межсетевого экрана.

  • Используйте переменные окружения для секретов/конфигурации.

Расширение

Добавляйте новые инструменты в src/tools/, экспортируйте их в src/server.ts и документируйте.
ИИ-клиенты автоматически найдут docstrings.

Устранение неполадок

  • Если fetchPlain возвращает 404 или не удаётся отрендерить JS: проверьте, что Firefox и Browsh установлены и находятся в PATH.

  • Если Firefox не найден или не запускается, установите BROWSH_FIREFOX_PATH в .env, указав полный путь до вашей установки Firefox.

  • Порт/хост Browsh фиксированы — нет ни переменной окружения, ни параметра CLI для их изменения.

  • Для максимальной безопасности запускайте в контейнере.

Лицензия

MIT

Автор: 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