Skip to main content
Glama
TrueNix

agent-browser

by TrueNix

agent-browser

Укреплённый локальный браузер для ИИ-агентов. Ноль зависимостей. Управляет уже установленным Chrome через DevTools Protocol, извлекает эффективный по токенам Markdown и не так просто распознаётся как автоматизация.

Способ

Установка

Для чего

MCP-сервер

npx -y @truenix/agent-browser mcp

Claude Code, Cursor, Codex, любой MCP-клиент

CLI

npx -y @truenix/agent-browser markdown <url>

оболочки, скрипты, CI

Библиотека

import { withBrowser } from '@truenix/agent-browser'

ваш собственный код на Node

DSH / Cordis плагин

строка композиции

нативные инструменты в среде DSH

npx -y @truenix/agent-browser markdown https://news.ycombinator.com

Всё работает локально. Никакого аккаунта, API-ключа, удалённого сервиса или квоты.

Зачем

Передача агенту сырого HTML тратит большую часть его контекста. Измерено на реальных страницах:

А браузер, который заявляет о себе как об автоматизации, блокируется, деградирует или получает другой контент — что тихо искажает выводы агента.

Бенчмарк тяжёлых сайтов (вживую, curl против markdown)

сайт

сырой HTML

markdown

--links text

экономия

en.wikipedia.org/wiki/WebAssembly

927 kB

120 kB

55 kB

7.7× / 16.8×

react.dev

273 kB

11 kB

8.7 kB

23.8× / 31.4×

nextjs.org

323 kB

10 kB

7.3 kB

32.0× / 44.2×

github.com/trending

648 kB

69 kB

13 kB

9.3× / 48.9×

apple.com

360 kB

4.6 kB

3.5 kB

78.6× / 102.8×

news.ycombinator.com

35 kB

10 kB

3.2 kB

3.4× / 11.0×

Перегенерируйте оба графика и измерения, лежащие в основе этой таблицы, с помощью npm run charts — он измеряет вживую, а затем рисует PNG с помощью самого agent-browser, так что числа на изображениях не могут разойтись с тем, что выдаёт код.

Тратим меньше токенов на ту же страницу

URL-адреса составляют треть вывода в статье Википедии и четыре пятых на github.com/trending. Когда агент читает, а не перемещается, отбрасывайте их:

agent-browser markdown https://github.com/trending --links text      # 69 kB -> 13 kB
agent-browser markdown https://en.wikipedia.org/wiki/Rust --links relative

режим

отображает

используйте, когда

inline (по умолчанию)

