Skip to main content
Glama
TrueNix

agent-browser

by TrueNix

agent-browser

AIエージェント向けの堅牢なローカルブラウザ。依存関係ゼロ。 既存のChromeをDevToolsプロトコルで操作し、トークン効率の良い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 vs 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 で再生成できます。ライブで測定し、agent-browser自身を使ってPNGを描画するため、画像内の数値がコードが生成するものからずれることはありません。

同じページでより少ないトークンを使う

URLはWikipediaの記事では出力の3分の1、github.com/trendingでは5分の4を占めます。エージェントがナビゲーションではなく読む場合には、それらを削除してください:

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

読む、要約する、質問応答

ヘビーサイトベンチマーク

トークンコスト:生のHTML vs agent-browser YCチェックあたりのトークンコスト(--links text でHN + YCブログを読んだ場合、51.1k → 1.5kトークン、+500出力)— 2026年8月のリスト価格: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 (デフォルト)

旧固定250ms待機

example.com

7 ms

258 ms

github.com/trending

115 ms

340 ms

nextjs.org

160 ms

365 ms

news.ycombinator.com

218 ms

466 ms

コンテンツがロード後に到着するクライアントレンダリングアプリには、より大きな推測ではなく、実際のシグナルが必要です。旧250msのセトルもそのコンテンツを見逃していました:

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。

すべてのサーフェスは、1つの共有カタログから同じ9つのツールを公開するため、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 を再起動すると、9つの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

環境変数の上書き: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

このツールでエージェントが犯す最も高くつく間違いは、1行の質問に答えるためにページ全体をレンダリングすることです。3つの重いページにわたる3つの対象を絞った質問は、eval 経由で235バイト、Markdownでは77 kBかかります:

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

textContentではなくinnerTextを使用してください。textContentは生のソースの空白を返します("openai /\n\n codex")。innerTextは実際にレンダリングされたものを返します("openai / codex")。これを間違えると、エージェントはリトライの往復全体を支払うことになり、節約したバイトよりもはるかにコストがかかります。

ページを実際に読む、要約する、検索する必要がある場合は、markdown を使用してください。

各呼び出しは独自のブラウザを起動します(約1.4秒)。連続して複数のルックアップを行う場合は、1つのブラウザを起動したままにして、--endpoint をそれに向けてください。同じ3つの質問は、3回のコールドスタートで5.9秒、ウォームスタートでは3.2秒かかります。

--endpoint は、ブラウザを起動する代わりに、すでに実行中のブラウザに接続します。多くの呼び出しにわたって単一の長期実行ブラウザを再利用する場合に便利です。

メモリ

Chromeの下限は、何も読み込む前に18プロセスで約420 MB PSSです。その下限はChromeのものであり、このパッケージのものではありません。フラグ調整で約5%動きますが、さらに動かすフラグ(--enable-low-end-device-mode)は、24コアの隣でnavigator.deviceMemory: 2を報告します。これは不可能なマシンであり、ブラウザがフラグされるまさにその種の不整合です。したがって、レバーはより小さいブラウザではなくより少ないブラウザです。

MCPサーバーは1つのブラウザを保持し、各ツール呼び出しに独自の分離されたコンテキストを提供します。3つの重いページを同時に取得した場合:

ピークPSS

プロセス数

ウォールクロック

呼び出しごとにブラウザ

1289 MB

44

2114 ms

1つのブラウザ、3つのコンテキスト

654 MB

20

2049 ms

分離は変わりません。呼び出しごとのブラウザコンテキストが常にそれを提供していました。ブラウザは30秒のアイドル後にシャットダウンします(AGENT_BROWSER_IDLE_MS、0で即座に閉じる)。そのため、長期実行サーバーは会話の間に420 MBを占有しません。ウォーム状態での繰り返し呼び出しは、起動を完全にスキップし、約2倍高速に実行されます。

トレードオフ:タスクはプロセスツリーを共有するため、ブラウザレベルのクラッシュは1つの呼び出しではなく、進行中のすべてを停止させます。死んだブラウザは検出され、次の呼び出しで再起動されます。タスクごとに爆発半径の分離が必要な場合は、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呼び出しに1つのブラウザ

各CLI呼び出しは独自のプロセスであるため、デフォルトではそれぞれが独自のChromeをコールドスタートします。10の同時呼び出しは10のブラウザを意味します。--daemon は代わりに1つの常駐ブラウザを共有し、各呼び出しは依然として独自の分離されたコンテキストを取得します:

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

ウォールクロック

ピークChromeプロセス数

3回の順次ルックアップ、デーモンなし

5330 ms

—

3回の順次ルックアップ、--daemon

3254 ms

—

10の同時呼び出し、デーモンなし

1443 ms

140

10の同時呼び出し、--daemon

1144 ms

32

これはオプトインです(--daemon または AGENT_BROWSER_DAEMON=1)。コマンドより長く存続するバックグラウンドプロセスを開始することは、要求する価値のある副作用だからです。オンデマンドで起動し、5分間アイドル状態が続くと終了します(AGENT_BROWSER_DAEMON_IDLE_MS)。環境変数を設定すると、MCPサーバーもそれにルーティングされます。これは、複数のMCPクライアントがマシンを共有する場合に価値があります。

--headful、--width、--height、--block-images、--gpu はブラウザ起動時に固定されるため、共有ブラウザはそれらを尊重できません。これらのいずれかを渡すと優先されます。その呼び出しは静かに独自のプライベートブラウザを取得し、stderrにその旨を出力します。

