mcpField
K
kimi-webbridge

kimi-webbridge

github.com/mxyhi生産性507205 回インストール1 週間前に更新
リポジトリ

kimi-webbridge について

kimi-webbridgeは、ローカルデーモン経由でユーザーのブラウザーを操作するエージェント向けスキルです。ログイン済みページの操作・調査に加え、ウェブサイト調査から再利用可能なCLIやスクリプトを作る手順も備えています。

主な機能

  1. 01ブラウザータブの移動と管理
  2. 02アクセシビリティスナップショットでのページ閲覧
  3. 03要素のクリックと入力欄への記入
  4. 04スクリーンショットとPDF保存
  5. 05ネットワークリクエストと応答の調査
  6. 06ウェブサイトCLI作成のワークフロー

活用シーン

  1. 01複数ページにわたる情報調査
  2. 02既存のブラウザーセッションでのフォーム入力
  3. 03サイト調査中のリクエスト確認
  4. 04サイト調査をもとにした再利用可能なCLIの作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mxyhi/ok-skills --skill kimi-webbridge

インストール後、Claude Code で/kimi-webbridgeを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
operations.md
references/cli-creator/
companion-skill-template.md
go-layout.md
login-handling.md
site-exploration.md
workflow.md

詳細

Kimi Browser Extension(旧称 Kimi WebBridge)

http://127.0.0.1:10086 のローカルデーモン経由で、ユーザーの実際のブラウザー(ログインセッションを含む)を操作します(デフォルトのアドレスです。異なる場合については、ツール呼び出しに失敗する場合を参照してください)。

ユーザーが、単発のタスクではなく、ウェブサイト用の再利用可能な CLI ツールやスクリプトの作成を依頼した場合は、references/cli-creator/workflow.md に従ってください。各フェーズでは、以下のファイルを読むタイミングが示されています。

  • references/cli-creator/site-exploration.md — 各機能がデータを取得する方法を調べる手順
  • references/cli-creator/login-handling.md — サイトでログインが必要な場合
  • references/cli-creator/go-layout.md — CLI を Go で作成する場合
  • references/cli-creator/companion-skill-template.md — エージェントに CLI の使い方を伝えるスキルのテンプレート

ツール

ツール引数戻り値注記
navigateurl、newTab(bool)、group_title{success, url, tabId}最初の呼び出しでタブを開きます — タブを参照してください。group_title はグループに表示されるラベルを設定します
find_taburl、active(bool){success, url, tabId, borrowed}このセッションで開いたタブを再選択します。active:true はユーザーが表示しているタブを借用します — タブを参照してください
snapshot任意の ref。format:"aria" を指定すると任意の max_chars (1–60000) のテキストが取得され、続きの取得には cursor を指定しますデフォルト {url, title, tree}。ARIA {url, title, tree_text}アクセシビリティツリー(テキスト) — ページの内容を読み取り、要素を特定するために使用します
clickselector (@e ref または CSS){success, tag, text}合成イベントの el.click()
fillselector、value{success, tag, mode}<input>/<textarea> と [contenteditable] (ProseMirror/Lexical/Slate) の両方に対応します。mode は "value" または "contenteditable" です
evaluatecode (await を使用する場合は async IIFE で囲みます — トップレベルの await は SyntaxError になります){type, value}
cdpmethod、paramsCDP の生レスポンスchrome.debugger の生のパススルーです — JS における evaluate と CDP における cdp のようなものです。上記のツールでは対応できないケースのための低レベルな代替手段です。Page.bringToFront は最後の手段です。タブでフォーカスエミュレーションがオフの場合、呼び出すとタブをアクティブにする代わりにオンにします(タブは切り替わらずにレンダリングされ、実際の入力を受け取ります)。エミュレーションがオンになった後に呼び出した場合に限りアクティブ化され、ユーザーが使用中の別のアプリよりも Chrome が前面に表示されることはありません。Target.activateTarget は拒否されます
screenshotformat(png|jpeg)、quality(0-100)、任意の selector (@e/CSS)、任意の path{format, path, sizeBytes, mimeType}base64 ではなくファイルパスを返します — スクリーンショットを参照してください
networkcmd(start|stop|list|detail)、filter(URL の部分文字列。list 用)、requestId(detail 用)list: {count, requests:[{requestId, url, method, status, mimeType, completed}]}。detail: 対象リクエストと requestHeaders、requestBody、body(レスポンス)キャプチャはタブごとに行われ、start 以降が対象です。stop の前に detail を呼び出してください — 停止するとレスポンス本文が解放され、その後 detail を呼び出すと body の代わりに bodyError が返されます
uploadselector、files(string[]){success, fileCount}
save_as_pdfpaper_format、landscape、scale、print_background、任意の path{path, sizeBytes, mimeType, pageTitle}現在のページを PDF にレンダリングし、ファイルパスを返します — PDF として保存を参照してください
list_tabs—{success, tabs:[{tabId, url, title, active, groupTitle}]}現在のセッション内のタブを確認します
list_browser_tabs—{success, tabs:[{tabId, windowId, url, title, active}]}ウィンドウをまたいで、この WebBridge 接続から見えるすべてのタブを確認します。タブへの接続やフォーカスは行いません
attach_tabtabId{success, tabId, url, title, borrowed}フォーカスせずに、既存の特定のタブをこのセッションに接続します。借用したタブは close_session の後も開いたままです
close_tab—{success, closed: bool}セッション内の現在のタブを閉じます
close_session—{success, closed: int}このセッションが開いたタブを閉じます。借用したタブは開いたままです。closed は閉じたタブの数です。呼び出すタイミングについてはセッションを参照してください
タブと現在のタブ

