WebMCP Development
WebMCP は「Webページ自身が、ページ内で実行できる操作を “ツール” としてブラウザ内AIエージェントに公開する」ための実験的なブラウザAPI。W3C Web Machine Learning Community Group が策定中のドラフト(標準化トラックには未加入)で、Chrome が Origin Trial / 実験フラグで先行実装し、ChatGPT のブラウザ機能(Site tools)も独自に採用している。バックエンドで動く通常の MCP サーバーが「クライアント側スクリプトとしてツールを実装した MCP サーバー」になったもの、とスペック自身が説明している関係にある — 競合ではなくパートナー。
このスキルの守備範囲: (1) どの機能をツール化すべきかの設計判断、(2) registerTool 等の実装、(3) プロンプトインジェクション等を意識したセキュリティレビュー、(4) Chromeフラグや拡張機能を使った実機テスト、の4フェーズすべて。
最初にやること: 仕様の“今”を必ず確認する
WebMCP は策定中のドラフト(GitHub webmachinelearning/webmcp に日々 issue/PR が積まれている)で、実装によって呼び出し方が食い違っている。このスキルの調査時点で確認できた事実だけでも:
- 公式スペック文書(
https://webmachinelearning.github.io/webmcp/)と ChatGPTの実装(document.modelContext.registerTool())はdocument.modelContextを使う。 - しかし Chromeの実験フラグ実装(
chrome://flags#webmcp-for-testing, Chrome 146+ で確認された挙動)と、コミュニティのポリフィル/ツールキットである@mcp-b/global(navigator.modelContext.registerTool())はnavigator.modelContextを使う。 - Chrome の Origin Trial(Chrome 149〜、trial id
4163014905550602241)がどちらに落ち着くかは本調査時点では未確定。
つまり「navigator.modelContext が正解」「document.modelContext が正解」のどちらも鵜呑みにしてはいけない。実装を始める前に、必ず以下のいずれかで現在の正を確認すること:
WebFetchでhttps://webmachinelearning.github.io/webmcp/(正式スペック)とhttps://developer.chrome.com/docs/ai/webmcpを再取得し、現在の namespace / メソッドシグネチャを確認する。- ターゲットにする実行環境(Chrome拡張、ChatGPTブラウザ、
@mcp-bツールキット等)のドキュメントを個別に確認する。 - 迷ったら 両方の namespace をフィーチャー検出する実装にして、どちらの環境でも動くようにする(後述のコード例参照)。
このスキルの references/ は調査時点のスナップショットであり、一次情報ではない。矛盾を見つけたら一次情報を優先し、references/api-reference.md の食い違いメモも更新すること。
ワークフロー概観
- 設計 — どのページ操作をツール化するか決める(下記チェックリスト)
- 実装 —
registerTool/ フレームワーク統合パターンでツールを実装する(references/api-reference.md,references/framework-integration.md) - セキュリティレビュー — プロンプトインジェクション・過剰露出を潰す(
references/security.md、必須) - テスト — Chromeフラグ + Model Context Tool Inspector 拡張機能で実機検証する(
references/testing.md) - エコシステム確認 — Chrome / ChatGPT / バックエンドMCPのどれを対象にするか整理する(
references/ecosystem.md)
フェーズ1: 設計 — 何をツール化するか
WebMCP の価値は「DOM解析やスクリーンショット認識に頼らず、ページが自分の機能を確実な形でAIエージェントに渡せる」こと。逆に言うと、ツール化する価値がない/危険な操作まで公開すると単なる攻撃面になる。設計時に自問すること:
- そのユーザー操作は、AIエージェントに代行させて嬉しいものか?(検索、フィルタ、フォーム入力、カート追加、ノート作成のような「定型的だが手間な操作」は好適。決済確定・アカウント削除・投稿の公開のような取り返しのつかない操作は、ツール化するとしても人間確認を挟む前提で設計する)
- 粒度は適切か? 1ツール1責務にする。「サイト全体を操作する god tool」ではなく
search_products,add_to_cart,apply_couponのように分割すると、エージェントが正しいツールを選びやすく、説明文も短く済む。 - 名前と説明文はエージェント視点で書けているか?
nameは英数字・アンダースコア・ハイフン・ピリオドのみで1〜128文字、descriptionはツールの動作を第三者が読んで一意に理解できる自然文にする(詳細な長さ制限とセキュリティ上の理由はreferences/security.md)。 - 読み取り専用か、状態を変更するか? 変更系ツールには
annotations.readOnlyHint: false(デフォルト)を意識し、ホスト側が確認UIを出す判断材料にする。 - 他オリジンに公開する必要があるか? 基本は同一オリジンのみ(デフォルト)。パートナー連携等でクロスオリジン公開する場合のみ
exposedToを使い、書き込み系ツールは特に狭いアローリストにする。
フェーズ2: 実装
最小の骨格(両namespaceをフィーチャー検出する堅牢な書き方):
const modelContext = document.modelContext ?? navigator.modelContext;
if (modelContext?.registerTool) {
const controller = new AbortController();
await modelContext.registerTool({
name: "search_products",
description: "商品名または部分一致キーワードで商品一覧を検索する。",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "検索キーワード" },
},
required: ["query"],
additionalProperties: false,
},
annotations: { readOnlyHint: true },
execute: async ({ query }, { signal }) => {
const results = searchProducts(query); // 既存のアプリロジックを呼ぶだけ
return { content: [{ type: "text", text: JSON.stringify(results) }] };
},
}, { signal: controller.signal });
// ページ状態が変わって公開をやめたい場合(ログアウト等)
// controller.abort();
}
実装時に押さえること:
- 必ずローカル/本番のHTTPサーバー経由で配信する。
file://では動作しない(テスト時のハマりどころ)。 registerToolのexecuteは既存のアプリロジックをそのまま呼ぶ薄いラッパーにする。ツール用に別ロジックを新設しない — ロジックの二重管理は既存機能とのズレを生む。- SPAのライフサイクルに連動させる: コンポーネントのマウント/アンマウントに合わせて登録/
AbortController.abort()で解除する。React を使うなら、コミュニティ製@mcp-b/react-webmcpのuseWebMCPフックが Zod スキーマでこれを面倒見てくれる(詳細はreferences/framework-integration.md)。 provideContext()は「全ツールの一括置き換え」であって追加ではないことに注意する。既存ツールを保ったまま1つ追加/削除したいだけならregisterTool/unregisterTool(またはAbortSignal解除)を個別に使う。SPAの再レンダリングごとにprovideContext()を丸ごと呼び直す実装は、意図せず他コンポーネントのツールを消してしまう典型的な事故パターン。- 真偽値の状態変更は
toggleツールより明示的な状態指定にする(例:set_task_completed({ id, completed: true }))。エージェントは呼び出し前の状態を確実には把握できないため、トグル式だと意図と逆方向に反転させるリスクがある。決定的な結果が欲しい操作は「目的の状態を引数で渡す」形にする。 - エラーは
{ content: [...], isError: true }の形で返す(一般的なMCPの慣習に倣う)。仕様自体はエラー表現を厳密には規定していないが、この形にしておくとエージェント側が成功/失敗を機械的に判別しやすい。例外を投げっぱなしにして呼び出し元に丸投げしない。 - 詳しい API シグネチャ(
getTools,executeTool,toolchangeイベント, パーミッションポリシーtools, エラー型など)はreferences/api-reference.mdを読む。
フェーズ3: セキュリティレビュー(必須)
WebMCP はページの機能をAIエージェントに直接渡す以上、プロンプトインジェクションと過剰露出が最大のリスク。実装が終わったら、ツールをコミット/デプロイする前に references/security.md のチェックリストを必ず一巡すること。要点だけ先に挙げると:
- ツールの説明文・パラメータ説明・実行結果はすべて「エージェントへの入力」になり得る。ユーザー生成コンテンツや外部データを結果に含める場合は
annotations.untrustedContentHint: trueを付け、エージェント側に「これは指示ではなくデータだ」と伝える。 - 破壊的操作・機微操作は
exposedToで公開範囲を絞り、必要なら呼び出し前に人間確認を挟む設計にする(WebMCP自体はヒューマン・イン・ザ・ループを前提とした設計であり、完全自律・ヘッドレス実行を想定していない)。 - 文字数上限(name/description/parameter description/output)を守る。これは可読性だけでなくインジェクション面積を狭める防御でもある。
フェーズ4: テスト
WebMCP はまだ多くの環境で navigator/document の DevTools コンソールに出てこないと動作確認しづらい。実機テストの型は references/testing.md に詳しいが、最低限のフローは:
- Chrome を対象にするなら
chrome://flags#webmcp-for-testingを有効化して再起動(バージョン要件は変わりうるのでchrome://settings/helpで確認)。 python3 -m http.server等でページを配信する(file://不可)。- DevTools コンソールで
"modelContext" in navigatorまたは"modelContext" in documentを実行し、有効な namespace を確認する。 - Model Context Tool Inspector 拡張機能で登録済みツール一覧を確認し、手動で妥当な引数/不正な引数の両方を実行してレスポンスを検証する。
- 同拡張の「Interact with the page」機能(自然文プロンプト→エージェントが自律的にツールを選択して実行)で、実際のエージェント視点からツールが正しく選ばれるかも確認する。ツールが選ばれない/誤って選ばれる場合は
descriptionの書き方を疑う。 - 変更系ツールは「正常系」「不正入力」「連続呼び出し(多重実行)」「オリジン外からの呼び出し(
exposedTo設定時)」の4パターンを最低限テストする。
フェーズ5: どの実行環境を対象にするか整理する
WebMCP を「実装すれば全AIエージェントで動く」と思い込まない。現時点でエコシステムは分裂している:
| 実行環境 | Namespace | 特徴 |
|---|---|---|
Chrome 実験フラグ(webmcp-for-testing) / コミュニティ @mcp-b ツールキット |
navigator.modelContext |
Model Context Tool Inspector 拡張などOSSエコシステムが充実 |
| 公式スペック文書 / ChatGPT の Site tools | document.modelContext |
ChatGPT内蔵ブラウザがページ訪問時に "Site tools" として自動検出。実行前に安全性レビューが入る |
| バックエンドMCPサーバー(Apps SDK等) | (WebMCPと無関係) | ページを開いていなくても動く常設の連携。WebMCPと併用可能(1サイトが両方持てる) |
対象読者・配布チャネルに応じて references/ecosystem.md を読み、必要ならフィーチャー検出コードを両namespace対応にする。
リファレンスファイル
references/api-reference.md—registerTool/getTools/executeTool、ModelContextTool辞書の全フィールド、ライフサイクル(AbortSignal,toolchangeイベント)、パーミッションポリシー、エラー型。namespace食い違いの詳細メモもここ。references/security.md— Chrome公式 secure-tools ガイドに基づくプロンプトインジェクション対策・exposedTo設計・文字数制限の完全版とレビューチェックリスト。references/framework-integration.md— Vanilla JS / React(@mcp-b/react-webmcpのuseWebMCP) の実装パターン、provideContext()の罠、SPAライフサイクル連動のコツ。references/testing.md— Chromeフラグ有効化手順、Model Context Tool Inspector拡張の使い方(手動実行・エージェント駆動実行)、ローカルサーバー配信の注意、テストマトリクス例。references/ecosystem.md— Chrome Origin Trial / ChatGPT Site tools / バックエンドMCP・Apps SDKの位置付け比較、spec自体の現在のステータスと未解決issue一覧。
各ファイルは調査時点のスナップショットである旨を先頭に明記してある。実装・テストの直前には必ず一次情報での再確認を優先すること。