[text](https://site/page)

агент будет перемещаться дальше

relative

[text](/page)

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

text

text

чтение, суммаризация, ответы на вопросы

Heavy-site benchmark

Token cost: Raw HTML vs agent-browser Стоимость токенов на одну проверку YC (HN + YC Blog прочитаны с --links text, 51,1k → 1,5k токенов, +500 на выходе) — цены по прайс-листу августа 2026: Anthropic Haiku 4.5 $1/$5, Sonnet 5 $3/$15, Opus 5 $5/$25 • OpenAI GPT-4o $2.50/$10, GPT-4o mini $0.15/$0.60

Страницы, которые рендерятся после загрузки

Навигация ожидает событие load, управляемое событиями жизненного цикла CDP, а не циклом опроса и фиксированной задержкой. На реальных страницах это в 2–3 раза быстрее при побайтно идентичном выводе:

страница

--wait load (по умолчанию)

старая фиксированная задержка 250 мс

example.com

7 мс

258 мс

github.com/trending

115 мс

340 мс

nextjs.org

160 мс

365 мс

news.ycombinator.com

218 мс

466 мс

Клиентское приложение, контент которого приходит после загрузки, нуждается в реальном сигнале, а не в более крупной догадке — старая задержка 250 мс тоже пропускала этот контент:

agent-browser markdown https://some-spa.example --wait idle

режим

ожидает

используйте, когда

domcontentloaded

DOM разобран

вам нужна только разметка, которая пришла в HTML

load (по умолчанию)

событие load

почти всегда

idle

сеть затихает

результат выглядит как пустая оболочка

Related MCP server: Browser-MCP Navigator

Любая другая среда

Если ваш фреймворк говорит на JSON Schema, он может управлять agent-browser, даже если этот проект не знает о существовании фреймворка. agent-browser tools выводит каталог в нужной вам форме:

agent-browser tools                     # MCP:       {name, description, inputSchema}
agent-browser tools --format openai     # OpenAI:    {type:"function", function:{...}}
agent-browser tools --format anthropic  # Anthropic: {name, description, input_schema}

Каждый инструмент затем работает в любом случае, в зависимости от возможностей вашей среды:

import { findTool, TOOLS } from '@truenix/agent-browser/tools';
import { withBrowser } from '@truenix/agent-browser';

// in-process: the harness can hold a CDP session
const tool = findTool('browser_markdown');
const text = await withBrowser({}, async (session) => {
  await session.navigate('https://example.com');
  return tool.run(session, { url: 'https://example.com', links: 'text' });
});

// out-of-process: the harness can only run a command (sandboxes, shells)
tool.cli({ url: 'https://example.com', links: 'text' });
// => ['markdown', 'https://example.com', '--links', 'text']

Установка

Как MCP-сервер

claude mcp add browser -- npx -y @truenix/agent-browser mcp
{
  "mcpServers": {
    "browser": {
      "command": "npx",
      "args": ["-y", "@truenix/agent-browser", "mcp"]
    }
  }
}

Инструменты: browser_markdown, browser_text, browser_html, browser_links, browser_screenshot, browser_evaluate, browser_accessibility_tree, browser_pdf, browser_probe.

Каждый способ предоставляет одни и те же девять инструментов из общего каталога, так что CLI, MCP-сервер и DSH-плагин никогда не разойдутся.

Как библиотека

npm install @truenix/agent-browser
import { withBrowser } from '@truenix/agent-browser';

const md = await withBrowser({}, async (session) => {
  await session.navigate('https://example.com');
  return session.markdown();
});

Как DSH / Cordis плагин

Однострочник (рекомендуется — автоматически подключается, когда вы имеете в виду DSH):

npx -y @truenix/agent-browser install          # adds the bundle to ~/.dsh/profiles/web/package.json, then pnpm install (the mount ships in the package's own cordis.patch.yml layer)
# npx -y @truenix/agent-browser install --profile web --dry-run  # preview
# npx -y @truenix/agent-browser uninstall      # remove again

Перезапустите dsh — все девять инструментов browser_* появятся как нативные. Никакой обработчик не запускается при простом npm install; требуется осознанная install.

Вручную (если вы предпочитаете редактировать композицию самостоятельно):

npm i -g @truenix/agent-browser
# or inside the harness checkout: pnpm add @truenix/agent-browser

Требуется Node ≥ 18 и установленный Chrome/Chromium. Затем добавьте в хостовую композицию (реестр инструментов живёт на хосте, а не на агенте):

# ~/.dsh/profiles/web/cordis.patch.yml  — persists for every web session
- insert:
  - id: agent-browser
    name: '@truenix/agent-browser/cordis'
    config:
      timeoutMs: 180000   # per-tool call budget; default respects AGENT_BROWSER_BIN / ENDPOINT
      # cli: 'npx -y @truenix/agent-browser'  # override only if needed

Краткая форма (когда композиция уже оборачивает insert):

- '@truenix/agent-browser/cordis':
    timeoutMs: 180000

Переопределения через env: AGENT_BROWSER_BIN (бинарник Chrome), AGENT_BROWSER_ENDPOINT (подключение к долгоживущему браузеру через --endpoint) или config.cli.

CLI

agent-browser <command> [options]

  markdown <url>     Extract the whole page as Markdown (main content by default)
  text <url>         Visible text only
  html <url>         Full serialized DOM after JavaScript runs
  links <url>        Every anchor as JSON
  screenshot <url>   PNG/JPEG   (-o file, --full)
  pdf <url>          PDF        (-o file)
  a11y <url>         Filtered accessibility tree
  eval <url> <expr>  Evaluate JS, return only its value (cheapest)
  probe              Browser, GPU and capability report
  mcp                Run as an MCP server on stdio
  tools              Print tool schemas (--format mcp|openai|anthropic)

Опции: --headful, --no-stealth, --block-images, --gpu/--no-gpu, --width, --height, --viewport WxH, --main, --raw, --links, --max-rows, --limit, --wait, --settle, --full, --endpoint <ws>, --timeout, --json, -o.

markdown для чтения, eval для поиска информации

Самая дорогая ошибка агента при работе с этим инструментом — рендеринг целой страницы для ответа на вопрос в одну строку. Три точечных вопроса на трёх тяжёлых страницах стоят 235 байт через eval против 77 кБ Markdown:

agent-browser eval https://github.com/trending \
  "JSON.stringify(Array.from(document.querySelectorAll('article h2 a')).slice(0,3).map(a=>a.innerText.trim()))"
# ["openai / codex","mattpocock / skills","affaan-m / ECC"]   -> 58 bytes

Используйте innerText, а не textContent. textContent возвращает исходные пробелы из исходного кода ("openai /\n\n codex"); innerText даёт то, что реально отрендерено ("openai / codex"). Агент, который ошибается в этом, платит целый цикл повторной попытки, что стоит гораздо дороже сэкономленных байт.

Используйте markdown, когда вам действительно нужно читать, суммаризировать или искать по странице.

Каждый вызов запускает собственный браузер (~1,4 с). Для нескольких последовательных запросов держите один браузер живым и направьте на него --endpoint — те же три вопроса занимают 5,9 с при трёх холодных стартах и 3,2 с при тёплом.

--endpoint подключается к уже запущенному браузеру вместо запуска нового — полезно для повторного использования одного долгоживущего браузера во многих вызовах.

Память

Минимальный уровень Chrome составляет около 420 МБ PSS на 18 процессов до загрузки чего-либо, и этот уровень принадлежит Chrome, а не этому пакету — настройка флагов сдвигает его на ~5%, а флаг, который сдвигает его дальше (--enable-low-end-device-mode), сообщает navigator.deviceMemory: 2 рядом с 24 ядрами — невозможная машина и именно та несогласованность, из-за которой браузер помечают. Поэтому рычаг — меньше браузеров, а не меньше размер.

MCP-сервер держит один браузер и даёт каждому вызову инструмента собственный изолированный контекст. Три тяжёлые страницы, загруженные одновременно:

пиковый PSS

процессы

время выполнения

браузер на каждый вызов

1289 МБ

44

2114 мс

один браузер, 3 контекста

654 МБ

20

2049 мс

Изоляция не меняется — именно контекст браузера на каждый вызов всегда её обеспечивал. Браузер завершается после 30 с простоя (AGENT_BROWSER_IDLE_MS, 0 для немедленного закрытия), так что долгоживущий сервер не висит на 420 МБ между разговорами. Повторный вызов, пока он тёплый, полностью пропускает запуск и работает примерно вдвое быстрее.

Компромисс: задачи разделяют дерево процессов, поэтому сбой на уровне браузера убивает всё, что в полёте, а не один вызов. Мёртвый браузер обнаруживается и перезапускается при следующем вызове. Если вам нужна изоляция радиуса поражения для каждой задачи, используйте withBrowser, который по-прежнему даёт каждому вызову собственный браузер.

import { withPooledSession, shutdownPool } from '@truenix/agent-browser/pool';

await withPooledSession({}, async (session) => {
  await session.navigate('https://example.com');
  return session.markdown();
});
await shutdownPool();   // or let it idle out

Для CLI каждый вызов — это отдельный процесс, поэтому повторное использование означает направление --endpoint на браузер, который вы держите живым самостоятельно.

Демон: один браузер для каждого вызова CLI

Каждый вызов CLI — это отдельный процесс, поэтому по умолчанию каждый холодно запускает свой Chrome — десять одновременных вызовов означают десять браузеров. --daemon вместо этого делит один резидентный браузер, при этом каждый вызов по-прежнему получает собственный изолированный контекст:

agent-browser markdown https://example.com --daemon
agent-browser daemon --status
agent-browser daemon --stop

время выполнения

пиковое количество процессов Chrome

3 последовательных запроса, без демона

5330 мс

3 последовательных запроса, --daemon

3254 мс

10 одновременных вызовов, без демона

1443 мс

140

10 одновременных вызовов, --daemon

1144 мс

32

Это opt-in (--daemon или AGENT_BROWSER_DAEMON=1), потому что запуск фонового процесса, который переживает вашу команду, — это побочный эффект, о котором стоит спросить. Он запускается по требованию и завершается после пяти минут простоя (AGENT_BROWSER_DAEMON_IDLE_MS). Установка переменной окружения также направляет на него MCP-сервер, что стоит сделать, когда несколько MCP-клиентов используют одну машину.

--headful, --width, --height, --block-images и --gpu фиксируются при запуске браузера, поэтому общий браузер не может их соблюсти. Передача любого из них побеждает: этот вызов тихо получает собственный приватный браузер и сообщает об этом в stderr.

Четыре режима отказа, вокруг которых он построен, каждый проверен тестом:

  • Ровно один демон. Десять одновременных первых вызовов порождают один; девять проигрывают гонку за привязку сокета и выходят, ничего не запустив. Привязка сокета и есть блокировка, поэтому нет lock-файла, который мог бы устареть.

  • Открытый сокет — это счётчик ссылок. Клиент держит соединение, пока работает, поэтому клиент, убитый с помощью SIGKILL, всё равно освобождает — ядро закрывает сокет. Сообщение «пожалуйста, освободи» утекло бы ссылку навсегда.

  • Выход по простою, чтобы он не висел на ~420 МБ между разговорами.

  • Убитый через SIGKILL демон ничего не бросает: его маркер профиля называет его pid, поэтому следующая зачистка возвращает браузер при следующем запуске.

Уборка за собой

Каждый запуск записывает маркер владельца в свой временный профиль и вычищает профили, чей владелец умер, убивая браузер, всё ещё прикреплённый к ним. В сочетании с обработчиками SIGINT/SIGTERM/SIGHUP это даёт:

как завершается вызов

осиротевшие процессы

после следующего запуска

обычно

0

0

SIGTERM / SIGINT

0

0

SIGKILL (неперехватываемый)

1 браузер

0

Таким образом, жёсткое завершение стоит не более одного зависшего браузера, а не одного на каждый прерванный вызов. Десять одновременных вызовов CLI, повторённых, не оставляют ничего. Живой браузер никогда не вычищается — его процесс-владелец всё ещё работает, и неприписанный профиль остаётся нетронутым, пока ничто не держит его открытым и он не простаивает 60 с.

Обнаружение ботов

Запустите сами: npm run test:bot. Последний результат:

detector

result

bot.sannysoft.com

31 пройдено, 0 провалено

bot-detector.rebrowser.net

6 зелёных, 0 красных, runtimeEnableLeak: clean

deviceandbrowserinfo.com

isBot: false, 0 из 22 проверок отмечено

Обычный headless Chrome не проходит четыре строки sannysoft (HEADCHR_UA, CHR_MEMORY, WebGL SwiftShader, old UA) и определяется как бот.

Недоступный детектор считается SKIP, а не прохождением, и для прохождения требуется три доступных успешных результата — так что день, когда тестовые сайты недоступны, не может быть ошибочно принят за успех.

Окружение важнее, чем патчинг

Один и тот же код, измеренный в двух местах:

эта рабочая станция

GitHub Actions runner

IP

резидентный

дата-центр

GPU

реальный (NVIDIA)

нет → SwiftShader

bot.sannysoft.com

31 пройдено, 0 провалено

30 пройдено, 1 провалено (WebGL Renderer)

bot-detector.rebrowser.net

6 зелёных, 0 красных

6 зелёных, 0 красных

deviceandbrowserinfo.com

isBot: false

isBot: true (hasSuspiciousWeakSignals)

Все сигналы на уровне CDP остаются чистыми в обоих случаях — это часть кода, и код правильный. Что меняет вердикт — это окружение: дата-центровый ASN плюс программный рендеринг вызывают композит слабых сигналов, который не исправить никаким патчингом отпечатков.

Это честная форма проблемы. Укрепление браузера убирает тривиальные признаки. Где вы его запускаете, решает остальное.

Что делает укрепление и почему

Каждый пункт появился из-за детектора, который говорил нам, что мы ошибаемся:

  • Без --enable-automation. Этот флаг — который добавляют Puppeteer и Playwright — устанавливает navigator.webdriver = true. Сырой CDP его не устанавливает, поэтому он остаётся false без каких-либо исправлений.

  • Без Runtime.enable. Это самый заметный признак CDP и он питает классический детектор console/Error.stack. Runtime.evaluate отлично работает без него.

  • Окно и экран двигаются вместе. --window-size без --ozone-override-screen-size даёт outerWidth > screen.width, что физически невозможно — более сильный сигнал, чем просто headless.

  • Без переопределения метрик устройства по умолчанию. Обычный 1280×720 — это стандартный вьюпорт Playwright, и детекторы помечают его по имени. Устанавливайте --viewport только если нужно.

  • Реальный GPU, когда доступен, дающий настоящий рендерер ANGLE (NVIDIA …) вместо SwiftShader.

  • UA задаётся при запуске, а не только через CDP. Emulation.setUserAgentOverride не достигает Web Workers, поэтому воркер продолжает сообщать headless UA, в то время как страница сообщает чистый (hasInconsistentWorkerValues).

  • Без переопределения acceptLanguage. CDP выводит navigator.languages путём разбиения этого заголовка, поэтому "en-US,en;q=0.9" становится ["en-US","en;q=0.9"] — q-значение, которое не может существовать легально, и ещё одно несоответствие страницы/воркера. --lang делает это правильно.

  • Client Hints, полученные из собственной версии бинарника, поэтому Sec-CH-UA не может противоречить navigator.userAgent.

  • Изолированный контекст браузера для каждой сессии, уничтожаемый при закрытии — чистое состояние для каждой задачи без второго процесса браузера.

Повторяющийся урок: согласованность важнее покрытия. Четыре из них — случаи, когда частичный спуфинг облегчал обнаружение, и это было выявлено только при запуске реальных детекторов.

Почему спуфинг WebGL отключён по умолчанию

spoofWebgl существует и реализован аккуратно — Proxy вокруг нативного getParameter, так что Function.prototype.toString по-прежнему сообщает [native code]. Он отключён, потому что измерения показывают, что он даёт обратный эффект. Из test/webgl-spoof-experiment.mjs:

вариант

заявленный рендерер

maxTexture

extensions

sannysoft

вердикт

реальный GPU, без спуфинга

NVIDIA

32768

37

0 провалено

isBot: false

SwiftShader, честно

SwiftShader

8192

35

1 провалено

isBot: false

SwiftShader + спуфинг

NVIDIA

8192

35

0 провалено

isBot: true

Заявление о наличии оборудования, которого у вас нет, исправляет одну косметическую строку и проваливает композитный детектор: внедрённый скрипт не достигает Web Workers, поэтому воркер по-прежнему сообщает SwiftShader, а MAX_TEXTURE_SIZE остаётся на программном значении, в то время как строка рендерера заявляет дискретный GPU.

Честный SwiftShader проходит. Убедительная ложь — нет. Вместо этого дайте браузеру реальный GPU — это бесплатно.

Чего это НЕ делает

Обнаружение на уровне отпечатков — это вся область действия. Он не побеждает и не пытается победить:

  • TLS/JA3-JA4 и HTTP/2 отпечатки — определяются до выполнения любого JavaScript

  • Репутация IP — дата-центр против резидентного ASN, часто реальный блокировщик

  • Поведенческий анализ — траектории мыши, тайминги, время пребывания

Коммерческие продукты для защиты от ботов опираются на это, поэтому «прохождение ворот» означает не быть тривиально помеченным как автоматизация, а не необнаруживаемым. Предназначено для ваших собственных сайтов, тестирования, работ по доступности и обычного просмотра страниц агентом.

Память

Стек Chrome стоит примерно 450 МБ. Рычаг — это архитектура, а не флаги: запускайте один браузер и много изолированных контекстов, а не один браузер на задачу. Запустите браузер один раз, затем направляйте каждый вызов на него с помощью --endpoint / AGENT_BROWSER_ENDPOINT. --block-images помогает при работе с текстом.

Ноль зависимостей

dependencies пуст, включая транспорт WebSocket.

Глобальный WebSocket Node (WHATWG) не может отправлять заголовки запросов, которые нужны любому аутентифицированному или проксированному CDP-эндпоинту, а undici не импортируется отдельно. Поэтому src/ws.mjs реализует RFC 6455 напрямую через node:http(s) — рукопожатие, маскирование, фрагменты продолжения, 64-битные длины, ping/pong — всё, что требуется CDP.

Конвертер Markdown обходит DOM с явным стеком, сохраняя глубину вызовов JS на O(1) независимо от вложенности, и использует нативный innerText для встроенных узлов на уровне листьев. Это делает его безопасным для рекурсии на глубоко вложенных документах и заметно более быстрым на больших страницах.

Окружение

AGENT_BROWSER_BIN

путь к бинарнику Chrome/Chromium

AGENT_BROWSER_ENDPOINT

подключиться к этому CDP-эндпоинту вместо запуска

Требования

Node ≥ 18 и установленный Chrome/Chromium. Без шага сборки.

Благодарности

Укрепление этого проекта почти полностью основано на опубликованных исследованиях других людей по обнаружению — см. CREDITS.md. Особая благодарность rebrowser-bot-detector, bot.sannysoft.com, deviceandbrowserinfo.com и Camoufox за то, как показать, как это делается правильно.

Лицензия

MIT

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    MCP server for browser automation with anti-detection. Scout pages, find elements, interact with websites, and monitor network traffic from any AI client that supports the Model Context Protocol.
    21
    1
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    A fault-tolerant, stealth-enabled Model Context Protocol (MCP) server for web searching and content fetching. Built for AI Agents (Cursor, Claude Code, OpenCode), it uses a stealth browser engine to fetch pages, dynamically handles SPAs/React, and converts bloat into token-optimized Markdown.
    2
    33
    3
    MIT
  • A
    license
    B
    quality
    A
    maintenance
    MCP server that drives your real Chrome/Edge/Opera browser through a Chrome extension and DevTools Protocol, preserving logins and session state, and can also perform OS-level mouse and keyboard input behind approval.
    55
    2
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TrueNix/agent-browser'

If you have feedback or need assistance with the MCP directory API, please join our Discord server