単一タブツール(snapshot、click、fill、screenshot、save_as_pdf)は、現在のタブ(navigate で最後に開いたタブ、find_tab で選択したタブ、または attach_tab でアタッチしたタブ)を操作します。

  • ページを開く:ページを並行して表示する必要がある場合(比較、相互参照)は newTab:true を使用します。省略すると、現在のタブが新しい URL に移動します。
  • 前のタブに戻る:find_tab を呼び出すと、このセッション中に以前に開いたタブを再び現在のタブにできます。タブの URL を渡してください。list_tabs または以前の navigate の結果から取得できます。照合はホスト名で行われます。kimi.com を指定すると www.kimi.com のタブも見つかり、パスは無視されます。デフォルトでは、find_tab はこのセッションで開いたタブのみを検索し、ユーザーの他のタブやウィンドウにはアクセスしません。
  • ユーザーがすでに開いているページを操作する:list_browser_tabs を呼び出し、URL/タイトルと tabId でタブを選択してから、その ID を指定して attach_tab を呼び出します。これは他のウィンドウのタブにも使用でき、ユーザーが前面に表示しているタブは変わりません。アタッチしたタブは借用されるもので、close_session の後も開いたままです。ユーザーが現在表示している特定のタブには、find_tab を active:true とともに使う方法も引き続き有効です。
  • find_tab が「no tab matching … in this session」というエラーを返した場合、そのページはこのセッションでは開かれていません。代わりに newTab:true を指定して navigate を実行してください。
curl -s -X POST http://127.0.0.1:10086/command \
  -d '{"action":"find_tab","args":{"url":"https://www.kimi.com","active":true},"session":"k26-research"}'
呼び出し形式

すべてのコマンドには、現在のタスクを示す最上位の session が含まれます。下記のセッションを参照してください。後のセクションの例では簡潔さのために省略していますが、実際の呼び出しでは必ず指定してください。すべての応答はエンベロープ形式です。成功時は {"ok":true,"data":…}(data の内容は上記の戻り値列を参照)、失敗時は {"ok":false,"error":{"code","message"}} となります。コマンド形式はユーザーの OS によって異なります。

macOS/Linux — インライン JSON を使用できます。

curl -s -X POST http://127.0.0.1:10086/command \
  -H 'Content-Type: application/json' \
  -d '{"action":"navigate","args":{"url":"https://example.com","newTab":true,"group_title":"My task"},"session":"my-task"}'

インライン呼び出しが失敗した場合(bash のシェル引用符/構文エラー、またはデーモンからの HTTP 400 エラー)、同じコマンドを変更せずに再試行しないでください。代わりに、リクエストをファイル本文として再送してください。

  1. 独自のファイル書き込みツールを使い、JSON 本文を一意の名前を付けた一時ファイルに書き込みます。JSON が同様に壊れるため、シェルの echo/heredoc は決して使わないでください。リクエストごとに新しい名前を使用します(例:/tmp/webbridge-req-<random>.json)。
  2. ファイルを POST します。
curl -s -X POST http://127.0.0.1:10086/command -H 'Content-Type: application/json' --data-binary @/tmp/webbridge-req-<random>.json
  1. リクエストが返されたら、すぐに一時ファイルを削除します。

