jev-ultrafast-mcp について
jev-ultrafast-mcpは、エージェントに代わってサーバー側でブラウザー操作を行うMCPサーバーです。コードで結果を検証する目標ベースの実行と、ページ要素表を使った個別の確認・操作を備え、スクリーンショットに依存しません。
主な機能
- 01サーバー側のブラウザー実行ループ
- 02ページ要素テーブルと参照ID
- 03コードによるアサーション検証
- 04マクロの記録と再生
- 05MCPクライアント設定インストーラー
活用シーン
- 01フォームを送信して結果を検証
- 02画面キャプチャなしでページ本文を読む
- 03記録済みのブラウザー操作を再生
MCP 対応
目標ベースの実行、ページの表示と観察、操作、アサーション、マクロなどのブラウザーツールをMCPクライアントに公開します。付属インストーラーは対応クライアントを検出し、既存設定にサーバー構成を統合します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
10掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | はい | |
| hint | string | いいえ | |
| session | string | いいえ |
詳細
jev-ultrafast-mcp
English · 简体中文

ブラウザーでの作業を任せましょう — エージェントの代わりにページを操作する MCP サーバーです。
エージェントがブラウザーを開く必要はありません。ブラウザーのタスク(URL、目的、それを証明する確認方法)をまとめて渡すと、サーバー上でループが実行されます。20回ではなく、1回のツール呼び出しで。1分ではなく、3秒で。最先端モデルのコンテキストではなく、1セントで。さらに、対象を作り出すことはありません。ページに実際にある要素から選択し、推測するくらいならサーバーが拒否します。
費用はいくらか。 1日中使って1セント、それだけです。

