想像一下,未來的 AI Agent 幫你在網頁上訂機票、買東西時,不再需要靠「螢幕截圖 + 猜按鈕」這種網站一改版就崩潰的方式,而是你的網站主動對 Agent 宣告:「我有這些 API,你可以直接呼叫」。
這就是 W3C 正熱烈討論中的 WebMCP(Web Model Context Protocol)。
如果說各路大神推出的 MCP 是讓 AI 操作你的「後端伺服器」,那麼 WebMCP 就是讓 AI 直接在「使用者瀏覽器」裡流暢操作 UI 的關鍵最後一哩路,這篇文章會用 Chrome 151 實測,帶你快速掌握宣告式(Declarative)與命令式(Imperative)API 的差異,並透過官方 3 個真實使用者案例,看看工具如何隨頁面動態長出!
WebMCP 是什麼?
WebMCP(Web Model Context Protocol)是 W3C 正在討論的網頁標準,核心概念是網站用 JavaScript 或 HTML 註解,向具備代理能力的瀏覽器註冊「工具」,而當 Agent 代理碰到註冊過的工具,就可以直接呼叫相關函式並拿到結構化結果,不用再靠螢幕截圖 + 猜按鈕。
MCP 是後端標準,讓代理連到你的伺服器拿資料;WebMCP 是前端標準,讓代理在你開著的這個分頁裡操作 UI。
MCP 的生命週期是永久的(伺服器常駐),而WebMCP 是暫時的(關掉分頁就沒了),在你的服務上如果同時提供了MCP與WebMCP,便可以理解成 MCP 管核心邏輯,WebMCP 管最後一哩的使用者介面處理。
宣告式 API:兩個屬性,表單直接變成工具
宣告式 API 是 WebMCP 的最吸引人的部分,你不用寫一行 JavaScript,直接在 <form> 上加上 toolname 和 tooldescription的注記就完成tool的註冊:
<form toolname="createSupportRequest"
tooldescription="Submits a request for customer support.">
<label for="name">姓名</label>
<input type="text" id="name" name="name">
<label for="topic">問題類型</label>
<select name="topic" toolparamdescription="決定問題要路由給哪個團隊">
<option value="billing">帳單問題</option>
<option value="tech">技術問題</option>
</select>
<button type="submit">送出</button>
</form>
實測後發現 document.modelContext.getTools() 會自動把這個表單轉成完整的 JSON Schema——<select> 的選項變成 anyOf + enum,toolparamdescription ,而 <label> 的中文文字變成欄位說明,也就是說當Agent 識別到這個 schema 後,就知道這個表單可以填什麼,以及每個欄位接受什麼值。
進階控制有三個屬性可以玩:
-
toolparamdescription:單一欄位的用途說明,沒寫就用<label>的文字。 -
toolautosubmit:加上後,代理呼叫工具會直接提交表單並導航,不用等人按送出。 -
SubmitEvent.agentInvoked:表單提交時這個布林值會告訴你「這次提交是代理發起的」。搭配respondWith(Promise)可以讓代理拿到非同步的執行結果。
另外還有 :tool-form-active 和 :tool-submit-active 兩個 CSS pseudo-class,讓代理在填表單時可以用來顯示正在輸入的欄位,使用者也可以看得到「AI 正在幫我填」的UI顯示。
命令式 API
命令式 API 適合在不是表單處理的場景來做使用——像是查訂單狀態、跑診斷、做狀態管理,主要提供三個方法,全部掛在 document.modelContext 上:
// 註冊工具
await document.modelContext.registerTool({
name: 'get_order_status',
description: '查詢訂單狀態,回傳訂單編號、運送狀態與地點',
inputSchema: {
type: 'object',
properties: {
orderId: { type: 'string', description: '訂單編號' }
},
required: ['orderId']
},
execute: async ({ orderId }) => {
return `訂單 ${orderId} 已出貨,狀態:運送中`;
},
});
// 列出可用工具
const tools = await document.modelContext.getTools();
// 手動執行工具
const result = await document.modelContext.executeTool(tools[0], '{"orderId": "ORD-123"}');
實測的三個方法全部正常:registerTool 成功註冊、getTools() 同時列出自訂工具和宣告式表單工具、executeTool 正確回傳執行結果,另外 toolchange 事件在工具清單變更時會觸發,AbortSignal 則可以取消工具執行或註冊。
不過有個說明有寫但是不是太清楚的部分是,Chrome 150 已把 navigator.modelContext 淘汰,改用 document.modelContext (W3C Web Incubator Community Group 討論中)。不過我的 Chrome 151 上兩者都還是 object,記得此時此刻如果要開工的話,就一律用 document.modelContext 就對了。
官方 demo 的旅程
官方 webmcp-tools repo 的 demos 資料夾有 15 個情境,我試了幾個比較完整 UX 的實測,這邊有一個跟Server MCP比較不一樣的,WebMCP 工具不是一次全給的,而是會跟著頁面狀態長出來
WebMCP Sports
WebMCP Sports 是 Angular 寫的體育用品電商,首頁有 5 個全站工具:
search_productview_productget_product_infoopen_cartget_store_promos_and_rules
在實測中 search_product {"query":"basketball","category":"BASKETBALL"},得到回傳 count:5 並切到搜尋結果頁,getTools() 結果直接變成 8 個,多出
refine_searchget_current_search_resultsadd_search_result_to_cart
接著再呼叫 open_cart 開購物車,工具一口氣長到 13 個XD
結帳相關的tool都飄出來了
start_checkoutconfirm_orderupdate_cart_delivery_optionremove_from_cart-
get_cart
突然有一種以前在練習寫購物車的架構與function標準答案 一一浮現的感覺。
三層 scope 的設計讓全站工具、搜尋頁工具、購物車工具分層註冊,Agent 當下能看到的最小工具set,永遠只跟目前 UI 狀態匹配,比起一般的 MCP 一次註冊 20 個工具,這種設計讓Agent不會亂呼叫不該叫的工具反而好很多,應該也比較省Token。
而工具自己也會驗證參數。我故意傳 {"price_range":"wrong"} 給 refine_search,結果 WebMCP 回傳 {"success":false,"message":"Invalid price range 'undefined'. Must be one of: 'all', '0-49.99', '50-99.99', '100+'"}。
另外它還內嵌一個 Gemini on-site AI assistant,站在網站自己那一側幫你聊天導購。「網站自帶代理」跟瀏覽器層級的代理是兩條路線,這個 demo 兩條都示範了。
L'Atelier 飯店訂房
另一個範例 L'Atelier 是 React 寫的豪華飯店訂房 app,東京、巴黎、紐約三家分店。首頁先是註冊了 三個工具。
search_locationview_hotel-
lookup_amenity
我從 DevTools Protocol 直接呼叫 executeTool(search_location, {"query":"Tokyo"}),回傳值是這樣的:
{"content":[{"type":"text","text":"{\"success\":true,\"message\":\"Navigated to search results for Tokyo with active search filters applied.\"}"}]}
這邊要注意的是回傳的結果包了一層 content 陣列,很多時候 WebMCP 的執行結果就是 MCP 的 content block 格式,而在我呼叫完 getTools(),工具清單又變成 6 個,多出了
filter_search_resultsget_current_search_resultsreset_filters
搜尋結果頁有自己的工具,代理跳到哪一頁,哪一頁的工具才上線。
除了基本的防呆之外,WebMCP 也提供狀態檢查,我手癢直接 view_hotel,回傳 {"success":false,"error":"Could not find a hotel matching \"1\". Please search first."}。
而代理亂呼叫也是會被擋的,start_booking 在搜尋結果頁根本不存在,要到飯店詳情頁才註冊,而整條操作旅程的最後一步(complete_booking 填客人資料)是宣告式表單,命令式 API 開頭、宣告式API 收尾,跟在真實 app 裡的架構上滿match的。
一些小限制們
WebMCP 有三個明確的限制:
一定要有瀏覽器環境。 工具呼叫是在 JavaScript 裡處理的,所以代理必須真的開著一個可見的分頁或 WebView,headless 環境下無法呼叫,這跟 MCP server 隨時待命完全不同。
網站太複雜會很痛。 如果頁面狀態複雜,要利用 JavaScript 去處理應用程式和 UI 狀態的同步,宣告式 API 也幫不了你,Agent能不能利用工具來探索性也是問題,也之後就會有給 Agent看的 sitemap ?
權限政策和跨源 iframe。 工具預設被 tools Permissions Policy 擋住(Same-Origin Policy),跨源 iframe 要加 allow="tools" 且網域需在白名單內,跨源分享工具還要 exposedTo + fromOrigins 兩個參數都設定才生效,以防止潛在的 Clickjacking 與工具注入攻擊
開始的起手式
-
開 flag:
chrome://flags/#enable-webmcp-testing設為 Enabled,重啟 Chrome。正式環境去加入 WebMCP origin trial。 -
選一個表單下手:找站上最常用的搜尋或表單,加上
toolname和tooldescription,最多 5 分鐘。 - 用 Inspector 驗證:裝 Model Context Tool Inspector 擴充功能,看工具有沒有正確註冊、schema 對不對,再用自然語言 prompt 叫代理執行。
從「給人看」到「給 Agent 用」的 Web 前端新浪潮
WebMCP 的核心價值,不是讓網站多一個花哨的 AI 聊天視窗,而是讓你的網站直接升級為 Agent Ecosystem(代理生態系)的成員。



Top comments (0)