Windows(PowerShell/cmd) — シェルは、コマンド引数やパイプで渡された非 ASCII 文字(中国語など)を破損させます。それらは ? としてデーモンに届き、テキストを復元できません。すべてのリクエストをファイル本文として送信してください。

  1. 独自のファイル書き込みツールを使い、JSON 本文を一意の名前を付けた一時ファイルに書き込みます。非 ASCII 文字が同様に破損するため、シェルの echo/heredoc は決して使わないでください。リクエストごとにランダムな接尾辞を付けた専用のファイル名を使用し、同時リクエスト間でファイルが共有されたり上書きされたりしないようにします(例:webbridge-req-<random>.json)。
  2. curl.exe を使ってファイルを POST します。必ず curl.exe を使用してください。Windows PowerShell で curl とだけ入力すると Invoke-WebRequest のエイリアスになるため、使用しないでください。
curl.exe -s -X POST http://127.0.0.1:10086/command -H "Content-Type: application/json" --data-binary "@$env:TEMP\webbridge-req-<random>.json"
  1. リクエストが返されたら、すぐに一時ファイルを削除してください。リクエスト本文をディスク上に残さないでください。

セッション

1つのタスク = 1つのセッション = 1つのタブグループです。 session には、タスクで開いたすべてのタブが1つのタブグループにまとめられるため、ユーザーは「エージェントが今何をしているか」をひと目で確認できます。リクエスト本文のトップレベルフィールドとして渡してください(args の中には入れないでください)。

  • タスクの開始時にセッション名を1つ選び、すべてのコマンドに指定してください。タスクの途中では、サイトが変わっても切り替えないでください。 サイトごとにセッション名を切り替えることが、タブグループが分断される最大の原因です。
  • サイトではなくタスクにちなんだ名前にしてください(camping-research、phone-compare など)。複数のセッションを使うのは、本当に無関係なタスクを並行して行う場合だけです。
  • group_title は人が読むためのグループ名です。ユーザーの言語で入力し、タスクの最初の navigate で指定してください。
  • タスクの最初の navigate でグループを作成する際、このタスクのページはグループ「title」にまとめられ、ユーザーが希望すればいつでも閉じられることを、ユーザーに一度伝えてください。
# First tab: set session + a human label (in the user's language)
curl -s -X POST http://127.0.0.1:10086/command \
  -d '{"action":"navigate","args":{"url":"https://www.kimi.com","newTab":true,"group_title":"K2.6 feature research"},"session":"k26-research"}'
# Another site, same task → same session → joins the same group automatically
curl -s -X POST http://127.0.0.1:10086/command \
  -d '{"action":"navigate","args":{"url":"https://www.moonshot.cn","newTab":true},"session":"k26-research"}'

閉じる操作は、必ずユーザーが開始する必要があります。ユーザーが明示的に「それらを閉じて」「タブを整理して」などと依頼した場合にのみ、close_session を呼び出してください。これにより、グループ全体が1回の呼び出しでクリアされます。

スクリーンショット

デーモンは画像をディスクに書き込み、{format, path, sizeBytes, mimeType} を返します。モデルは生の画像バイト列を読み取れないため、base64は返しません。.path を取得し、Read ツールで開いて実際に確認してください。

# Default: PNG of the visible viewport, daemon picks a temp path
curl ... -d '{"action":"screenshot","args":{}}'
# Options (each independent): JPEG quality, element-only via @e/CSS selector, custom output path
curl ... -d '{"action":"screenshot","args":{"format":"jpeg","quality":60}}'
curl ... -d '{"action":"screenshot","args":{"selector":"@e123"}}'

呼び出し元が指定した path は、そのまま使用されます(親ディレクトリは作成され、既存のファイルは上書きされます)。上書きを避けるため、一意の名前を使用してください。save_as_pdf も同じルールに従います。

CSS/JSセレクターよりsnapshotを優先する

snapshot は、観測したDOMノードに紐付けられた @e 参照を持つインタラクティブ要素を返します。参照は不透明な文字列としてコピーし、クリックや入力に使用してください。ページを再読み込みしても同じノードの参照は維持されます。ノードが削除された場合、またはドキュメント/接続が変更された場合は、新しいsnapshotが必要です。参照によって、名前が一致する別の要素が自動的に選択されることはありません。

