iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Modern Web

WebMCP:30 天打造 AI Agent 看得懂、也操作得動的網站系列 第 10

Day 10|表單不用重寫一套 Tool?Declarative WebMCP 把現有 HTML 直接給 AI 用

  • 分享至 

  • xImage
  •  

本篇重點

WebMCP 不只有 registerTool()。Chrome 目前也提供 Declarative API:在標準 HTML <form> 上增加 toolnametooldescription,表單欄位就能被瀏覽器轉成 Tool parameters。

如果網站本來已經有一張正確、可存取、驗證完整的 Form,Declarative API 可以減少「UI 一份、Tool Schema 又一份」的重複。

最小範例只要兩個屬性

原本:

<form action="/support" method="post">
  <label>
    Email
    <input type="email" name="email" required>
  </label>

  <label>
    Message
    <textarea name="message" required></textarea>
  </label>

  <button type="submit">送出</button>
</form>

加上:

<form
  toolname="create_support_request"
  tooldescription="Submit a customer support request."
  action="/support"
  method="post"
>

就把這張 Form 宣告成 Tool。

官方文件目前的兩個核心屬性是:

toolname
tooldescription

如果移除其中一個,該 Declarative Tool 也會被解除註冊。

Form 欄位會變成 Tool Parameters

例如:

<label for="category">問題類型</label>
<select
  id="category"
  name="category"
  required
  toolparamdescription="The support category used to route this request."
>
  <option value="billing">帳務</option>
  <option value="technical">技術</option>
  <option value="account">帳號</option>
</select>

瀏覽器可以把 select 的選項轉成 Schema 的有限值。

另外可用:

toolparamdescription

替欄位補上更精準的參數語意。

如果沒有寫,瀏覽器會參考關聯的 <label> 等既有 HTML 語意。

這也提醒我們:Accessible HTML 對 Agent-friendly Web 也有幫助。

完整 Support Form

<form
  id="support-form"
  toolname="create_support_request"
  tooldescription="Prepare a customer support request using the user's email, category, and message."
  action="/support"
  method="post"
>
  <label for="email">Email</label>
  <input
    id="email"
    type="email"
    name="email"
    required
    toolparamdescription="Email address for the support reply."
  >

  <label for="category">問題類型</label>
  <select
    id="category"
    name="category"
    required
    toolparamdescription="Category used to route the support request."
  >
    <option value="billing">帳務</option>
    <option value="technical">技術</option>
    <option value="account">帳號</option>
  </select>

  <label for="message">問題描述</label>
  <textarea
    id="message"
    name="message"
    required
    toolparamdescription="Description of the user's support issue."
  ></textarea>

  <button type="submit">送出</button>
</form>

實際操作 1:確認 HTML 表單已成為 Tool

以下操作使用 Day 10 本地 Demo 的 index.html 與 app.js。Demo 補上了 submitSupportForm()、結果顯示與事件紀錄,使用本地模擬工單,不寄送郵件、不建立真實客服需求。前面的 action="/support" 是後端路徑示意;本地 Demo 不依賴這個端點,而是由 submit handler 攔截並處理。

  1. 透過 localhost 或 ServBay 開啟 Demo,重新整理。
  2. 確認頁面顯示「✅ create_support_request 已由 HTML 表單註冊」。
  3. 開啟 WebMCP - Model Context Tool Inspector,確認清單有 create_support_request
  4. 保持表單尚未填寫,在 Inspector 展開 Tool 的 Description 與 Input Schema。
  5. 確認 Schema 包含 emailcategorymessage,並查看 category 的 billing、technical、account 選項值。

toolnametooldescriptiontoolparamdescription 是 HTML 屬性,不會直接顯示在輸入欄位上。本地 Demo 的「HTML 宣告與瀏覽器實際 Schema」區塊可展開查看原始宣告與瀏覽器讀取結果。

📸 圖片 1|HTML 表單與瀏覽器產生的 Tool Schema
https://ithelp.ithome.com.tw/upload/images/20260919/20121296ZxuSWGQ9dz.png

Agent 呼叫時,瀏覽器會把 Form 帶入焦點並填入欄位,使用者仍可以看到內容。

這點我很喜歡:不是黑箱在背景偷偷填資料,而是能保留 UI 作為人類確認介面。

實際操作 2:Agent 填妥表單,等待使用者確認

  1. 確認表單是空的;若有舊資料,先按「取消並重設」。
  2. 在 Inspector 開啟 Interact with the Page。若尚未設定,先透過 Set Gemini API Key 完成設定。
  3. 輸入:
請幫我準備一筆客服需求:
Email 是 reader@example.com,
問題類型是技術問題,
問題描述是「登入後無法查看訂單,請協助確認」。
填好表單後讓我確認,先不要送出。
  1. 等待 Agent 選擇 create_support_request 並填入表單。
  2. 先不要按「確認並模擬送出」。

預期 Email 為 reader@example.com、問題類型為「技術」、問題描述為「登入後無法查看訂單,請協助確認」。頁面會提示「Agent 已填入表單,請確認內容後送出,或取消並重設」,最後一次送出結果仍是「尚未送出」。

此時 Tool 呼叫仍在等待完成是正常流程。不需要等到 Inspector 出現成功結果;這個階段觀察的是 toolactivatedagentInvoked 則是在 submit 階段檢查。

