12k
All articles

WebMCPでサイトのアクションをAIエージェントに公開する

WebMCPは、document.modelContextでサイトツールを登録し、注釈を設定して、ログイン済みブラウザ内で実行する安全な操作を扱います。

OpenReplay Team
OpenReplay Team
WebMCPでサイトのアクションをAIエージェントに公開する

WebMCPは、Model Context Protocolの方向性を逆転させます。エージェントが、あなたがホストするサーバーへ外向きに接続するのではなく、ページ自身がdocument.modelContext.registerTool()を使ってJavaScriptでツールを登録し、すでにそのページを開いているエージェントが宣言されたアクションを直接呼び出します。インターフェースをクリックして回り、フォームフィールドを推測する必要はありません。

すでにコーディングエージェントにMCPサーバーを接続したことがあるなら、サーバーサイドのモデルは馴染みのあるものでしょう。プロセス、トランスポート、ツールリスト、そして接続するクライアント。厄介なのはブラウザのケースです。エージェントのトラフィックは、ログイン済みセッションを持つレンダリング済みページに到達します。そしてこれまで唯一の手段はアクチュエーション(操作)でした。DOMを読み、ボタンが何をするのかを推論し、チェックアウトのステップがクリックの途中で再レンダリングされないことを祈る、というやり方です。

本記事では、実運用のアプリケーションを所有する立場の人にとって重要なメカニズムを扱います。正しいツール登録がどのようなものか、3つのアノテーションヒントがエージェントの挙動を実際にどう変えるのか、サイトツールが今日どこで動作するのか、そしてユーザーのサインイン済みセッション内でツールが実行されることのセキュリティ上の帰結です。

要点

  • ツールはdocument.modelContext.registerTool()で登録し、name、description、inputSchemaが必須です。navigator.modelContextは以前の名前空間で、古いスニペットにはまだ登場します。
  • 3つのアノテーションヒントがエージェントの挙動を変えます。readOnlyHint、consequentialHint、untrustedContentHintです。
  • 登録されたツールは、ユーザーのサインイン済みセッションの下でライブページ内で実行されます。したがって公開するすべての機能は、エージェントがそのユーザーの権限で行使できる機能です。
  • ChatGPTの組み込みブラウザは宣言的なHTMLフォームAPIをサポートせず、iframe内のツールも検出しません。そのため、トップレベルのドキュメントで命令的に登録してください。
  • WebMCPはディスカバリーのチャネルではありません。エージェントがページを読み込むまでサイトのツールは何も広告されないため、Chromeはツールの発見可能性を未解決の制約として挙げています。

逆転:WebMCPは何が違うのか?

サーバーサイドのMCPサーバーは、エージェントが外向きに接続する対象であり、一度設定すれば、開いているページとは独立して到達可能です。WebMCPは逆方向に動きます。OpenAIのサイトツールのドキュメントは、ツールがどこに存在するかで線引きをしています。MCPはAIアプリケーションを、ページの外側に位置しブラウザが開いているかどうかに関係なく動作するサーバー(ローカルまたはリモート)に向けます。WebMCPサイトは、自身の機能を、エージェントが到着時に見つけられる出来合いのツール群として引き渡します。ユーザーがインストールするものは何もありません。

見返りは精度です。ChromeのWebMCPドキュメントは、コントロールが何を意味するかを誰が決めるのかという観点でこの違いを説明しています。ツールがあれば、サイトがそれを直接宣言し、エージェントには推測する余地が残りません。アクチュエーションでは一連のステップと、その各段階での判断が必要になります。あなたが書いたスキーマに対してsearch_orders({ status: "open" })を呼び出すエージェントは、フィルターのドロップダウンをクリックし損ねることはありませんし、あなたがCSSクラス名を変更したせいで壊れることもありません。

document.modelContext.registerTool()でツールを登録するには?

ツール登録はname、description、inputSchemaを持つオブジェクトを受け取ります。Chromeの命令的APIリファレンスはこの3つを必須フィールドとして扱い、annotationsとexecute関数が挙動を担います。このAPIはまだほとんどのブラウザに存在しないため、OpenAI自身の例と同じように、呼び出す前に機能検出を行ってください。

async function registerAgentTools() {
  if (typeof document.modelContext?.registerTool !== "function") return;

  await document.modelContext.registerTool({
    name: "list_orders",
    description:
      "List the signed-in customer's orders, newest first, optionally filtered by fulfilment status. Returns order number, placed date, status and total.",
    inputSchema: {
      type: "object",
      properties: {
        status: {
          type: "string",
          enum: ["open", "shipped", "delivered", "cancelled"],
          description: "Fulfilment status to filter by. Omit for all orders.",
        },
        limit: {
          type: "integer",
          minimum: 1,
          maximum: 20,
          description: "Maximum orders to return. Defaults to 10.",
        },
      },
      required: [],
      additionalProperties: false,
    },
    annotations: { readOnlyHint: true },
    // Same function the orders table calls. The API still checks the session.
    execute: async ({ status, limit = 10 }) => fetchOrders({ status, limit }),
  });
}