範囲を限定してテキストを読み取るには、format:"aria" を指定し、必要に応じて max_chars(デフォルトは60000)を指定して snapshot を呼び出してください。これは tree_text の長さを制限するもので、メタデータは対象外です。truncated:true の場合は、同じ保存済みの観測を続けるため、ref を指定せず next_cursor を cursor として渡してください。後続のチャンクには continued:true が付与されます。チャンクは長い行の途中で分割される場合があるため、区切り文字を加えずに tree_text を連結してください。また、上限はサロゲートペアを分割せず、UTF-16コード単位で数えられます(次の文字に2単位必要な場合、上限が1だとエラーになります)。カーソルは5分後、キャッシュの削除時、ページ遷移時、または接続のリセット時に期限切れになります。期限切れカーソルのエラーが発生した場合は、新しいsnapshotを開始してください。同一ドキュメント内のコンテンツ編集によって、保存済みテキストが更新されることはありません。キャッシュには最大8個のsnapshot、または800万コード単位まで保存できます。400万単位を超える観測は明示的に失敗するため、読み取り範囲を狭めてください。別の方法として、特定の query を指定して find を呼び出し、メインドキュメントのアクセシビリティツリー全体を検索した後、選択した一致項目の ref を指定して snapshot を呼び出し、そのサブツリーを読み取ることができます。検索結果には、同じ名前の一致項目を区別するための祖先パスが含まれます。範囲や上限を指定しても、既存の参照が割り当て直されることはありません。この検索にはiframeのコンテンツは含まれません。

次の場合に限り、evaluate(JS)に切り替えてください。

  • 対象にsnapshot内の @e 参照がない
  • snapshotにない属性(例:href)が必要
  • 複雑なイベントシーケンスの発生、またはスクロールが必要

Evaluateのヒント

  • 常にコンパクトな JSON.stringify(data) を使用してください。null, 2 の書式指定は絶対に追加しないでください。インデントや改行によって応答が数倍に膨らみ、送信中に切り詰められることがあります。
  • evaluate の呼び出しはページのJSレルムを共有します。同じ const/let を2回の呼び出しで再宣言すると、SyntaxError が発生します。新しいスコープを作るには、IIFEで囲んでください:(() => { const x = ...; return x; })()。

テキスト入力 — fill を使用

fill(セレクターは CSS または @e 参照で、値も指定)は、<input>/<textarea>(mode: "value" を返します)と、リッチエディターの [contenteditable](ProseMirror、TipTap、Lexical、Slate、Quill など。mode: "contenteditable" を返します)で動作し、ページが反応するよう適切な入力イベントを発生させます。

fill は既存の内容を消去して挿入します。追記するには、evaluate で現在の値を読み取り、連結してから、その結果を fill で入力します。

フォームの送信/特殊キー

「Enter キーを押す」ための専用ツールはありません。フォームを送信するには、送信ボタンを直接クリックします(@e 参照またはセレクターに対して click)。キーイベントをプログラムから発生させる場合(例:モーダルを閉じるための Escape):

{"action":"evaluate","args":{"code":"document.activeElement.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}))"}}

現在のページを PDF として保存

save_as_pdf は現在のページを PDF にレンダリングし、ファイルパスを返します。すべての引数は省略可能です:

  • paper_format:letter(デフォルト) | a4 | legal | a3 | tabloid
  • landscape:false(デフォルト)
  • scale:1.0(デフォルト)、範囲は [0.1, 2.0]
  • print_background:true(デフォルト) — 背景色を保持します
  • path:呼び出し元が指定する出力パス。指定がない場合、デーモンはページタイトルをファイル名として OS の一時ディレクトリ内にデフォルトのパスを選びます

path の仕様は screenshot と同じです。指定どおりに書き込まれ、親ディレクトリは自動的に作成され、既存ファイルは上書きされます。

デコード後の PDF の上限は 100 MB です。これを超えるとデーモンは処理を拒否します。scale を小さくするか、ページを分割してください。