クイックスタート
3つのコマンドを実行したら、クライアントを再起動します。
git clone https://github.com/jiawei686/jev-ultrafast-mcp.git
cd jev-ultrafast-mcp
python3 -m venv .venv
.venv/bin/pip install -e . # Windows: .venv\Scripts\pip install -e .
python scripts/install.py # finds your MCP clients and writes their config
install.py は WorkBuddy、Claude Code、Claude Desktop、Codex CLI、Cursor、VS Code、Cline、Windsurf、Gemini CLI を探し、それぞれが必要とする形式で設定を書き込みます。既存の設定にマージし、先に .bak として保存します。Python ≥ 3.10 と、Chromium 系のブラウザーが必要です。
クライアントを再起動したら、やってほしいことを伝えるだけです。
あなた: このフォームを大人3人に設定して、直行便のみにチェックを入れてから送信してください。 エージェント:
browser_goal(goal=…, url=…, verify=[…])— 1回の呼び出しでページを開き、サーバー側でループを実行し、その後コードで結果を確認します。 (費用はこちら)
あなた: example.com を開いて、ページに何が書いてあるか教えてください。 エージェント:
browser_open→ 要素テーブルを読み取る → 回答する — ページを見るだけならタスクではないため、モデルは不要です。 (実際の実行例)
再起動したのにツールが表示されませんか? クライアントによっては、サーバーを一度承認する必要があります。WorkBuddy では Connectors → Custom connectors → Trust です。承認は設定自体に紐づけて記憶されるため、後で設定を編集すると、もう一度だけ確認されます。
インストール
パッケージとしてインストールする場合は、チェックアウトは不要です。PyPI に公開されているので、名前を指定するだけです。
uvx jev-ultrafast-mcp # run it straight from PyPI, nothing installed
pip install jev-ultrafast-mcp # or install it yourself
クライアントの設定には uvx のキャッシュ内のパスではなく、安定したインタープリターのパスが必要です。そのため、次のようにします。
python3 -m venv ~/.jev-ultrafast-mcp/venv
~/.jev-ultrafast-mcp/venv/bin/pip install jev-ultrafast-mcp
これにより、jev-ultrafast-mcp コンソールスクリプトと、クライアント設定に指定できる安定したインタープリターのパスが得られます。Python 3.13 で最新の mcp SDK を使って検証済みで、リストにある10個のツールすべてが対象です。
scripts/install.py はもう一方の方法です。MCP クライアントを探し、それぞれが必要とする設定を書き込みます。既存のファイルにマージし、先に .bak として保存します。
python scripts/install.py --list # what is installed, and the file each one reads
python scripts/install.py --print # show the config it would write, change nothing
python scripts/install.py -c cursor,codex # only these two
python scripts/install.py --headed # keep a visible browser window
python scripts/install.py --allow-domains example.com,*.example.org
python scripts/install.py --uninstall # take the entry back out
実行時の依存関係:mcp、websockets、httpx。Playwright、Selenium、browser-harness は不要です。
安価で高速、そして請求額はこちらです
実際のページで browser_goal を使って実行した、3 ステップの目標です。エージェントが送信した内容と
受け取った内容はこれがすべてです。1 ターンだけで、ページがコンテキストに入ることはありませんでした。
browser_goal(
goal="On this flight search form: set Passengers to 3 adults, tick the 'Nonstop only' "
"checkbox, then submit the search. Do not type into any city field.",
verify=[{"type": "text_contains", "text": "3 adults · nonstop"}],
)
goal: On this flight search form: set Passengers to 3 adults, …
status: done
steps: 3
turbo: 4 decisions · 14,626 tokens · 1.8s model + 1.1s page · 3.3s wall
trace:
1. SELECT e6 Passengers → ok (759ms model / 30ms browser)
2. TOGGLE e7 Nonstop only → ok (336ms model / 692ms browser)
3. CLICK e8 Search → ok (370ms model / 410ms browser)
4. DONE (conf 0.93)
verified: PASS
ok text_contains: '3 adults · nonstop' found in page text
2 回目にかかる費用。 何もかかりません。2 回目は記録済みのマクロであり、マクロはモデルを一切呼び出しません。キーさえ不要です。
所要時間。 目標全体で実時間 3.3 秒です。モデルに 1.8 秒、ページに 1.1 秒かかりました。実行するたびにこの行が出力されるため、数値は説得材料ではなく検証可能なものです。
この実行はモックではありません。scripts/turbo_check.py は実際の Chrome と実際のモデルを使って同じ実行を再現し、さらにモデル自身の作業報告を信頼するのではなく、コードでページを検証します。3 つの操作と、その間の読み取りと再読み取りはすべてサーバー上で行われました。エージェントは 1 ターンを費やしただけで、要素テーブルを見ることはありませんでした。
役割分担こそが設計上の決定事項であり、タスクごとに選択するのはあなたです。
| エージェントが操作 | browser_goal が操作 | |
|---|---|---|
| 3 ステップのフローに必要なツール呼び出し | 6 回以上(観察、操作、観察、操作…) | 1 回 |
| ページをコンテキストに保持するのは誰か | あなたのエージェント | モデル(サーバー側) |
| 各ステップのコスト | エージェントのターン 1 回 | 型付きリクエスト 1 回、スクリーンショット不要 |
| 対象を指定するのは誰か | モデルがセレクターを記述 | モデルがページ独自のテーブルから ref を選択 |
| 失敗した場合 | 通常は気づかれない誤クリック | サーバーが理由を示して拒否 |
| 成功したかどうかを知る方法 | モデルの要約 | コードで検証されたアサーション。不一致があればこちらを優先 |
| 2 回目の実行 | モデルを再実行 | マクロを再生。モデル呼び出しはゼロ |
概要
通常のブラウザー自動化では、エージェントが操作を担当します。ページを読み取り、要素を1つ選び、操作し、うまくいったかどうかを確かめるためにもう一度読み取ります。クリックが10回なら、やり取りも10回になり、毎回ページがエージェントのコンテキストを通過します。誤クリックが起きても、それと分かることはほとんどありません。
このサーバーにその作業を任せられます。browser_goalはエージェントからの1回のツール呼び出しです。ループはサーバー側で実行され、TypeSafeの意思決定モデルであるJevが各ステップを選択します。モデルがセレクターを書くことはありません。実際にページ上にある要素から選び、ページ上にないものは推測せず、サーバーが拒否します。処理が止まると、browser_assertがコードで残されたページを検証します。検証に合格した結果は、モデル自身による作業の説明よりも優先されます。
ここから、次の4つの特長が得られます。
- クリックごとではなく、1回の呼び出し。 上記の実行では、実際のページで3ステップの目標を達成するために、4回の判断、14,626トークン、モデル処理1.8秒+ページ処理1.1秒、合計3.3秒かかりました。エージェントのコンテキストを使うのは1ターンだけです。
- 設計上、正確です。 対象はモデルが作り出したセレクターや座標ではなく、ページ上にある要素を番号付きで示した表の
refです。操作は実行前にページと照合して再確認されます。 - 初回実行後は無料です。 一度経路を記録すれば、再生時のモデル呼び出しはゼロです。キーがなくても動作し、ページが一致しなくなると続行を拒否します。
- ピクセルではなくテキストです。 スクリーンショットもHTMLダンプもありません。すでにお使いのChromeにCDPで直接接続するため、Playwright、Selenium、スクリーンショットの処理パイプラインは不要です。
browser_goal以外のすべての機能(browser_open、browser_observe、browser_act、browser_assert、browser_macro)は、どのMCPクライアント(WorkBuddy、Claude Code、Codex、Cursor、VS Code)からも、キーもアカウントもページへの接続以外のネットワーク接続も不要です。自分で操作したい場合にも、これらの機能はすべて引き続き利用できます。
browser_open → element table → browser_act [refs] → browser_assert
browser-use/jev-ultrafastとTypeSafeの型付き質問APIに着想を得ています。どちらとも無関係な独立プロジェクトです。違いとその理由については、docs/DESIGN.mdをご覧ください。
目次 · クイックスタート · 低コストで高速 · 概要 · セッションの実際の様子 · エージェントの接続 · 依頼できること · エージェントが読み取る内容 · なぜ別のブラウザーMCPなのか? · ツール · 設定 · FAQ · エージェントなしで試す · 関連情報
セッションの実際の様子
次のように依頼します。
example.comを開いて、ページに何が書かれているか教えてください。
エージェントは次のように動作します。これがエージェントに見えるすべてです。
browser_open("https://example.com")
[obs#1] https://example.com/ "Example Domain" scroll=0/216 reachable=1/1
e1 lnk More information...
browser_observe()
[delta#2] … 1 element
= no change (1 element)
その後、エージェントが回答します。スクリーンショットは撮影されず、HTMLもダンプされず、ページがモデルのコンテキストに入ることもありません。エージェントは表を読み取って回答しました。
より実際的な例として、エージェントが操作しながら、実在のサイトを検索する場合は次のとおりです。
browser_open("https://duckduckgo.com")
e4 cmb* Search with DuckDuckGo ▸ ""
browser_act([{type, ref: "e4", text: "python asyncio tutorial"}, {keys, key: "Enter"}])
→ 2/2 ops ok, one round trip, page navigated
browser_observe()
[delta#3] https://duckduckgo.com/?…&q=python+asyncio+tutorial reachable=9/59
+ e5 lnk Python Asyncio Tutorial
+ e6 lnk Async IO in Python: A Complete Walkthrough
…
43 new, 0 changed, 0 gone
browser_assert([{url_contains, text: "q="}, {count_at_least, role: "link", min: 5}])
PASS
これはライブウェブでの実行をそのまま記録したものです。scripts/live_check.pyを使うと、最初から最後まで再現できます。
エージェントの接続
| クライアント | install.py が書き込む設定ファイル | インストール後 |
|---|---|---|
| WorkBuddy | ~/.workbuddy-ai/mcp.json(古いインストールでは ~/.workbuddy/mcp.json) | 再起動してから、Connectors → Custom connectors → Trust |
| Claude Code | ~/.claude.json(ユーザースコープ) | または claude mcp add --scope user … |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json | アプリを完全に終了してから、再度開く |
| Codex CLI | ~/.codex/config.toml | codex mcp list で確認 |
| Cursor | ~/.cursor/mcp.json | ウィンドウを再読み込み |
| VS Code (Copilot) | …/Code/User/mcp.json | エージェントモードのみ — Ask/Edit では利用できません |
| Cline | …/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json | ウィンドウを再読み込み |
| Windsurf | ~/.codeium/windsurf/mcp_config.json | ウィンドウを再読み込み |
| Gemini CLI | ~/.gemini/settings.json | gemini mcp list で確認 |
手動セットアップ — インストーラーを実行しない場合
以下の各クライアントで必要なのは、絶対パスのインタープリター、モジュール、環境変数の3つです。
/ABS/PATH はご自身のパスに置き換えてください。
WorkBuddy — ~/.workbuddy-ai/mcp.json
WorkBuddy は WORKBUDDY_CONFIG_DIR から設定ディレクトリを読み込み、設定されていない場合は
~/.workbuddy を使用します。古いアプリと現在のアプリが併存しているなど、1台のマシンに両方の
ディレクトリが存在することがあります。アプリが読み込んでいない方に書き込んでも、登録されず、
ログにも残りません。install.py はアプリと同じ方法でこれを判定し、どちらを選ぶ必要があったかを
お知らせします。
ツールを探す前に、アプリを再起動してください。 設定ファイルが監視されるのは、アプリの起動時に すでに存在していた場合だけです。そのため、新しく作成したファイルは次回の起動まで認識されません。 再起動後、サーバーが最初の接続先として表示されるので、一度だけ承認してください。
{
"mcpServers": {
"jev-ultrafast-mcp": {
"command": "/ABS/PATH/jev-ultrafast-mcp/.venv/bin/python",
"args": ["-m", "jev_ultrafast_mcp"],
"env": { "JEVMCP_HEADLESS": "1" }
}
}
}
Claude Code
claude mcp add --scope user jev-ultrafast-mcp \
--env JEVMCP_HEADLESS=1 \
-- /ABS/PATH/jev-ultrafast-mcp/.venv/bin/python -m jev_ultrafast_mcp
同じ mcpServers オブジェクトを手動で記述することもできます。ユーザースコープでは ~/.claude.json、
チームスコープではプロジェクト内の .mcp.json(git にコミット)を使用します。
Codex CLI — ~/.codex/config.toml。Codex は TOML を使用し、テーブル名は mcpServers ではなく
mcp_servers です。
[mcp_servers.jev-ultrafast-mcp]
command = "/ABS/PATH/jev-ultrafast-mcp/.venv/bin/python"
args = ["-m", "jev_ultrafast_mcp"]
startup_timeout_sec = 20
[mcp_servers.jev-ultrafast-mcp.env]
JEVMCP_HEADLESS = "1"
同じ設定は codex mcp add jev-ultrafast-mcp --env JEVMCP_HEADLESS=1 -- /ABS/PATH/…/python -m jev_ultrafast_mcp としても追加できます。
Cursor — すべてのプロジェクトでは ~/.cursor/mcp.json、1つのプロジェクトでは .cursor/mcp.json を使用します。
WorkBuddy と同じ mcpServers オブジェクトを指定します。
VS Code (Copilot) — .vscode/mcp.json、またはすべてのワークスペースに適用する場合は、コマンドパレット →
MCP: Open User Configuration を使用します。VS Code は2つの点で例外です。キーは servers であり、
各エントリに "type": "stdio" を指定しないと、警告なしにスキップされます。
{
"servers": {
"jev-ultrafast-mcp": {
"type": "stdio",
"command": "/ABS/PATH/jev-ultrafast-mcp/.venv/bin/python",
"args": ["-m", "jev_ultrafast_mcp"],
"env": { "JEVMCP_HEADLESS": "1" }
}
}
}
Claude Desktop — claude_desktop_config.json(Windows では %APPDATA%\Claude\)を使用し、
同じ mcpServers オブジェクトを指定します。ウィンドウを閉じるだけでなく、トレイからアプリを再起動してください。
ブラウザーが起動するのは最初の browser_open の後です。また、操作対象のタブは、このツールが所有する
バックグラウンドタブです。フォーカスをエミュレートすることで、ウィンドウを奪うことなく、
アニメーションやメニューを動作させ続けます。
エージェントが実際に引き継ぐようにする
クライアントをサーバーに向けるのは、半分にすぎません。もう半分は、エージェントが引き継ぐ必要があると理解することです。そして、これはどの環境でも自動的に行われるわけではありません。
クライアントが接続すると、サーバーは短い instructions ブロックを送信します。その最初のルールでは、ブラウザーのタスクはURLを指定して、1回の呼び出しで browser_goal に渡すよう定めています。これを読み取るクライアントなら、適切に動作します。ただし、すべてのクライアントがそうするわけではありません。WorkBuddyはサーバーのツールをモデルに渡しますが、instructions は破棄します。これは推測ではなく、実測した結果です。記録されたリクエストのペイロードにはツールスキーマが含まれていますが、instructionsのテキストは含まれていません。このようなホストは当然、1回のクリックごとに1回呼び出して自らページを操作しますが、まさにその作業を引き受けるために、このサーバーは存在します。
このギャップを埋める方法は2つあります。どちらか一方で十分です。
-
スキルをインストールする。
skills/jev-ultrafast-mcp/SKILL.mdには、クライアントがスキルとして読み取れる形式で同じルールが記載されており、実行を無駄にする落とし穴も説明されています。 クライアントのスキルフォルダーにコピーしてください(WorkBuddyの場合は~/.workbuddy/skills/)。mkdir -p ~/.workbuddy/skills/jev-ultrafast-mcp cp /path/to/jev-ultrafast-mcp/skills/jev-ultrafast-mcp/SKILL.md ~/.workbuddy/skills/jev-ultrafast-mcp/ -
または、一度だけ伝える。 ほとんどのセッションでは「ブラウザーのタスクは
browser_goalに渡してください」と伝えるだけで十分です。そう伝えられたエージェントは、その後も同じように動作します。
引き継ぎが行われたか確認する方法。 クリックが必要な作業を依頼してください。呼び出し内に url を含む browser_goal が返ってきたら、引き継ぎは有効です。代わりにエージェントがページを開き、要素テーブルを順にたどり始めたら、ルールが届いていません。スキルをインストールするか、一度だけ伝えてください。
依頼できること
| こう依頼してください | 動作 |
|---|---|
| 「このフォームに入力して送信して」 | 全体を引き継ぎ — URL、目標、確認手順を含む1回の browser_goal を実行し、ループはサーバー側で処理されます |
| 「ステージング環境でこのフローを実行して、うまくいったか教えて」 | 同じく1回の呼び出しです。verify がコードでPASS/FAILを判定し、モデル自身の説明より優先されます |
| 「明日、同じことをもう一度やって」 | マクロを記録します。再生にモデルの呼び出しは不要で、キーも一切必要ありません |
| 「このページを開いて、何が書いてあるか教えて」 | タスクではなく、ページの確認です。表示テキストとコントロールを読み取ります。モデルもキーも不要です |
| 「デプロイは本当に反映された?」 | browser_assert は意見ではなく、PASS/FAILを返します |
| 「ログインして、先月の請求書をダウンロードして」 | 最初に一度だけ手動でログインすれば、プロファイルは保持されます |
| 「ステージング環境でチェックアウトを進めて」 | 支払いに関係するボタンは needs_confirmation として返されます |
対応していないこと
この点を明確にしておけば、誰にとっても時間の節約になります。
- ピクセルは解析しません。 CAPTCHA、チャート、キャンバスのみで構成されたアプリなど、実際の視覚的な判断が必要なものは対象外です。そのような場合は、スクリーンショットと視覚解析を使うエージェントを利用するか、このサーバーの
screenshotopで、人間が確認するための証拠を取得してください。 - スクレイピング用フレームワークではありません。 一度に操作できるブラウザーとセッションは1つだけです。プロキシのローテーション、並行処理、大規模なクロールには対応していません。
- 人間向けのレコーダーではありません。 クリックして記録するUIはありません。エージェントが通常どおりタスクを実行する中で、マクロが記録されます。
エージェントが実際に読み取る内容
DOM のダンプでもスクリーンショットでもなく、操作可能なコントロールの表です。各行には、ref
(要素番号)、ロールコード、フラグ、アクセシブル名が含まれます。編集可能な項目には現在の値が、選択可能な項目には選択肢が表示されます。
[obs#1] http://127.0.0.1:54409/fixture.html "Ultrafast Fixture" scroll=0/860 reachable=16/16
e1 lnk Home
e2 lnk About
e3 lnk Open popup
e4 inp* Where from? ▸ ""
e5 cmb* Where to? ▸ ""
e6 cmb Passengers ▸ 1 adult opts{1 adult=1 | 2 adults=2 | 3 adults=3 | 4 adults=4}
e7 chk· Nonstop only
e8 btn Search
e10 inp* Password ▸ ""
e11 file CV accept=.pdf,.txt
e12 btn Delete account
フラグ:* 編集可能 · » 画面外(サーバーが表示範囲内にスクロールします) · ⊘ 別の要素に覆われています
· ⊗ 存在しますが無効です · ⋮ メニューを開きます。まずホバーしてください · ▾ 展開済み · ✓/· チェック状態です。
reachable=16/19 は、コントロールが3つ存在するものの、現時点では覆われているか、画面外にあるか、無効になっていることを意味します。無効な項目も、フォームが何を待っているか確認できるよう一覧に表示されますが、クリックする項目として提示されることはありません。
アクションの後には、変更された内容だけが報告されます。長いループで最も大きな節約になる点です。
[delta#2] http://127.0.0.1:54409/fixture.html "Ultrafast Fixture" reachable=16/16
~ e4 inp* Where from? ▸ "Zurich" (was "")
~ e7 chk✓ Nonstop only
2 changed, 0 new, 0 gone
何も達成できなかったアクションは、エージェントのループにおいて最もコストがかかります。モデルが再試行するためです。そのため、1行で明示されます。
[delta#3] … 16 elements
= no change (16 elements)
新しい行は + 付きで表示され、消えた行には - が付きます。名前が同じコントロールが2つある場合は、区別できるよう行にコンテキストが付加されます。
+ e17 btn Select @Zurich → Anywhere Option 1 · 1 adult · nonstop Select
+ e18 btn Select @Zurich → Anywhere Option 2 · 1 adult · nonstop Select
もはや何も指していない ref は、誤ったクリックを行う代わりに、理由を添えて拒否されます。
[{"op": "click", "ok": false, "ref": "e999", "error": "detached"}]
自分のページでこの表を確認する
chrome-extension/
にある拡張機能を使うと、表を確認できます。パッケージ化されていない拡張機能として読み込み、どのページでもアイコンをクリックすると、モデルが受け取るのと同じ行が表示されます。同じオブザーバーと同じレンダラーの移植版が使われているため、ポップアップ内の ref はセッション内と同じものを指します。ページを2回目に読み取ると差分が表示されるので、ページの変化を確認できます。
さらに、ループ内にモデルを介さずマクロを実行できます。リゾルバー、ディスパッチャー、レポートライターはすべてサーバー自身のコードを移植したものなので、そこでの再生はここでの再生と同じです。
この2つの機能があるため、必要な権限は4つだけで、ホストへのアクセスは一切求めません。activeTab(クリックしたタブのみ。それ以外にはアクセスしません)、scripting、storage、debugger です。最後の権限は再生のために必要ですが、近道ではありません。element.click() は isTrusted: false のイベントを生成し、サイト側で無視できます。そのため、再生されたクリックを確実なものにするには、DevTools プロトコルを経由させる必要があります。拡張機能の
README では、これによって得られるもの、必要なコスト、そして指定したタブの外部にアクセスする代わりに実行を見送る4つの操作について説明しています。
もう一つのブラウザー MCP が必要な理由
違いは2つあります。1つ目が、このツールを作った理由です。
操作するのはエージェントの役目ではありません。 ブラウザーフローはループであり、ほとんどのサーバーでは、そのループは呼び出し元のエージェント側にあります。ページを読み、要素を1つ指定し、待って、また読みます。2ステップなら問題ありませんが、20ステップでは無駄が多すぎます。小さなモデルなら1回の呼び出しでできることに、高価なコンテキストを20ターンも費やすことになります。ここではループはサーバー上で動きます。1回の browser_goal 呼び出しに URL、目標、確認方法を渡せばよく、エージェントがブラウザーを直接開くことはありません。手動ツールは、必要な2つのケースに備えて残しています。ページを読む場合(これはタスクではないため、モデル呼び出しを消費すべきではありません)と、モデルキーが設定されていない場合の代替手段です。
モデルが対象をでっち上げることはありません。 ほとんどのブラウザー MCP サーバーは、CDP のプリミティブである click_at_xy、CSS セレクター、evaluate を渡します。柔軟性は最大ですが、安全性は最低です。誤ったセレクターは何も起きずに失敗するか、さらに悪い場合は、間違った要素に対して成功してしまいます。ここでは、対象はページ上の要素を番号付きで並べた表にある ref で指定します。その ref を実際のクリックに変換するのはサーバーの役目で、サーバーは推測せずに拒否します。これにより、操作の引き継ぎも安全になります。操作する側は、ページに実際に表示されている選択肢から選ぶため、正確さは慎重さに頼りません。
| プリミティブベースのブラウザー MCP | jev-ultrafast-mcp | |
|---|---|---|
| ループを実行するのは誰か | 呼び出し元のエージェントが各ステップで実行 | サーバー — 1回の browser_goal 呼び出し |
| 対象の指定方法 | モデルが記述するセレクター/座標/JS | 要素テーブルの ref |
| 追加のモデル呼び出し | なし | 各ステップで小さな判断モデルを1回。ただし browser_goal 内のみ |
| API キーの要否 | なし | ブラウザーツールには不要。browser_goal のみ判断モデルのキーが必要 |
| Ref の有効期間 | 該当なし(エージェントが各ステップで再指定) | 観察をまたいで安定 |
| ページの再読み込み | 毎回すべてをダンプ | 差分 — 追加は +、変更は ~、削除は -、変更なしは = |
| 往復回数 | アクションごとに1回 | まとめて実行 — 1回の呼び出しで複数の操作 |
| 対象が曖昧な場合 | エージェントが推測 | サーバーが理由を示して拒否 |
| Shadow DOM/iframe | 通常は未対応 | 走査し、フレームオフセットを考慮してスクロール |
| 描画が遅いページ | エージェントが待機するかどうかによる | 要素が表示されるまで、上限付きで待機 |
| フローの繰り返し | モデルを再実行 | モデルコストゼロでマクロを再生 |
| 成功したかどうかの確認 | モデルがページを目視で確認 | モデルの判断に優先する、決定的な browser_assert |
| 破壊的なクリック | モデルの判断次第 | needs_confirmation、ドメインの範囲設定、シークレットのマスキング |
バッチ処理と差分は、見た目だけの機能ではありません。同梱のエンドツーエンド実行では、29個の操作とその後の観察に必要なコンテキストは 15.4 KB でした。そのうち 13.6 KB は差分、1.8 KB は全テーブル です。モデルが再読み込みするのは、変化したページの部分だけです。
ツール
10個のツールがあります。ほとんどのセッションで使うのは、そのうち4つです。
| ツール | 説明 |
|---|---|
browser_open | 独自のタブで URL を開き、要素テーブルを返します |
browser_observe | ページを再読み込みします。差分、または必要に応じて全テーブルを返します |
browser_act | 1回の往復で操作のリストを実行し、差分を返します |
browser_assert | モデルの判断を介さずに、ページを決定的にチェックします |
browser_macro | フローを一度記録し、モデル呼び出しゼロで再生します |
browser_goal | タスク全体を引き渡します。判断モデルがページを操作します |
browser_tabs | タブの一覧表示、作成、切り替え、終了を行います |
browser_sessions | 実行中のブラウザーセッションを一覧表示します |
browser_close | セッションを終了します |
browser_doctor | セルフチェックを行います。検出されたブラウザーと、応答の有無を確認します |
browser_open(url, session="default", hint="")
独自のタブで URL を開き、要素テーブル全体を返します。hint は目標を1行で言い換えるもので、そのまま返されます。
browser_observe(session="default", mode="auto", include_text=True, include_json=False)
ページを再読み込みします。auto は差分を出力し、full はテーブル全体を強制的に出力し、delta は差分を強制的に出力します。
= no change は最後のアクションで何も起きなかったことを意味します — 戦略を変えてください。再試行しないでください。
browser_act(ops, session="default", dry_run=False, stop_on_error=True, observe_after=True)
1 回の ラウンドトリップ で ops を順に実行し、その後、差分を返します。
| op | fields |
|---|---|
click | ref |
type | ref、text、clear=true、submit=false、slow |
select | ref、value(オプションの値またはラベル) |
toggle | ref、state(省略すると切り替え) |
hover / upload | ref / ref、path |
keys | key("Enter"、"Meta+A"、"ArrowDown")、または keys(リスト)— 単一の文字だけを指定するとキー押下ではなくテキストとして扱われ、フォーカス中の要素に入力されます。また、値をページ外に出してはならないフィールドでは拒否されます |
scroll | dir、amount、ref |
nav / back / forward / reload | url(nav の場合) |
wait / wait_for_ref / wait_for_text / wait_for_load | ms / ref,timeout_ms / text / timeout_ms |
screenshot | path(shots ディレクトリ内のファイル名)、full、format(jpeg または png) |
tab | action=list|new|switch|close、target_id、index、url |
eval | js — JEVMCP_ALLOW_JS=1 の場合のみ |
{"ops": [
{"op": "type", "ref": "e4", "text": "Zurich"},
{"op": "select", "ref": "e6", "value": "3 adults"},
{"op": "toggle", "ref": "e7"},
{"op": "click", "ref": "e8"}
]}
失敗した op は理由を報告します:occluded、detached、target_changed、page_changed、
needs_confirmation、blocked_by_policy。再試行するのではなく、browser_observe を使ってください。
アクセシブル名が確認ルール(buy now、delete account、
unsubscribe など)に一致するコントロールは、op に "confirm": true が含まれるまで needs_confirmation を返します。
これは クリックを行うすべての op に適用され、click という名前の op だけに適用されるわけではありません — toggle もコントロールを押します。
名前がアクション名に該当するかどうかを判定するロール(「Delete account」というラベルのチェックボックスではクリックが停止されませんが、ボタンでは停止されます)は、op からではなく、サーバーが観測した要素から読み取られます。そのため、リクエストの "role" では制限を解除できません。同じルールは type にも適用されます。ページがフラグを付けたフィールド または 名前とロールから判断されるフィールドは機密扱いです — 観測によってマスクされる対象の和集合であり、テーブルで値が非表示になっているフィールドが type の対象となるフィールドです。
タブには、index より target_id を優先してください。インデックスは位置に基づき、タブ一覧が変わるたびに番号が振り直されるため、1 つ前の呼び出しで読み取ったインデックスが別のタブを指す場合があります。
browser_assert(checks, session="default")
決定的なチェックです — 成功したかどうかをモデルが判断することはありません。
{"checks": [
{"type": "url_matches", "pattern": "*/checkout*"},
{"type": "text_contains", "text": "Order confirmed"},
{"type": "element_exists", "role": "button", "name": "Continue"},
{"type": "value_equals", "ref": "e4", "value": "Zurich"},
{"type": "count_at_least", "role": "link", "min": 3}
]}
browser_macro(action, session="default", name="", params={}, ...)
record_start → タスクを実行 → record_stop → run。リプレイには モデル呼び出しが不要 です。タスクを開始した場所に戻り、ロールとアクセシブル名を使って各ステップを再解決します。誤った要素をクリックする可能性がある、確度の低い一致や曖昧な一致は拒否します。params は入力テキストと URL 内の {{placeholders}} を置き換えます。
browser_goal(goal, url="", session="default", max_steps=20, verify=[...])
タスク全体を引き渡します。url と目標を渡すと、ページが開かれ、TypeSafe の投機的ファンアウト(ステップごとに 1 リクエスト)を使って、サーバー側で最後まで操作されます。1 回の呼び出しで 1 ターンです。セッションで現在表示されているページから続ける場合は、url を省略します。意思決定モデル用のキーが必要です。Jev 独自の API では TYPESAFE_API_KEY、または JEV_PROVIDER=openrouter を設定した OPENROUTER_API_KEY(同等の設定として、TYPESAFE_BASE_URL を OpenRouter の decisions ルートに指定できます)を使用します。verify のチェックを指定すると、verified: PASS/FAIL が返されます。
ページを読むことはタスクではありません。browser_open、browser_observe、browser_assert は直接実行でき、無料でキーも不要なので、ページを見るだけならコストはかかりません。引き渡し機能は、ページを変更する作業に使います。
実行ごとに、処理のコストも報告されます。たとえば turbo: 4 decisions · 14,626 tokens · 1.8s model + 1.1s page · 3.3s wall のように、引き渡しにかかったコストと、壁時計時間のうちモデルとページそれぞれにかかった時間が回答に表示されます。
意思決定モデルが失敗するあらゆるケース(キーがない、クレジットがない、接続できない、回答が不正な形式、本文が JSON ではない)では、何も実行されずに turbo_unavailable: が返されます。すでに実行されたステップのトレースは保持されるため、5 番目のステップで実行が停止しても、最初の 4 ステップで行われたことが報告されます。
status は主にモデル自身が要約しますが、ループも書き込みを行います。書き込まれる値の意味を知っておくと便利です。連続して 3 回、操作によって何も変化しないと stopped: no progress になります。ページはこれ以上進展しないため、残りの max_steps を費やして確かめることなく、そこで実行を停止します。予算を使い切ると stopped: hit max_steps になります。この 2 つは意図的に意味が異なります。前者はやることが残っていないことを示し、後者はまだやることがあるかもしれないことを示します。
verify はコードでチェックされるため、要約とページの内容が食い違う場合はアサーションが優先されます。ページがチェックに合格すれば、モデルの判断にかかわらず、実行結果は status: done と報告され、トレースにはモデルの判断を覆したことが記録されます。目標を達成する最後の操作によって、その操作対象がページからなくなる場合はよくあります。たとえば、チェックインボタンをクリックするとそのボタンが消えるため、モデルは残っている作業がないと判断し、実際には成功した目標を BLOCKED と報告することがあります。
browser_tabs · browser_sessions · browser_close · browser_doctor
タブ管理(一覧表示/新規作成/切り替え/閉じる)、セッション一覧表示、終了処理、および検出されたブラウザーとその接続可否を報告する自己診断機能です。
設定
すべて任意です。デフォルト設定のまま使うことを想定しています。
| 変数 | 必須 | デフォルト | 説明 |
|---|---|---|---|
| いいえ | JEVMCP_CHROME | 自動検出 | Chrome/Chromium/Edge/Brave の実行ファイル |
| いいえ | JEVMCP_MODE | launch | ブラウザーを launch するか、実行中の CDP エンドポイントに attach するか |
| いいえ | JEVMCP_CDP_URL | — | mode=attach の場合は http://127.0.0.1:9222、または検出をスキップするための ws:// URL |
| いいえ | JEVMCP_ATTACH_PROFILE_DIR | (ブラウザーのデフォルト) | DevToolsActivePort が自動検出されない場合に、接続先ブラウザーのデータディレクトリ |
| いいえ | JEVMCP_HEADLESS | 1 | ウィンドウを表示する場合は 0 |
| いいえ | JEVMCP_FOREGROUND | 0 | 所有するタブをアクティブにする場合は 1 |
| いいえ | JEVMCP_SANDBOX | auto | ブラウザーの起動時に異常終了した場合、--no-sandbox を付けて再試行するには auto を指定します |
| いいえ | JEVMCP_WINDOW | 1280x860 | ブラウザーのウィンドウサイズ |
| いいえ | JEVMCP_PROFILE_DIR | ~/.jev-ultrafast-mcp/chrome-profile | 永続プロファイル。ログインは一度だけで、その後もログイン状態が維持されます |
| いいえ | JEVMCP_ALLOW_DOMAINS | (すべて) | カンマ区切り。指定外の場所への移動は拒否されます |
| いいえ | JEVMCP_DENY_DOMAINS | (なし) | カンマ区切りのブロックリスト |
| いいえ | JEVMCP_CONFIRM_PATTERNS | pay / delete / unsubscribe … | これらに一致するクリックには "confirm": true が必要です |
| いいえ | JEVMCP_ALLOW_JS | 0 | eval と js アサーションを有効にします |
| いいえ | JEVMCP_ALLOW_UPLOADS | 1 | upload 操作を制御します |
| いいえ | JEVMCP_MAX_ACTIONS | 250 | 有用性に基づいて適用される、要素テーブルの上限 |
| いいえ | JEVMCP_MAX_TEXT | 6000 | 1 回の観察で取得する可視テキストの上限 |
| いいえ | JEVMCP_SETTLE_TIMEOUT | 4.0 | URL を開いた後、ページの読み込みが止まり、要素テーブルの変化が止まるまで待機する時間 |
| いいえ | JEVMCP_SETTLE_POLL_MS | 120 | 待機中に再読み込みする間隔 |
| いいえ | JEVMCP_STATE_DIR | ~/.jev-ultrafast-mcp | プロファイル、マクロ、スクリーンショット |
| いいえ | JEV_PROVIDER | typesafe | 判断モデルの料金を支払う API。typesafe(Jev 独自)または openrouter |
| いいえ | TYPESAFE_API_KEY | — | Jev 独自 API のキー |
| いいえ | TYPESAFE_BASE_URL | https://api.typesafe.ai/v1/systemone | 判断モデルのエンドポイント。カスタムエンドポイントであり、JEV_PROVIDER が未設定の場合はプロバイダーの推定元にもなります |
| いいえ | OPENROUTER_API_KEY | — | JEV_PROVIDER=openrouter の場合に、OpenRouter の判断ルートで使用するキー |
| いいえ | TYPESAFE_MODEL | jev-latest | 判断モデルのスラッグ |
| いいえ | TEXT_MODEL_API_KEY | — | 任意。browser_goal がフィールドに値を入力する際に使用する、小規模なテキストヘルパー専用です。未設定の場合、ヘルパーは判断モデルのプロバイダーを引き継ぎます |
| いいえ | TEXT_MODEL_BASE_URL | https://api.deepseek.com/v1 | ヘルパーのエンドポイント。これを設定するか TEXT_MODEL_API_KEY を設定すると、判断モデルのプロバイダーの引き継ぎが解除されます |
| いいえ | TEXT_MODEL | deepseek-chat | ヘルパーのモデル。deepseek-chat は OpenRouter のスラッグではないため、プロバイダーを引き継ぐ場合は必須です |
JEVMCP_MODE=attach は、「すでに開いているブラウザーを使う」方法です。必要なログイン情報がすでに自分のプロファイルに保存されている場合に使います。Chrome 144 以降では chrome://inspect/#remote-debugging を通じてこれを利用できます。サーバーは仕様上、/json/version に 404 を返しますが、jev はこれを「リッスンしていない」と判断せず、DevToolsActivePort にフォールバックします。アタッチモードで操作するのは、jev が開いたタブだけです。browser_close はブラウザーを終了せずに接続を解除し、サーバーの終了時も同様です。ほかのウィンドウや、そこにあるセッションが閉じられることはありません。
最後の 8 行より上の設定はすべてローカルで、マシン上のブラウザーを設定するものです。ネットワークと通信するのは判断モデルの設定だけで、browser_goal が実行された場合に限られます。
意思決定モデルには2つのルートがあり、JEV_PROVIDERでどちらを使うか指定します。typesafeはJev独自のAPIです。openrouterはOpenRouterの意思決定ルート経由で同じモデルを利用するもので、TypeSafeアカウントは不要です。また、この環境変数が導入される前からあるルートです。どちらの場合もTYPESAFE_BASE_URLでURLを上書きできます。JEV_PROVIDERが未設定の場合は、このURLからプロバイダーが推定されるため、この名前が導入される前に書かれた設定も変更せずに動作します。
チャットAPIも提供するのはOpenRouterルートだけなので、テキストヘルパーを継承できるのもこのルートだけです。JEV_PROVIDER=openrouterを設定し、TEXT_MODELでチャットモデルを指定すれば、1つのOPENROUTER_API_KEYで両方を利用できます。Jev独自のAPIは型付きの質問に回答し、文章を生成することはありません。そのため、このAPIでTYPE_TEXTを使うには、TEXT_MODEL_API_KEYを通じて別のチャットプロバイダーを用意する必要があります。どちらの場合も、キーとURLは必ず同じプロバイダーから取得されます。別のプロバイダーのキーを流用すると、呼び出していない会社名が記された401エラーが発生します。また、間違ったプロバイダーのエラーをもとに実行を診断しても、問題の原因は特定できません。
自分のアカウントでエージェントを使う前に設定しておきたい項目が2つあります。
JEVMCP_ALLOW_DOMAINSでブラウザーのアクセス先をホストの一覧に制限し、それ以外を拒否できます。また、永続化されるJEVMCP_PROFILE_DIRを設定すれば、モデルにパスワードを教える代わりに、一度だけ手動でログインできます。
FAQ
つまり、別のモデルに作業させるだけですか? 誰が主導権を持つのですか?
主導権を持つのはあなたで、タスクごとに選べます。browser_goalは、小さな意思決定モデルであるJevに1つの目標を任せ、ページ上のどの要素を操作するかを一度に1ステップずつ決めさせます。これは汎用エージェントではなく、目標をまたいで記憶を保持することも、コードやセレクターを書くこともありません。サーバーから渡された選択肢の中から選ぶだけです。何を依頼するかは引き続きあなたのエージェントが決め、実際に処理が行われたかどうかはverifyが判断します。すべてのステップに自分も関わりたい場合は、そのツールを呼び出さなければよいだけです。他に何かをどこかへ送信する機能はありません。
APIキーやアカウントは必要ですか?
ブラウザーツールには必要ありません。browser_open、browser_observe、browser_act、browser_assert、browser_macroおよびタブ/セッションツールが外部に接続することはありません。テレメトリーも、ホームへの通信もなく、マシンの外へ情報が送られることはありません。例外はbrowser_goalですが、これはオプトインです。目標と現在の要素テーブルを意思決定モデルに送信するため、キーが必要です。このツールを使わなければ、ページに関する情報が外部へ送られることはありません。
ブラウザーウィンドウが開いて、画面を占有しますか?
いいえ。デフォルトではヘッドレスで実行され、所有するバックグラウンドタブを操作します。アニメーションやメニューは引き続き動作しますが、フォーカスが奪われることはありません。動作を見たい場合は、--headed(またはJEVMCP_HEADLESS=0)を指定するとウィンドウが表示されます。
ログイン済みのサイトで使うにはどうすればよいですか?
JEVMCP_PROFILE_DIRに永続化するディレクトリを設定し、ブラウザーを一度手動で開いてログインします。セッションは記憶されます。エージェントにパスワードを教えるより、はるかに安全です。さらに、パスワードを入力した場合、観測結果ではパスワード欄がマスキングされます。
すでに開いていてログインも済んでいるブラウザーを、そのまま使えますか?
はい。JEVMCP_MODE=attachとJEVMCP_CDP_URL=http://127.0.0.1:9222を指定すると、自分のChromeを操作できます。Chrome 144以降では、chrome://inspect/#remote-debuggingからデバッグを有効にできます。再起動は不要なので、タブやログイン状態は維持されます。また、Chromeからクライアントの接続を許可するよう求められます。最初の接続はそのクリックを待つため、失敗したと判断する前に少し待ってください。
操作するたびに、そのクリックを承認する必要がありますか?
いいえ。承認が必要なのはブラウザーセッションごとであり、接続ごとでも操作ごとでもありません。一度承認すれば、その後のすべての操作は同じ WebSocket 接続を使い、再び確認を求められることはありません。新しいプロセスから接続した場合でも同様です(実測では、クリックから 20 分後に 3 つの新しいプロセスが接続し、すべて確認なしで承認されました)。つまり、必要なのはブラウザーセッションごとに 1 回のクリックであり、操作ごとではありません。それすら不要にするには、デフォルトの JEVMCP_MODE=launch を使用してください。実際のデバッグポートで独自のブラウザーを起動するため、承認ダイアログは表示されません。ただし、そのプロファイルで一度ログインする必要があります。
curl http://127.0.0.1:9222/json/version の結果が 404 です。デバッグは有効になっていますか?
おそらく有効です。chrome://inspect/#remote-debugging の背後にあるサーバーは WebSocket 専用で、HTTP の検出エンドポイントを意図的に提供していません。そのため、404 は設定の不具合ではなく、ドキュメントに記載されている動作です(両方ともポート 9222 と表示されますが、--remote-debugging-port=9222 とは別のものです)。jev はこのエンドポイントに依存しません。/json/version から応答がない場合は、Chrome の DevToolsActivePort ファイルからポートとブラウザーの WebSocket パスを読み取ります。ブラウザーのデータディレクトリが通常とは異なる場所にある場合は、JEVMCP_ATTACH_PROFILE_DIR にその場所を指定してください。
何も起こらず、ページが空に見えます。
JavaScript で描画されるページは、一時的に空に見えることがあります。URL を開いた後、サーバーはページへのリクエストが止まり、さらに要素テーブルの変化も止まるまで待ってから、モデルにページを渡します(最大 JEVMCP_SETTLE_TIMEOUT)。静止するまで待つだけでは不十分です。バンドルをまだ取得していないアプリはシェル状態であり、シェルは完全に静止しているからです。サイトが Cookie の同意画面や同意ダイアログの背後で止まっている場合は、要素テーブルに表示されます。観測ヘッダーにオーバーレイの警告がないか確認してください。
CAPTCHA があります。解決できますか? いいえ。意図的に、ピクセルを見ることはありません。その場合は、スクリーンショットと画像認識を使うエージェントを使用してください。
PyPI にありますか?MCP レジストリにはありますか?
PyPI にはあります。pip install jev-ultrafast-mcp を実行するか、何もインストールせずに実行するには uvx jev-ultrafast-mcp を使ってください。レジストリにはまだ登録されていませんが、手作業で残っている作業はありません。
server.json はレジストリのスキーマに対する検証に合格しており、リリースワークフローが各タグの作成時に OIDC 経由で送信するため、次回のリリースで登録されます。詳細は
公開をご覧ください。
Playwright MCP とはどう違いますか? Playwright のサーバーはページの基本操作を公開し、エージェントがセレクターと座標を記述します。こちらは、番号付きの操作対象テーブルを公開し、曖昧な対象を拒否します。ピクセル単位の操作や、成熟した記録型テストのエコシステムが必要なら、Playwright を使ってください。エージェントが誤ったボタンを気付かれないままクリックできないようにしたいなら、こちらを使ってください。
browser-use の代替ですか?
同じ問題を、正反対のアプローチで解決しています。browser-use
はエージェントのループをプロセス内で実行するライブラリです。こちらは、すでにお使いのエージェントに同じような操作手段を提供する MCP サーバーです。こちらのオプションのターボパスは、
browser-use/jev-ultrafast の移植版です。自由形式のテキストではなく、各ステップで判断モデルに型付きの質問を 1 つずつ尋ねます。
自分のアカウントを任せても安全ですか?
信頼してはいけないことを前提に設計されています。破壊的に見えるクリックは実行されずに needs_confirmation が返され、JEVMCP_ALLOW_DOMAINS によって指定したドメイン以外への移動が拒否されます。機密フィールドはマスキングされ、eval は有効にしない限りオフです。まずドメインの許可リストを設定し、問題が起きても構わないアカウントで試してください。
値をページ外に出してはならないフィールドは、テーブル内でマスキングされ、入力するには "confirm": true が必要で、マクロには平文ではなく {{secret}} として記録されます。そこにテキストを入力できる操作は2つあり、2つ目は見落としやすいものです。keys に単独の文字を指定すると({"op": "keys", "keys": "a"})、キー押下ではなく Input.insertText が送信されるため、フォーカスされている場所に入力されます。この操作は、確認を求めるのではなく、機密フィールドでは拒否されます。ref がなく、マクロには文字列が記録されるため、再生時に戻せるプレースホルダーが存在しないからです。フィールドの ref を指定して type を使ってください。
ここでデフォルトで有効になっており、制限もない機能は upload です。これは、このマシン上にある任意のファイルまたはディレクトリをページに渡すため、エンベロープで許可されているホスト上のページがそれを受け取る可能性があります。タスクでファイルを添付する必要がない場合は、JEVMCP_ALLOW_UPLOADS=0 を設定してください。スクリーンショットはその逆で、制限されています。状態ディレクトリ内にのみ書き込めます。
エージェントを使わずに試す
.venv/bin/python scripts/smoke.py # headless, 61 checks
.venv/bin/python scripts/smoke.py --headed # watch it drive
Chrome を起動し、tests/fixture.html を配信して、実際のコードパスを実行します。バッチ実行、オートコンプリート、画面を覆うモーダル、シャドウ DOM、同一オリジンの iframe、ファイルのアップロード、パスワードフィールド、破壊的なクリックのガード、古い ref、マクロの記録と再生、タブの受け渡し、スクリーンショット、および readyState がすでに "complete" を示した後にレンダリングされるページをテストします。
1. Observation — one atomic read, indexed refs
[ok ] element table is not empty — 16 elements
[ok ] shadow DOM element indexed — Shadow action -> e14
...
5. Occlusion — precomputed, not discovered by a failed click
[ok ] covered control flagged before any click — e8 occluded=True
[ok ] click on a covered control is refused with a reason — occluded
...
61/61 checks passed
フィクスチャではなく、実際のウェブサイトでテストするには、次のようにします。
.venv/bin/python scripts/live_check.py # Bing + DuckDuckGo + tabs + screenshots
.venv/bin/python scripts/live_check.py --headed # watch it happen
このテストにはネットワークとサードパーティーのサイトが必要なため、意図的に CI には含めていません。到達できないサイトはスキップとして報告され、そのことはサマリーにも明記されるため、すべてスキップされた実行を合格と誤認することはありません。
そして、ターボモード自体、つまりコストが発生し、そのためエンドツーエンドでほかのテストから実行されない唯一の経路を確かめるには、次のようにします。
.venv/bin/python scripts/turbo_check.py # the model drives: dropdown, checkbox, submit
.venv/bin/python scripts/turbo_check.py --headed # watch it decide
同じフィクスチャを配信し、実際の Chrome を接続して、Jev に目標を達成させます。その後、成功したという主張を鵜呑みにせず、コードでモデルが残したページを検証します。キーがなければ skipped を出力して終了コード 0 で終了するため、終了コードと表示される語が一致します。
それ以上コストをかける意味がなくなるチェックイン
examples/checkin.html は、実際に自動化したいもの、つまり毎日のボタン操作を模したものです。
scripts/checkin.py は、最も低コストなものから順に、3段階で処理します。重要なのは、コストがかかるのは最初の実行だけという点です。
.venv/bin/python scripts/checkin.py --port 8901 # learn once, then never again
.venv/bin/python scripts/checkin.py --port 8901 --record # re-learn, ignoring the saved macro
1. すでに完了している場合。 ページを読み取ります。今日のチェックインがすでにページに表示されていれば、そのまま終了します。クリックもモデル呼び出しも不要で、取り消すものもありません。
2. 再生。 最初の実行で記録したマクロを実行します。モデル呼び出しはなく、数百ミリ秒で完了し、ページが変わっていた場合には推測せずに処理を拒否します。通常の日に毎回実行される段階で、キーは一切必要ありません。
3. 探索。 マクロがない場合、または保存済みのマクロがページに合わなくなった場合にのみ実行します。判断モデルがページの操作方法を見つけ、実行内容をマクロとして記録するため、翌日からはステージ2で処理できます。ページで成功が確認された場合にのみ、その経路が保存されます。
デモでは --port を固定することが重要です。ページのオリジンにはポートが含まれるため、異なるポートで2回目の実行を行うと、ブラウザーにとっては別のサイトになります。その場合、localStorage は空で、チェックイン済みであることも記憶されていません。
実際のサイトでは、次のようにします。
.venv/bin/python scripts/checkin.py --url https://example.com/rewards \
--goal "Click the daily check-in button" --expect "已签到"
.venv/bin/python scripts/checkin.py --url https://example.com/rewards --replay-only
目標と成功の確認を別々の引数にしているのは意図的です。--goal はモデルに実行させる内容で、--expect は実行後にページに表示されている必要があるテキストをコードで確認します。そのため、実行結果はモデル自身による作業の要約ではなく、常にページで判定されます。--headed --wait 120 を使って一度サインインしてください。ブラウザープロファイルは保持されるため、後続の実行ではセッションが再利用されます。--replay-only はモデルを呼び出さないため、cron ジョブで使うフラグです。
構成
jev_ultrafast_mcp/
js/observer.js in-page observer: stable refs, shadow/frame traversal, verify/resolve
cdp.py synchronous CDP client + Chrome launch (no wrapper library)
browser.py sessions, guarded execution, op dispatch, macro recording
observe.py element model, compact renderer, delta computation
macros.py semantic descriptors, scored re-resolution, storage
assertions.py deterministic checks
policy.py optional TypeSafe turbo policy (speculative fan-out)
safety.py domain envelope, redaction, confirmation rules
config.py environment-driven configuration
server.py the MCP surface
scripts/
install.py writes the right config for each MCP client on this machine
smoke.py end-to-end proof against a real browser
mcp_check.py drives the server over real stdio MCP
live_check.py the same, against real websites (needs the network)
turbo_check.py lets the decision model drive a real browser (needs a key)
extension_check.py the extension in a real Chrome: its table, and a macro it replayed
checkin.py a real check-in: learn once with the model, then replay for free
chrome-extension/
lib/observer.js a byte-identical copy of jev_ultrafast_mcp/js/observer.js
lib/render.js a port of observe.py, held to the real renderer by generated fixtures
lib/macro.js a port of macros.py, held to the real resolver by generated fixtures
lib/session.js a port of browser.py's op dispatcher, held to the real one by generated fixtures
lib/report.js a port of server.py's report writers, so a report reads the same anywhere
lib/store.js macros in chrome.storage.local, under the server's own {{placeholder}} rules
background.js the service worker, and the only file that calls the debugger API
examples/
checkin.html the daily-button page checkin.py drives
assets/
social-preview.png the card GitHub shows when this repository is shared
make_social_preview.py renders it, so the words on it are placed rather than generated
llms.txt what this server is, for agents that read before recommending it
server.json the MCP registry entry, submitted by the release workflow
開発
.venv/bin/pip install -e ".[dev]"
.venv/bin/ruff check .
.venv/bin/python -m pytest -q
.venv/bin/python scripts/smoke.py # 61 checks, real browser
.venv/bin/python scripts/mcp_check.py # 17 checks, real stdio MCP
すべてのテストは、Python 3.10、3.12、3.13 とヘッドレス Chrome を使って CI で実行されます。ターゲットの解決方法を変更する前に、CONTRIBUTING.md をお読みください。このロジックこそが、プロジェクトの要点です。
関連項目
browser-use/jev-ultrafast— オプションの高速化パスの移植元となったプロジェクトです。各ステップで型付きの質問を1つ出し、判断モデルが回答します。- TypeSafe —
browser_goalを支える、型付き質問の判断 API です。 - Model Context Protocol — このサーバーが使用するプロトコルです。
- 公式 MCP レジストリ — このサーバーのようなサーバーをクライアントが探す場所です。
- Chrome DevTools Protocol — ラッパーライブラリを介さずに、ブラウザーを操作するためのプロトコルです。
ライセンス
MIT — LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。