この記事をシェア
E2Eテストの相談で、そこそこの頻度で行き詰まる話があります。「テストしたい画面が、MFAの向こう側にある」。
IDとパスワードだけならまだ何とかなる。ところが実際の業務システムは、スマートフォンの認証アプリで承認して、メールに届いたコードを入れて、SSOを経由して、端末証明書まで見ている。ここをPlaywrightに全部やらせる方法を考え始めると、たいてい途中で「これ、そもそも自動化していいんだっけ」という話になります。
発想を逆にすると、話は少し変わります。認証は人間がやる。認証が終わったブラウザだけをAIエージェントに渡す。 この形をChrome拡張とローカルのWebSocketで実現しようとしているのが、今回取り上げる Kimi WebBridge です。
この記事の材料について(先にお断り)
本稿は、公開されているリポジトリ、npmパッケージ、Chrome ウェブストアの掲載内容を読んだ範囲で書いています。稼働環境での実測(所要時間、失敗率、リトライ回数)は行っていません。
Kimi WebBridgeは開発途上のOSSで、npm上の kimi-webbridge は本稿執筆時点(2026-08-06確認)で 0.1.3。コマンド名や引数は今後変わり得ます。手元で使う際は、必ず最新版のREADMEとソースを確認してください。「動くはずのコマンド」を並べるより、どこを読めば自分の環境で確かめられるかを書くほうが役に立つと判断しました。
1. なぜ「いま開いているChrome」を使いたいのか
CI用の無人ブラウザと、日常業務で開いているブラウザは、同じChromeでも別物です。後者には、ログイン済みのセッション、拡張機能、社内CAの証明書、業務でしか出ない画面状態が全部乗っている。この状態を自動テスト環境で作り直すのが、そもそも大変なわけです。
Kimi WebBridgeの立ち位置を一枚にすると、こうなります。
人間:
Chromeを起動 → ID/PW → MFAアプリ・認証コード → ログイン完了
│
▼
拡張を入れた同じChrome ← ローカルWebSocket ← Claude Code / Cursor など
│
▼
ログイン後の画面を読む・入力する・検証する
ポイントは、AIに渡しているものが認証情報ではなく「認証済みタブを操作する権限」だという点です。パスワードもMFAのシークレットも、エージェントのプロンプトや環境変数には入りません。
もっとも、これは安全になったという話ではありません。ログイン済みセッションを渡すのは、それ自体がかなり強い権限移譲です。この点は後半でもう一度触れます。
2. Kimi WebBridge の構成を先に押さえる
名前が同じでも、実体は二系統あります。ここを混ぜると設定でハマるので、最初に分けておきます。
| 名前 | 実体 | 状態(2026-08-06確認) |
|---|---|---|
| Chrome拡張 | Chrome ウェブストアで配布されている Kimi WebBridge 拡張 | 公開中 |
kimi-webbridge(npm) |
CLI と MCPサーバーを兼ねる薄いラッパー。依存は ws と MCP SDK のみ |
0.1.3 / Node.js 18以上 |
efrg123/kimi-webbridge |
v2.0 の設計文書リポジトリ。PLAN.md、API-SPEC.md などが中心 | 実装ではなく計画 |
三つ目が特に紛らわしい。efrg123/kimi-webbridge のREADMEには get_page_state()、submit_form()、request_user_approval() といった立派なAPI一覧が載っているのですが、冒頭に「Status: Planning Complete | Ready for Implementation」と書かれています。これはv2の設計であって、いま npx で降ってくるものではありません。 記事や社内資料でAPI名を引用するときは、この区別を必ず添えたほうがいい。
実際に手を動かすときに触るのは、npmの kimi-webbridge と拡張のほうです。
2-1. データの流れ
AIエージェント
│ CLI / MCP (JSON)
▼
ローカルWebSocket(既定 127.0.0.1:10086/ws)
│
▼
Chrome拡張の Service Worker
│ tabs.sendMessage
▼
Content Script(DOM操作)
│
▼
ユーザーが実際に開いているタブ
拡張は既定で ws://127.0.0.1:10086/ws に接続しにいきます。この接続先は、拡張のポップアップでアイコンを5回クリックすると出る開発者モードから変更できる、とREADMEに書かれています。ポート番号を変えたくなったときに探し回ることになるので、先に知っておくと楽です。
3. CLIとMCP、どちらから触るか
インストールは要りません。npx で直接叩けます。
node --version # v18以上であること
# ページを開く
npx kimi-webbridge navigate '{"url":"https://example.com"}'
# ページ構造(アクセシビリティツリー)を取得
npx kimi-webbridge snapshot
# 入力とスクリーンショット
npx kimi-webbridge fill '{"selector":"input[name=q]","value":"Kimi WebBridge"}'
npx kimi-webbridge screenshot '{"format":"jpeg"}'
引数を付けずに実行すると対話モードに入り、標準入力から1行1JSONで {"action":"...","args":{...}} を流し込めます。シェルスクリプトから回すなら、こちらのほうが取り回しがいい場面もあります。
MCPサーバーとして起動する場合は次の一行です。
npx kimi-webbridge mcp
Claude Code や Claude Desktop 側の設定はこの形になります。
{
"mcpServers": {
"webbridge": {
"command": "npx",
"args": ["kimi-webbridge", "mcp"]
}
}
}
3-1. 使える操作
0.1.x のREADMEに載っている操作は次のとおりです。観察系と操作系が素直に並んでいて、Playwrightのlocator APIのような抽象化はありません。
| 操作 | 内容 | 必須引数 |
|---|---|---|
navigate |
ページを開く | url |
snapshot |
アクセシビリティツリーを取得 | — |
click / snapshot_click / mouse_click |
CSSセレクター/@e ref/物理クリックの3系統 |
selector または ref |
fill |
フォーム入力 | selector, value |
send_keys / key_type |
キー送出/テキスト入力 | keys / text |
evaluate |
JavaScript実行 | code |
screenshot / save_as_pdf |
画面キャプチャ/PDF出力 | format(任意) |
network |
ネットワークリクエストの捕捉 | cmd |
list_tabs / find_tab / close_tab |
タブの列挙・検索・クローズ | url(find時) |
upload |
ファイルアップロード | selector, files[] |
クリックが3系統ある点は覚えておくと役に立ちます。アイコンだけのボタンなど、CSSセレクターで安定して掴めない要素があるからこそ、snapshot で得た @e ref を使う snapshot_click が別に用意されている、という構造です。
4. 「接続できない」の原因は、たいてい向きの問題
ここが本稿でいちばん書きたかった部分です。kimi-webbridge は、モードによってWebSocketのサーバーとクライアントが入れ替わります。
ソースを読むと、MCPモード(src/mcp.js)は new WebSocketServer({ port: 10086, ... }) でサーバーを立てます。つまり待ち受ける側はNode側で、Chrome拡張がそこへ接続しに来る。一方CLIモード(src/cli.js)は new WebSocket(WS_URL)、こちらはクライアントです。CLIだけを叩いても、別に待ち受け役がいなければ繋がりません。
MCPモード:
Chrome拡張 ──接続──▶ npx kimi-webbridge mcp(10086で待ち受け)
CLIモード:
npx kimi-webbridge navigate ──接続──▶ 誰かが立てた 10086
CLIの接続先は環境変数で変えられます。既定値もソースに書いてあるとおりです。
| 変数 | 既定値 | 備考 |
|---|---|---|
WS_URL |
ws://127.0.0.1:10086/ws |
CLIモードのみ有効 |
WS_TIMEOUT |
60000 |
ミリ秒 |
MCPモードのポートは環境変数では変わりません。READMEには「サービスを止めて src/mcp.js の CONFIG.WS_PORT を書き換え、拡張側のWebSocketアドレスも合わせて変更してから再起動する」と書かれています。npx で都度取得している構成だと編集先が消えるので、ポートを変えたいならローカルにクローンして使うほうが素直です。
5. WindowsとWSLをまたぐとき
Windows 11 + WSL2 という構成だと、Chromeは Windows 側、開発エージェントは WSL 側、という分かれ方をします。この状態で最初に崩れるのが「localhost なら繋がるはず」という感覚です。Windowsの 127.0.0.1 と WSL2 の 127.0.0.1 は別のループバックだからです。
ただし、前節の「向き」を踏まえると、見通しはそれほど悪くありません。MCPモードのサーバーは WebSocketServer に host を渡していないので、Node の既定どおり全インターフェースで待ち受けます。WSL側でデーモンを動かし、Windows側のChrome拡張からWSLのIPへ接続する形は、経路としては成立します。
# WSL側: 待ち受けているか確認
ss -ltnp | grep 10086
# WSL側のIPを確認(拡張の接続先に使う)
hostname -I
# Windows側から到達性を確認
wsl hostname -I
Test-NetConnection <WSL_IP> -Port 10086
WSLのIPは再起動で変わることがあるので、拡張の設定に焼き込むと翌日に動かなくなります。切り分けを優先するなら、まずChrome拡張とデーモンをどちらもWindows側に寄せて動くことを確認し、それからWSLへ持っていく順番をおすすめします。
5-1. よくある症状
| 症状 | 疑うところ | 確認方法 |
|---|---|---|
ECONNREFUSED |
その側で誰も待ち受けていない | ss -ltnp / Get-NetTCPConnection -LocalPort 10086 |
| タイムアウトする | Firewall、VPN、WSLのIP変更 | Test-NetConnection でポート単位に確認 |
EADDRINUSE |
Windows側とWSL側で二重起動 | pgrep -af webbridge で残骸を探す |
| 拡張は接続済みなのに操作が効かない | Chromeプロファイル違い、対象タブ違い | list_tabs で実際に見えているタブを確認 |
| コマンドは成功するが画面が変わらない | @e ref が古い |
snapshot を取り直してから再操作 |
最後の行は地味に効きます。設計文書側でも「アクションが実際にページを変えたか確認せず clicked を返す」ことが v1 の課題として挙げられていて、これは実装が追いつくまでは呼び出し側で面倒を見る領域です。コマンドの終了コードを成功条件にしない。URL、見出し、成功メッセージなど、事後状態で判定する。
6. Playwrightと競合しない
「PlaywrightがあるのにWebBridgeを使う意味は」と聞かれることがありますが、これは置き換えの話ではないと考えています。役割が違う。
| 層 | 道具 | 得意なこと |
|---|---|---|
| CIの回帰テスト | Playwright | 高速・並列・隔離、trace、ブラウザ行列。結果が再現する |
| ログイン済み環境の調査 | Kimi WebBridge | 実ブラウザの状態を使った探索・例外対応 |
| 人間に近い画面操作 | Claude for Chrome など | 自然言語での指示、手動作業の補助 |
実務で効きそうなのは、この2つを直列に並べる使い方です。
Playwright: 毎回同じ仕様をCIで検証
↓ 失敗時の trace・スクリーンショット
WebBridge: 人間のログイン状態で再現調査
↓ 観察結果
人間: 仕様変更か、環境障害か、テストの不備かを判断
CIが落ちたときに「テストコードが悪いのか、ログイン済みセッションでしか起きない問題なのか」を切り分ける手段が増える、という理解が近い。決定性が必要なリグレッションテストをWebBridgeへ移すのは、逆方向です。
7. 手順をAgentSkillに固定する
毎回「snapshotして、入力欄を探して、送信後に検証して」と説明するのは無駄です。禁止事項と検証手順をファイルに落として、エージェントに読ませたほうが安定します。
---
name: kimi-web-e2e
description: Kimi WebBridge経由で、接続済みChromeタブの画面検証を行うときに使う
---
# Kimi Web E2E
## 前提確認
1. WebBridgeのデーモンに到達できること
2. 対象URLがテスト環境であること
3. 本番データ、および取り消せない操作は承認なしに実行しない
## 標準ループ
1. 対象URLを開く
2. snapshot を取る(必要ならスクリーンショットも)
3. アクセシブルネーム、role、label、@e ref で対象を特定する
4. 1項目ずつ入力し、その都度観察し直す
5. 副作用のある操作の前に、内容を要約して停止する
6. 承認後にのみ実行する
7. URL、可視テキスト、DOM、ブラウザエラーで検証する
## 対象の指定
- 最新 snapshot の @e ref を最優先
- 次に role + アクセシブルネーム
- CSSの深い子孫セレクターは最後の手段
- ref が古くなったら再試行せず snapshot を取り直す
## 失敗時
- クリックは成功したが状態が変わらない → 失敗として扱う
- 同じエラーが続く → ループせず停止して報告する
## 出力
テスト名 / URL / 実行手順 / pass・fail・blocked / 観察した証拠 /
スクリーンショットのパス / 人間が次にやること
Claude Code から呼ぶときのプロンプトも、副作用を明示的に切り離しておくと事故が減ります。
テスト環境の注文確認画面をWebBridgeで検査してください。
「注文確定」ボタンは押さず、ボタンの存在、disabled状態、
表示金額、エラー表示だけを報告してください。
8. ポート10086は誰でも繋がる
便利さと危険性が同じ場所から出てくる話です。ログイン済みブラウザを操作できるということは、そのブラウザでできることは一通りできてしまうということでもあります。
設計文書のほうには、v1の課題としてはっきりこう書かれています。「No security boundary: any localhost process can connect to port 10086」。認証の仕組みがなく、localhost上のどのプロセスからでも接続できる。実装側も WebSocketServer に host を指定していないので、既定では全インターフェースで待ち受けます。マルチユーザーの端末や、他人と共有するネットワークでは、この点を確認してから使ってください。
運用側で最低限やることを挙げておきます。
- WebSocketを外部に出さない。必要ならOS側のFirewallでポート10086を絞る
- 操作対象URLを allowlist で限定し、既定は読み取り専用にする
- 送信・削除・購入・公開・権限変更には人間の承認を挟む
- snapshotやスクリーンショットに認証トークンや個人情報が写るので、保存先と保持期間を決める
evaluate で任意のJavaScriptが実行できる以上、「エージェントに渡した権限=そのブラウザの全権」だと考えておくのが安全側です。読み取りだけの調査から始めて、書き込みは承認付きで、というのがしばらくは現実的な線でしょう。
9. まとめ
Kimi WebBridge は Playwright の代わりになる別のテストランナーではなく、ユーザーが実際に使っている Chrome を、CLI や MCP から観察・操作するための接続層です。人間がMFAまで済ませた状態をそのまま渡せるので、「認証の向こう側にある画面」に手が届くようになる。ここは既存のE2Eツールが構造的に苦手な領域です。
一方で、現時点の実装はまだ薄い。API一覧が充実して見えるv2リポジトリは設計文書であり、npmで動くのは 0.1.3 のCLI/MCPラッパーです。認証境界もありません。固定の回帰テストはPlaywrightで守り、WebBridgeは調査と探索に使う。この線引きを最初に決めておけば、扱いやすい道具だと思います。
導入するなら、まず navigate、snapshot、screenshot の3つだけで疎通させる。そこで詰まるとしたら、原因はほぼ WebSocket の向きかポートです。
参考リンク
- efrg123/kimi-webbridge — v2.0 の設計・計画リポジトリ
- AkagiYui/kimi-webbridge-mcp — npm の
kimi-webbridge(CLI/MCP)のソース - Kimi WebBridge 拡張(Chrome ウェブストア)
- Playwright