descriptionは、このツールがリクエストに適合するかどうかを判断する際にモデルが読む唯一の情報です。したがって、その背後にあるコードと同じだけの重みを持ちます。戻り値の形を明示し、フィルターを明示し、そのツールがカバーしないことを述べてください。

ここでexecuteが何をしているかに注目してください。委譲しています。ツールはUIが呼ぶのと同じデータ取得関数を呼び、その背後のサーバーはすでに適用しているのと同じ認可を適用します。OpenAIのガイダンスは、並行した経路ではなく既存の認証・認可を使うよう開発者に促しており、そのエンジニアリング上の理由は明白です。同じ機能への2つのコードパスは必ず乖離し、そしてUIが前面にない方こそ、誰も乖離に気づかない方だからです。

3つのアノテーションヒントは何を変えるのか?

アノテーションは、エージェントがツールを呼び出す前にそのツールをどう扱うべきかを伝えるメタデータです。Chromeは3つを文書化しており、Chromeのツールセキュリティガイダンスはそれぞれをシグナルするリスクの観点から捉え直しています。

ヒント設定するときエージェントへの影響
readOnlyHintツールが読み取りのみを行い、何も変更しない場合確認が必要かどうかをそもそもエージェントが判断できるようになる
consequentialHintアクションが現実世界に影響し、取り消せない場合(決済、送金、予約など)エージェントまたはブラウザに、先にユーザーの確認を取るよう伝える
untrustedContentHint出力にユーザー生成コンテンツや外部データが含まれる場合ペイロードを信頼できないものとしてマークし、エージェントが一層慎重に扱うようにする

ツールごとに、意図的に設定してください。consequentialHintのないcancel_subscriptionツールは、エージェントが一呼吸置かずに実行しかねないツールです。またuntrustedContentHintのないレビュー取得ツールは、見知らぬ他人が書いたテキストの塊を、何の目印もなくモデルに渡すことになります。

WebMCPは今日どこで動作するのか?

OpenAIのサイトツールのページは、ChatGPTが登録されたツールを尊重する場所を示しています。それはChatGPTデスクトップアプリの組み込みブラウザ(最新の状態に保たれたもの)であり、そこではChatGPT WorkとCodexがページの提供するものを見つけて呼び出せます。モデルも関係します。GPT-5.6 SolとGPT-5.6 Terraがサポートされ、GPT-5.6 LunaではWebMCPは無効化されています。EnterpriseとEduのワークスペースは対象外で、そもそも機能が表示されるかどうかはロールアウト状況と、開いているページが何を登録しているかに依存します。アドレスバーの矢印がページの提供するツールを一覧表示し、機能全体はブラウザの権限設定からオフにできます。

Chromeの実装はまだプレビュー段階です。Chromeはローカル開発向けにchrome://flags/#enable-webmcp-testingフラグ(Enabledに設定して再起動)の背後でWebMCPを文書化しており、あわせてChrome 149から参加できるオリジントライアルも提供しています。安定版ではデフォルトで有効ではなく、両ベンダーのサポート表明も変動するため、これらに依存して出荷する前に元のページを確認してください。

ChatGPTのブラウザがサポートしないもの

OpenAIのドキュメントは、組み込みブラウザがWebMCPの一部しかカバーしないことを明記しており、2つのギャップを挙げています。HTMLフォーム属性で定義されたツールはサイトツールになりません。またiframe内で登録されたツールは検出されず、これは同一オリジンのiframeも含みます。実務上の指示は短いものです。トップレベルのドキュメントで命令的に登録し、風変わりな手法に頼らないこと。

そのiframeの制限はChatGPT側のものであり、標準仕様のものではありません。Chromeは両方のAPIをtools Permissions Policyの背後に置いており、その初期値はselfです。このデフォルトでは、トップレベルのドキュメントと同一オリジンのフレームはツールを登録できますが、クロスオリジンのiframeはできません。別オリジンに埋め込まれたウィジェットがツールを登録するには、そのフレームにtoolsポリシーが付与され、ツールが認可されたオリジンを列挙するexposedToを渡し、呼び出し側がgetTools()にfromOriginsを渡す必要があります。さらにChromeはWebMCPをオリジン分離されたドキュメントに限定しているため、document.domainを使用しているページではAPIがまったく利用できません。

あなたのツールはログイン中のユーザーとして実行される

登録されたツールは、ユーザーのサインイン済みセッションの下でライブページ内で実行されます。つまり、公開するすべての機能は、エージェントがそのユーザーの権限で行使できる機能だということです。スコープを決める際の問いは「自動化できたら便利なのは何か」ではありません。「クリックなしで呼び出されても受け入れられるのは何か」です。