既知の制限事項

  • event.isTrusted を厳密に確認するサイト(一部の銀行ポータルや CAPTCHA など)では、click/fill が DOM レベルの合成イベント(isTrusted=false)を発生させるため無視されます。このような場合は、ページの操作には手動での操作が必要であることをユーザーに伝えてください。(プロトコルレベルでは cdp のエスケープハッチを使って信頼済みの入力を行えますが、高度な機能として扱ってください。タブはバックグラウンドタブであり、フォーカスエミュレーションが有効な間だけ実際の入力がバックグラウンドタブに届きます。入力前に Emulation.setFocusEmulationEnabled {"enabled":true} を送信し、そのタブでの操作が終わったら {"enabled":false} を送信してください。入力が反映されない場合は、最後の手段として Page.bringToFront を使用してください。cdp の行を参照してください。)
  • iframe 内のコンテンツ:snapshot、fill、click、evaluate が参照するのはトップドキュメントのみです。埋め込みドキュメント(プレビューペイン、サンドボックスプレビュー、埋め込みアプリ)は別のページであり、そのノードはツリーに含まれません。snapshot でツリーの後に frames(frames: [{frame:"#f1", url, size, …}]。画面を占める面積が大きい順)が表示された場合は、その一覧にあるハンドルを使って read_page {"frame":"#f1"} で読み取ってください。フレームの読み取り結果には frame が含まれます。含まれない場合、拡張機能はこのスキルより古く、代わりにトップページを返しています。「バージョンの不一致」を参照してください。プレビューフレームは、ページ自体の読み込みから数秒以上遅れて表示されることがよくあります。再度 snapshot を取得する代わりに、wait {"frame":"any"} を使うと、画面の大部分を占めるフレームが読み取り可能になった時点で戻ります。PDF プレビューはビューアー独自のドキュメントを通じて読み取られるため、スクロールしなくてもすべてのページが返されます。フレーム内の要素を操作する機能は、引き続きサポートされていません。フレームの URL に直接移動すれば動作する場合もありますが、認証が必要なプレビューストリームは通常、単独では何も読み込みません。

ツール呼び出しに失敗した場合(デーモンまたは拡張機能の準備ができていない)

ツール呼び出しでデーモンに接続できない(接続が拒否される)場合、または応答が上記の ok エンベロープではない(別のプログラムがそのポートで応答している)場合は、ユーザーに尋ねず、自分で start を実行してください。いつ実行しても安全です。デーモンがすでに起動している場合は何も行いません。 バイナリは PATH にありません。~/.kimi-webbridge/bin/kimi-webbridge(Windows の場合:%USERPROFILE%\.kimi-webbridge\bin\kimi-webbridge.exe)です。

デーモンのリッスン先は、常に start の出力、または kimi-webbridge status(実行中の場合は port、停止中の場合は addr)で確認できます。127.0.0.1:10086 でない場合は、このタスクのすべての呼び出しでそのアドレスを使用してください。設定ファイルはデーモンの移動にのみ使用し、場所の確認には使用しません。その後、ツール呼び出しを再試行してください。

応答が ok:false で、コードが extension_not_connected の場合、デーモンに問題はなく、ブラウザー側に問題があります。start を実行しても変わりません。メッセージにはユーザーが行う必要のある操作が記載されています。それをユーザーの言語で伝え、確認が取れたら続行してください。

start が「did not come up … held by another program」で失敗する場合 → 別のプログラムがそのポートを使用しています。デーモンを移動します。エラーに記載されている設定ファイルに {"addr":"127.0.0.1:<port>"}(空いている任意のポート)を書き込み、再度 start を実行します。その後、新しいポートを一度だけ拡張機能に設定するようユーザーに伝えてください(Kimi のサイドパネル → Settings → Local agent remote control → Connection address → ws://127.0.0.1:<port>/ws。設定は記憶されます)。

それでも失敗する場合、バイナリが見つからない(command not found は kimi-webbridge がインストールされていないことを意味します)か、ブラウザー拡張機能が接続できません。詳しいトラブルシューティングは行わず、代わりにヘルプページを案内してください。

stop/restart/upgrade/uninstall は、実行中のデーモンを停止させるため、自動的には実行しないでください。status に version_mismatch、update_available、skill_mismatch が表示される場合、または kimi-webbridge コマンドが ==> … Run: <command> の行(同じ通知が stderr に出力されます)を表示する場合は、ユーザーに伝え、実行するコマンドをそのまま渡してください。command フィールド、または Run: の後に続く内容が該当します。そのために表示されています。ユーザーが kimi-webbridge 自体(インストール、起動/停止/アップグレード、「実行中かどうか」、status の意味、別のポートへの移動)について尋ねた場合は、まず references/operations.md を読んでください。

バージョンの不一致

ツールが "Please update the Kimi Browser Extension" を含むエラーを返した場合、ユーザーのブラウザー拡張機能がこのスキルより古い状態です。自分でバージョンを調整しようとせず、ユーザーの言語で拡張機能を更新して再試行するよう伝えてください。

コメント