これが構築されている4つの障害モード。それぞれテストで検証されています:

  • デーモンは正確に1つ。 10の同時の最初の呼び出し元はすべて1つを生成しますが、9つはソケットをバインドする競争に負けて、何も起動せずに終了します。ソケットをバインドすることがロックであるため、古くなるロックファイルはありません。

  • 開いているソケットが参照カウントです。 クライアントは作業中に接続を保持するため、SIGKILLで強制終了されたクライアントでも解放されます。カーネルがソケットを閉じます。「解放してください」というメッセージは、参照を永久にリークしていたでしょう。

  • アイドル終了。会話の間に約420 MBを占有しません。

  • SIGKILLされたデーモンは何も残しません:そのプロファイルマーカーはpidを名前として持つため、以下のスイープが次の起動時にブラウザを回収します。

自己クリーンアップ

すべての起動は、一時プロファイルに所有者マーカーを書き込み、所有者が死亡したプロファイルをスイープして、それらにまだ接続されているブラウザを強制終了します。SIGINT/SIGTERM/SIGHUPハンドラーと組み合わせると、次のようになります:

呼び出しの終了方法

孤立プロセス

次の起動後

通常

0

0

SIGTERM / SIGINT

0

0

SIGKILL(捕捉不可)

1ブラウザ

0

つまり、ハードキルで失われるのは最大で取り残されたブラウザ1つだけで、中断された呼び出しごとに1つではありません。10件の同時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、22件中0件がフラグ付き

素のヘッドレスChromeはsannysoftの4行(HEADCHR_UA、CHR_MEMORY、WebGL SwiftShader、古いUA)で失敗し、ボットとして報告されます。

到達不能な検出器はSKIPとしてカウントされ、合格とは決してみなされません。また、ゲートは到達可能な3つの合格を要求するため、テストサイトがダウンしている日を成功と誤認することはありません。

環境はパッチ適用よりも重要

同一のコードを2つの場所で測定した結果:

このワークステーション

GitHub Actionsランナー

IP

住宅用

データセンター

GPU

実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の兆候であり、古典的なコンソール/Error.stack検出器を動かします。Runtime.evaluateはそれがなくても正常に動作します。

  • ウィンドウとスクリーンは連動します。 --ozone-override-screen-sizeなしの--window-sizeはouterWidth > screen.widthを生み出しますが、これは物理的に不可能であり、素のヘッドレスよりも強いシグナルです。

  • デフォルトのデバイスメトリクスオーバーライドなし。 通常の1280×720はPlaywrightのデフォルトビューポートであり、検出器はそれを名前でフラグ付けします。必要な場合にのみ--viewportを設定してください。

  • 利用可能な場合は実GPUを使用し、SwiftShaderの代わりに本物のANGLE (NVIDIA …)レンダラーを提供します。

  • UAはCDP経由だけでなく、起動時に設定。 Emulation.setUserAgentOverrideはWeb Workersに到達しないため、ページがクリーンなUAを報告している間、ワーカーはヘッドレス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と矛盾することはありません。

  • セッションごとに分離されたブラウザコンテキストを、クローズ時に破棄します。2つ目のブラウザプロセスなしで、タスクごとにクリーンな状態を実現します。

繰り返し現れる教訓: 一貫性は網羅性に勝る。 そのうちの4つは、部分的なスプーフィングが検出を容易にしたケースであり、実際の検出器を実行することでのみ発見されました。

WebGLスプーフィングがデフォルトでオフな理由

spoofWebglは存在し、注意深く実装されています。ネイティブのgetParameterを囲むProxyであり、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 ❌

持っていないハードウェアを主張すると、見た目上の1行は修正されますが、複合検出器で失敗します: 注入されたスクリプトはWeb Workersに到達しないため、ワーカーは依然としてSwiftShaderを報告し、レンダラー文字列がディスクリートGPUを主張している間もMAX_TEXTURE_SIZEはソフトウェアの値のままです。

正直なSwiftShaderは合格します。説得力のある嘘は合格しません。代わりにブラウザに実GPUを与えてください。無料です。

これが行わないこと

フィンガープリントレベルの検出が全範囲です。以下を打ち負かすことはできず、試みもしません:

  • TLS/JA3-JA4およびHTTP/2フィンガープリンティング — JavaScriptが実行される前に決定されます

  • IPレピュテーション — データセンター対住宅用ASN、しばしば実際の障壁となります

  • 行動分析 — マウスの軌跡、タイミング、滞在時間

商用チャレンジ製品はこれらに依存しているため、「ゲートを通過する」とは自動化として簡単にフラグ付けされないことを意味し、決して検出不可能ではありません。自分のサイト、テスト、アクセシビリティ作業、および通常のエージェントブラウジングを対象としています。

メモリ

Chromeスタックのコストはおよそ450 MBです。鍵となるのはアーキテクチャであり、フラグではありません。タスクごとに1つのブラウザではなく、1つのブラウザと多数の分離コンテキストを実行します。ブラウザを一度起動し、--endpoint / AGENT_BROWSER_ENDPOINTで毎回の呼び出しをそこに向けます。テキスト作業には--block-imagesが役立ちます。

ゼロ依存

dependenciesは空で、WebSocketトランスポートも含みません。

NodeのグローバルWebSocket(WHATWG)はリクエストヘッダーを送信できません。これは認証付きまたはプロキシ経由のCDPエンドポイントがすべて必要とする機能であり、undiciは単体ではインポートできません。そのため、src/ws.mjsはnode:http(s)上で直接RFC 6455を実装しています。ハンドシェイク、マスキング、継続フラグメント、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

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
    B
    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
    13 npm
    3
    MIT
  • A
    license
    A
    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.
    51
    34 PyPI
    2
    MIT