📸 圖片 2|Agent 填妥客服表單,等待人工確認
https://ithelp.ithome.com.tw/upload/images/20260919/201212969XlgANa8Xo.png

另一種驗證:Inspector 手動呼叫

如果只想驗證 Declarative Tool 能否填表,可在 Inspector 選擇 create_support_request,於 Input Arguments 貼上:

{
  "email": "reader@example.com",
  "category": "technical",
  "message": "登入後無法查看訂單,請協助確認。"
}

按 Execute Tool 後,觀察表單是否填入。category 要使用 technical 等選項值,而非中文顯示文字。這種測試的圖說應寫「Inspector 呼叫 Tool 後填入表單」;它沒有經過自然語言 Agent 的選擇與參數生成。

要不要自動 Submit?

預設可以讓使用者自己按最後的 Submit。

如果真的希望 Tool 呼叫時自動送出,可以加:

<form
  toolautosubmit
  toolname="search_tool"
  tooldescription="Search public site content."
>

但不要看到 toolautosubmit 就每張 Form 都加。

我會這樣分:

搜尋/篩選
→ 可以考慮 auto submit

聯絡表單
→ 視風險與 UX

付款/刪除/發布
→ 不要只靠 auto submit,應有明確確認流程

Agent 觸發 Submit 時怎麼知道?

Declarative API 擴充 SubmitEvent,提供 agentInvoked

const form = document.querySelector('#support-form');

form.addEventListener('submit', (event) => {
  if (event.agentInvoked) {
    console.log('Submitted by an agent');
  }
});

如果要自己處理請求並把結果回給 Agent,可以搭配:

event.preventDefault();
event.respondWith(promise);

例如:

form.addEventListener('submit', (event) => {
  event.preventDefault();

  const task = submitSupportForm(new FormData(form))
    .then(result => ({
      status: 'success',
      ticketId: result.id
    }));

  if (event.agentInvoked) {
    event.respondWith(task);
  }
});

上面的 submitSupportForm() 是請求處理函式的示意。本地 Demo 已補上實作,直接回傳包含 status、ticketId、simulated 與 request 的結果,因此可直接將它產生的 task 交給 respondWith,不需要再讀取 result.id。

respondWith(task) 必須在 submit handler 中同步呼叫;把非同步工作放進 task,不要先 await 工作完成才呼叫 respondWith。

實際操作 3:確認送出並查看結果

  1. 接續圖片 2 的填表狀態,檢查三個欄位。
  2. 按頁面的「確認並模擬送出」。
  3. 等待頁面顯示「模擬送出完成,結果與表單內容已保留」。
  4. 查看 Inspector 的回傳結果。

第一次成功送出的預期結果:

{
  "status": "success",
  "ticketId": "DEMO-001",
  "simulated": true,
  "request": {
    "email": "reader@example.com",
    "category": "technical",
    "message": "登入後無法查看訂單,請協助確認。"
  }
}

request 會保留實際送出的內容,包含使用者在確認前的修改。若已成功測試多次,工單編號會遞增。

📸 圖片 3|確認送出後,回傳模擬工單結果
https://ithelp.ithome.com.tw/upload/images/20260919/20121296ln0V7dZUo5.png

三張圖依序對應:表單成為 Tool → Agent 填表 → 使用者確認並取得結果

還有 toolactivated / toolcancel

當 Agent 啟用 Declarative Tool 並填好欄位後,window 會收到:

window.addEventListener('toolactivated', ({ toolName }) => {
  console.log('Activated:', toolName);
});

取消則是:

window.addEventListener('toolcancel', ({ toolName }) => {
  console.log('Cancelled:', toolName);
});

可以拿來:

  • 顯示 UI 提示。
  • 更新 Validation。
  • 記錄使用者是否取消。
  • 切換 Agent interaction 的畫面狀態。

再測一次取消流程

再次呼叫 create_support_request,等表單填妥後,改按「取消並重設」。檢查表單是否重設,以及互動事件紀錄是否出現 toolcancel。這次不應產生新的模擬工單。

手動輸入表單並送出也能驗證一般使用者流程,但不能當作 Agent 填表的證據。

Imperative 還是 Declarative?

我自己的判斷:

情境 建議
已有標準 HTML Form Declarative 優先評估
複雜資料查詢 Imperative
多 API 串接 Imperative
需要完全自訂 Result Imperative 或 Declarative + respondWith
單純填表並讓使用者確認 Declarative 很適合

不是誰比較高級,而是不要重複實作。

可帶走的重點

  1. Declarative API 可以把既有 Form 直接宣告成 Tool。
  2. 核心屬性:toolnametooldescription
  3. toolparamdescription 可以補欄位語意。
  4. toolautosubmit 要依風險使用,不是預設全部打開。
  5. agentInvokedrespondWith()toolactivatedtoolcancel 讓網站能處理 Agent 互動生命週期。
  6. 好的 HTML label/accessibility 不只幫人,也幫助 Tool 語意。

參考資料


上一篇
Day 09|登入前後 Tools 不一樣怎麼辦?動態註冊 WebMCP Tool 實戰
下一篇
Day 11|別再讓 AI 找搜尋框:把網站搜尋縮成一次 WebMCP Tool Call
系列文
WebMCP:30 天打造 AI Agent 看得懂、也操作得動的網站14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言