Chromeのセキュリティガイダンスは、それが重要である理由について異例なほど率直です。モデルは命令とデータを一続きのトークン列として受け取り、両者の間に境界はありません。確率的な仕組みの内部で安全性を保証することはできません。プロンプトインジェクションは、入手可能な最良のモデルで動作するエージェントシステムに対して、すでに繰り返し成功しています。そしてウェブ上でのそうした攻撃の件数は増え続けています。OpenAIもツール自体についてほぼ同じことを述べており、サイトツールのドキュメントでは、ウェブサイトのツール定義とそれが返す結果の双方を信頼できないコンテンツとして扱っています。

そこから3つの具体的な対策が導かれます。まず、ツールの可視性は閉じた状態から始まります。他のサイトやクロスオリジンのiframeは、exposedToでそれらのオリジンを指定するまであなたのツールを見ることができません。ユーザーデータを露出する読み取り専用ツールにも、書き込みツールと同じ注意を払ってください。またChromeは、あなたが開いたわけではないアクセス経路についても言及しています。拡張機能はコンテンツスクリプトからあなたのツールを照会・実行でき、あなたのサイトに対するhost_permissionを持つ拡張機能はそもそもページ上で独自のJavaScriptを実行できます。そしてテキストは小さく保つこと。Chromeはツールのdescriptionに500文字、パラメータのdescriptionごとに150文字、ツール名とパラメータ名に30文字、ツール出力ごとに1.5Kを推奨しており、これら4つすべてを、エコシステムからのフィードバックにより変わりうる推奨値であり、後に正式化される可能性があるものと説明しています。同意管理に関する作業は継続中で、実行途中にユーザーへ問い合わせるための仕様草案requestUserInteraction()も含まれますが、これはまだ出荷されていません。

WebMCPはSEO施策ではない

サイトツールを登録することは、エージェントがあなたのページに到着した後に何ができるかを変えます。到着させることには何の効果もありません。Chrome自身の制約リストは、ツールの発見可能性を未解決の課題として挙げています。クライアントやブラウザは、そこに行くことでしか、サイトに呼び出し可能なツールがあることを知り得ません。クロールもインデックスも、登録済みツールのフィードも存在しません。この仕組みと併せて読むと、結論は単純です(ただしこれはベンダーの表明ではなく我々の解釈です)。WebMCPはコンバージョン経路上の接点であって、ランキングや引用を左右するレバーではありません。ツールのdescriptionをメタディスクリプションのコピーのように扱うのは、それを誰が読むのかを取り違えています。

ユーザーがすでにあなたのサイト上で完了させているアクションを1つ選び、まずは読み取り専用で登録し、本当の労力はdescriptionとスキーマに注ぎ込んでください。エージェントがあなたのアプリケーションを理解できるかどうかが決まるのはそこであり、どのブラウザのロールアウトもあなたの代わりに解決してはくれない部分です。

FAQ

ユーザーがページを離脱したとき、WebMCPツールの登録をどう解除すればよいですか?

unregisterToolメソッドは存在しません。document.modelContext.registerToolのオプションオブジェクトにAbortSignalを渡し、コンポーネントのアンマウントやSPAのルート変更など、そのツールが適用されなくなった時点でコントローラーをabortしてください。Chromeのベストプラクティスはこれをページの状態という観点で説明しています。ツールが有用な間は登録し、そうでなくなったら登録を解除する、ということです。abortをページ遷移に紐付けるのがそれを実現する実務的な方法であり、古いツールが残り続けたり、同名の新しい登録と衝突したりするのを防げます。エージェントはdocument.modelContext上のtoolchangeイベントを通じてこの変更を検知します。

宣言的WebMCP APIと命令的WebMCP APIの違いは何ですか?

宣言的APIは既存のHTMLフォームをツールに変えます。form要素にtoolnameとtooldescription属性を追加し、個々のフィールドにtoolparamdescriptionを付けると、ブラウザがそのフォームから構造化された表現を導出します。どちらかの属性を削除すると、ツールの登録は解除されます。命令的APIであるdocument.modelContext.registerToolは、動的なツールや複雑なロジックに適しています。ChatGPTの組み込みブラウザは命令的な方法のみをサポートします。

WebMCPツールの登録にReactやAngularのサポートはありますか?

どちらも存在しますが、いずれも実験的です。Chrome Labsはuse-webmcp-toolパッケージでuseWebMCPフックを提供しており、マウント時にツールを登録し、アンマウント時に登録解除します。React 18以降が必要で、APIが存在しない環境ではno-opに縮退します。AngularはコアパッケージからprovideExperimentalWebMcpToolsを公開しており、ツールの生存期間をインジェクターに紐付けます。ルートプロバイダーまたはアプリケーションプロバイダーへの配置が推奨されています。

ブラウザは、エージェントが渡した引数を自分のinputSchemaに対して検証してくれますか?

してくれると想定しないでください。executeに到達する入力は未検証のものとして扱い、処理する前にコード内でチェックしてください。ChromeのWebMCPガイダンスは、制約を検証し、エージェントが再試行できるよう説明的なエラーを返すよう開発者に指示しています。またAngularは、宣言したJSONスキーマに対してエージェント提供の引数をチェックしないと明言しています。その上でサーバーサイドの認可チェックも引き続き適用されます。

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.