Imperative API ใช้ document.modelContext.registerTool() เพื่อกำหนดเครื่องมือ JavaScript แบบเป็นโปรแกรม ซึ่งเหมาะสําหรับแอปพลิเคชันหน้าเว็บเดียว (SPA) ที่ต้องเพิ่มหรือนําเครื่องมือออกตามเส้นทางปัจจุบันหรือสถานะของผู้ใช้
WebMCP ทำงานบนสถาปัตยกรรมผู้ผลิต/ผู้บริโภค ดังนี้
- หน้าเว็บเป็นผู้สร้างเครื่องมือ: คุณกำหนดและลงทะเบียนเครื่องมือโดยใช้
document.modelContext.registerTool()หน้าเว็บต้องติดตั้งใช้งานเพียงเท่านี้ คุณไม่จำเป็นต้องเรียกใช้getTools()หรือexecuteTool()ในหน้าเว็บเพื่อแสดงเครื่องมือต่อ Agent - ตัวแทนเบราว์เซอร์และส่วนขยายเป็นผู้ใช้หลัก: ตัวแทนที่เบราว์เซอร์จัดหาให้หรือผ่านเบราว์เซอร์ ซึ่งรวมถึงตัวแทนในตัวของเบราว์เซอร์, ส่วนขยายเบราว์เซอร์, เครื่องมือสำหรับนักพัฒนาเว็บ และผู้ช่วยระดับระบบ จะค้นพบและเรียกใช้เครื่องมือที่ลงทะเบียนไว้นอกแบนด์ผ่านกลไกแพลตฟอร์มภายใน
- เอเจนต์ในหน้าเว็บและโปรแกรมทดสอบอัตโนมัติ:
getTools()และexecuteTool()มีไว้สำหรับผู้ช่วย JavaScript ในหน้าเว็บโดยเฉพาะ (เช่น วิดเจ็ตแชทที่ฝังหรือ<iframe>) และชุดโปรแกรมทดสอบอัตโนมัติที่ต้องค้นหาและเรียกใช้เครื่องมือโดยตรงภายในบริบทของหน้าเว็บ
การลงทะเบียนและวงจร
ระบบจะลงทะเบียนเครื่องมือโดยการส่งออบเจ็กต์คำจำกัดความของเครื่องมือและออบเจ็กต์ตัวเลือกที่ไม่บังคับ (ModelContextRegisterToolOptions) ซึ่งรองรับสมาชิกที่ไม่บังคับ 2 รายการ ได้แก่
signal:AbortSignalที่ใช้เพื่อยกเลิกการลงทะเบียนเครื่องมือเมื่อไม่จำเป็นต้องใช้แล้วexposedTo: อาร์เรย์ของสตริงต้นทางที่ควบคุมว่าเอกสารใดในโครงสร้างเอกสารที่ได้รับอนุญาตให้ค้นพบและเรียกใช้เครื่องมือข้ามขอบเขตเฟรม
การจัดการวงจรด้วย AbortController
WebMCP ไม่มีเมธอด unregisterTool() หากต้องการยกเลิกการลงทะเบียนเครื่องมือ คุณต้องส่ง AbortSignal ระหว่างการลงทะเบียนและยกเลิกสัญญาณดังกล่าวเมื่อไม่จำเป็นต้องใช้เครื่องมืออีกต่อไป
const controller = new AbortController();
await document.modelContext.registerTool({
name: "get_user_preferences",
description: "Retrieves the user's saved preferences.",
inputSchema: { type: "object", properties: {} },
execute() {
const prefs = localStorage.getItem("user_prefs");
return prefs ? JSON.parse(prefs) : { theme: "light" };
},
annotations: { readOnlyHint: true }
}, { signal: controller.signal });
// To unregister the tool (e.g., on component unmount):
controller.abort();
การยกเลิกสัญญาณการลงทะเบียนจะยกเลิกการลงทะเบียนเครื่องมือเท่านั้น แต่จะไม่ยกเลิกการดำเนินการที่ทำงานอยู่แล้ว เครื่องมือที่เริ่มงานที่ใช้เวลานานต้องเป็นไปตามสัญญาณต่อการดำเนินการที่อธิบายไว้ด้านล่างด้วย ไม่เช่นนั้นการยกเลิกการลงทะเบียนจะทำให้คำขอที่ไม่มีเจ้าของและการอัปเดต UI ที่ล้าสมัยยังคงอยู่
การควบคุมการแสดงเครื่องมือแบบข้ามต้นทางด้วย exposedTo
โดยค่าเริ่มต้น เครื่องมือที่ลงทะเบียนจะเป็นแบบส่วนตัวสำหรับเอกสารที่ลงทะเบียนและเฟรมต้นทางเดียวกัน เมื่อแอปพลิเคชันของคุณฝังอยู่ใน <iframe> (หรือฝังวิดเจ็ตของบุคคลที่สาม) และคุณต้องการเฟรมระดับบนหรือระดับเดียวกันเพื่อค้นหาและเรียกใช้เครื่องมือ ให้ระบุต้นทางที่อนุญาตโดยใช้ exposedTo
const controller = new AbortController();
await document.modelContext.registerTool({
name: "get_cart_items",
description: "Retrieves items currently in the user's shopping cart.",
inputSchema: { type: "object", properties: {} },
async execute(input, { signal }) {
return await cartService.getItems({ signal });
},
annotations: { readOnlyHint: true },
}, {
signal: controller.signal,
exposedTo: ["https://checkout.example.com"],
});
- การแฮนด์เชคแบบเลือกใช้ร่วมกัน: การค้นพบเครื่องมือแบบข้ามต้นทางเป็นการเลือกใช้แบบ 2 ทาง เฟรมของผู้ให้บริการเครื่องมือจะให้สิทธิ์ต้นทางของผู้บริโภคผ่าน
exposedToและเฟรมของผู้บริโภคต้องขอต้นทางของผู้ให้บริการนั้นอย่างชัดแจ้งผ่านgetTools({ fromOrigins: [...] })หากไม่มีfromOriginsgetTools()จะค้นหาเฉพาะเอกสารที่มีต้นทางเดียวกัน - การจับคู่ต้นทาง: ต้นทางของเอกสารการจดทะเบียนจะมีสิทธิ์เข้าถึงเสมอ ต้นทางที่ระบุใน
exposedToจะได้รับสิทธิ์ในการค้นหาเครื่องมือผ่านdocument.modelContext.getTools({ fromOrigins: [...] })และเรียกใช้ผ่านdocument.modelContext.executeTool() - ข้อกำหนดด้านความปลอดภัย: ต้นทางทุกรายการใน
exposedToต้องเชื่อถือได้ (HTTPS หรือ localhost) การส่งต้นทางที่ไม่ถูกต้องหรือไม่ปลอดภัยจะทำให้registerTool()ปฏิเสธด้วยSecurityError - ขอบเขต:
exposedToควบคุมการค้นพบข้ามเอกสารในหน้าเว็บในเฟรมต่างๆ ในแผนผังต้นไม้ของเอกสาร
การกำหนดพารามิเตอร์
พารามิเตอร์ (params) จะกำหนดโดยใช้พร็อพเพอร์ตี้ inputSchema ซึ่งต้องเป็นออบเจ็กต์ JSON Schema ที่อธิบายข้อมูลที่มีโครงสร้างที่เครื่องมือคาดหวัง
await document.modelContext.registerTool({
name: "calculate_area",
description: "Calculates the area of a rectangle.",
inputSchema: {
type: "object",
properties: {
width: { type: "number", description: "The width of the rectangle." },
height: { type: "number", description: "The height of the rectangle." }
},
required: ["width", "height"]
},
execute(input) {
// input is { width: 10, height: 20 }
return input.width * input.height;
},
annotations: { readOnlyHint: true }
});
คำอธิบายเครื่องมือและพารามิเตอร์การเขียน
Agent ได้รับ inputSchema ทั้งหมดแล้ว ดังนั้น description จึงต้องระบุเพียงสิ่งที่เครื่องมือทำและเวลาที่ควรใช้ อย่าใส่ชื่อพารามิเตอร์ ประเภท ค่า enum ค่าเริ่มต้น หรือขีดจำกัดซ้ำในคำอธิบาย ให้ประกาศข้อมูลเหล่านี้ในสคีมา (enum, default, minimum/maximum) แทน คำอธิบายพารามิเตอร์เป็นไปตามกฎเดียวกัน กล่าวคือ อธิบายความหมายของค่า ไม่ใช่ประเภทหรือค่าที่อนุญาต
เบราว์เซอร์จะไม่ตรวจสอบอาร์กิวเมนต์กับ inputSchema หรือใช้ค่า default ดังนั้นให้ทำทั้ง 2 อย่างใน execute
const SORT_ORDERS = ["newest", "price_low_to_high"];
await document.modelContext.registerTool({
name: "search_products",
// Don't list the sort orders here, even via SORT_ORDERS: `enum` already does.
description: "Searches the product catalog by keyword. Use when the user wants to find or compare products.",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Words to search for." },
sort: { type: "string", enum: SORT_ORDERS, default: "newest", description: "Order of the results." },
},
required: ["query"],
},
async execute({ query, sort = "newest" }, { signal }) {
if (typeof query !== "string" || !SORT_ORDERS.includes(sort)) {
return { error: "Pass a search query and a supported sort order.", sortOrders: SORT_ORDERS };
}
return await productService.search({ query, sort }, { signal });
},
annotations: { readOnlyHint: true },
});
รูปแบบการดำเนินการ
คอลแบ็ก execute จะได้รับอาร์กิวเมนต์ 2 รายการเสมอ ได้แก่ ออบเจ็กต์อินพุต และออบเจ็กต์ตัวเลือกที่มี AbortSignal ซึ่งก็คือ execute(inputObject, { signal })
กรณีที่ควรใช้ async execute
ใช้ async เมื่อเครื่องมือเกี่ยวข้องกับการดำเนินการที่แสดงผล Promise หรือใช้เวลาในการดำเนินการให้เสร็จสมบูรณ์
- การเรียกใช้เครือข่าย: การดึงข้อมูลจาก API
- พื้นที่เก็บข้อมูลแบบอะซิงโครนัส: การเข้าถึง IndexedDB
- เหตุการณ์ภายนอก: รอให้การเปลี่ยนแปลงสถานะหรือภาพเคลื่อนไหวที่เฉพาะเจาะจงเสร็จสิ้น
async execute(input, { signal }) {
const response = await fetch(`/api/data/${input.id}`, { signal });
return await response.json();
}
กรณีที่ควรใช้ execute (พร้อมกัน)
ใช้ฟังก์ชันแบบซิงโครนัสมาตรฐานสำหรับการดำเนินการทันที เครื่องมือแบบซิงโครนัสจะทำงานจนเสร็จก่อนที่จะสังเกตเห็นการยกเลิก จึงสามารถละเว้นสัญญาณได้ ดังนี้
- ตรรกะล้วนๆ: คณิตศาสตร์ การกรอง หรือการจัดเรียงข้อมูลที่มีอยู่แล้วในหน่วยความจำ
- สถานะแบบซิงโครนัส: การอ่านจาก
localStorageหรือเครื่องมือจัดการสถานะแบบซิงโครนัส
execute(input) {
return input.items.filter(item => item.active);
}
การจัดการข้อผิดพลาดใน execute
เมื่อ execute แสดงข้อผิดพลาด (หรือแสดงผลสัญญาที่ถูกปฏิเสธ) Agent จะได้รับเฉพาะข้อผิดพลาดในการดำเนินการทั่วไป ระบบจะไม่ส่งต่อข้อความแสดงข้อผิดพลาดไปยังตัวแทน หากเครื่องมือพบข้อผิดพลาดที่ดำเนินการได้หรือกู้คืนได้ (เช่น อินพุตไม่ถูกต้อง รายการหายไป หรือสถานะ HTTP ล้มเหลว) อย่า throw new Error(...) แต่ให้แสดงผลเพย์โหลดข้อผิดพลาดที่มีโครงสร้างผ่านค่าที่แสดงผลปกติของเครื่องมือแทน เพื่อให้ AI Agent ได้รับรายละเอียดการวินิจฉัยและสามารถแก้ไขด้วยตนเองหรือลองอีกครั้งได้ ดังนี้
execute({ itemName }) {
const item = menuItems.find((entry) => entry.name.toLowerCase() === itemName.toLowerCase());
if (!item) {
// Return the error as a value instead of throwing, so the agent receives the message:
return {
error: `Menu item "${itemName}" not found.`,
availableItems: menuItems.map((entry) => entry.name),
};
}
return item;
}
ส่งอีกครั้งเมื่อยกเลิกการดำเนินการแล้วเท่านั้น (signal.aborted คือ true)
กำลังยกเลิกการดำเนินการที่อยู่ระหว่างดำเนินการ
การยกเลิกเริ่มต้นโดยผู้ใช้หรือตัวแทน บังคับ: เครื่องมือใดๆ ที่ส่งคำขอเครือข่ายหรืองานแบบไม่พร้อมกันอื่นๆ ที่ใช้เวลานานต้องเป็นไปตาม signal มิฉะนั้นการดำเนินการที่ยกเลิกจะยังคงใช้ทรัพยากรต่อไปและอาจเขียนข้อมูลที่ล้าสมัยลงใน UI หลังจากที่ Agent ดำเนินการต่อ
- API ที่ยอมรับสัญญาณ (ผู้อ่าน
fetch(),addEventListener(),ReadableStream): ส่งsignalผ่านโดยตรง - API ที่ไม่ (
setTimeout,setInterval, ลูปการโพล, ไปป์ไลน์ที่ใช้awaitมาก): เรียกsignal.throwIfAborted()ระหว่างขั้นตอน และ/หรือปฏิเสธในsignal.addEventListener('abort', ...)ตัวจับเวลาไม่ยอมรับสัญญาณ ดังนั้นคุณต้องล้างตัวจับเวลาด้วยตนเองใน Listener การยกเลิก
await document.modelContext.registerTool({
name: "fetch_tool",
description: "Fetch the text content of a URL and show it on the page.",
inputSchema: {
type: "object",
properties: {
url: { type: "string", description: "The URL to fetch" },
priority: {
type: "string",
enum: ["high", "low", "auto"],
description: "Relative network priority for the request",
},
},
required: ["url"],
},
execute: async ({ url, priority }, { signal }) => {
const output = document.querySelector("pre");
output.textContent = "Loading…";
try {
// Passing `signal` aborts the network request the moment execution is cancelled.
const response = await fetch(url, { priority, signal });
if (!response.ok) {
output.textContent = "";
return { error: `Request failed with status ${response.status}` };
}
const text = await response.text();
output.textContent = text;
return text;
} catch (err) {
// Roll back the UI state this execution set, so a cancelled run leaves no trace.
output.textContent = "";
if (signal.aborted) {
// The execution was cancelled: re-throw instead of returning an error value.
throw err;
}
// Return other errors as a value instead of throwing, so the agent receives the message.
return { error: err instanceof Error ? err.message : String(err) };
}
},
annotations: { readOnlyHint: true }
});
เครื่องมือการแจ้งวิดีโอที่ไม่เหมาะสมที่มีผลตามมา
ตั้งแต่ Chrome 154 เป็นต้นไป annotations จะรองรับ consequentialHint ตั้งค่าเป็น true สำหรับเครื่องมือที่ดำเนินการที่มีความเสี่ยงสูง ย้อนกลับไม่ได้ หรือดำเนินการในชีวิตจริง เช่น การจองการเดินทาง การโอนเงิน การส่งข้อความ หรือการลบข้อมูล ซึ่งจะส่งสัญญาณให้ Agent ขอการยืนยันจากผู้ใช้อย่างชัดเจนก่อนดำเนินการ
await document.modelContext.registerTool({
name: 'book_flight',
description: 'Book a flight for the user with confirmed flight details.',
inputSchema: {
type: 'object',
properties: {
flightId: { type: 'string', description: 'ID of the flight to book' },
passengers: { type: 'number', description: 'Number of tickets to purchase' },
},
required: ['flightId', 'passengers'],
},
execute: async ({ flightId, passengers }, { signal }) => {
// Forward `signal` to the transaction API to honor cancellation:
return await bookFlightReservation({ flightId, passengers }, { signal });
},
annotations: {
readOnlyHint: false, // This tool mutates state (it makes a booking).
consequentialHint: true, // Spends money and is not trivially reversible.
untrustedContentHint: false, // Output is first-party data, not third-party content.
}
});
บังคับ: ถือว่า consequentialHint เป็นคำแนะนำ ไม่ใช่กลไกการบังคับใช้ โดยจะไม่บล็อกการดำเนินการด้วยตัวเอง และเบราว์เซอร์ที่เก่ากว่าคำแนะนำจะไม่แสดงข้อความแจ้งเลย คงการยืนยันในแอปที่การดำเนินการนั้นรับประกันไว้แล้ว
เครื่องมือแก้ไขข้อบกพร่องในการแจ้งว่าไม่เหมาะสม
ตั้งแต่ Chrome 156 เป็นต้นไป annotations จะรองรับ debugging ตั้งค่า annotations.debugging เป็น true สำหรับเครื่องมือที่สร้างขึ้นเพื่อการแก้ไขข้อบกพร่องและเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ ไม่ใช่งานของผู้ใช้ปลายทาง ตัวอย่าง: การดัมพ์สถานะภายในของแอป การเปิด/ปิดแฟล็กฟีเจอร์ หรือการสร้างข้อมูลทดสอบ ซึ่งจะช่วยให้ Agent แยกแยะเครื่องมือสำหรับนักพัฒนาแอปเท่านั้นออกจากเครื่องมือที่ออกแบบมาเพื่อดำเนินการแทนผู้ใช้ได้ โดยค่าเริ่มต้นจะเป็น false เอเจนต์ในหน้าเว็บและโปรแกรมทดสอบอัตโนมัติจะอ่านค่านี้ได้จาก RegisteredTool.annotations.debugging ผ่าน getTools()
await document.modelContext.registerTool({
name: "dump_app_state",
description: "Returns a snapshot of the internal application store for debugging.",
execute() {
return appStore.getState();
},
annotations: {
readOnlyHint: true, // Only reads state.
debugging: true, // Developer tooling, not an end-user action.
}
});
เอเจนต์และการทดสอบในหน้าเว็บ (getTools และ executeTool)
หน้าเว็บไม่จำเป็นต้องมี getTools() หรือ executeTool() เพื่อแสดงเครื่องมือต่อ AI Agent เพียงเรียกใช้ document.modelContext.registerTool() ก็เพียงพอแล้วสำหรับเอเจนต์เบราว์เซอร์, ส่วนขยายเบราว์เซอร์, เครื่องมือสำหรับนักพัฒนาเว็บ และผู้ช่วยระดับระบบในการค้นพบและเรียกใช้เครื่องมือของคุณนอกแบนด์
เมธอด getTools() และ executeTool() มีไว้สำหรับผู้บริโภคที่ทำงานภายในสภาพแวดล้อม JavaScript โดยเฉพาะ
- เอเจนต์ JavaScript ในหน้าเว็บ: ผู้ช่วย AI, วิดเจ็ต Copilot หรืออินเทอร์เฟซแชทที่ฝังอยู่ในหน้าโดยตรง (หรือทำงานภายใน
<iframe>) ซึ่งจำเป็นต้องค้นหาเครื่องมือที่หน้าเว็บโดยรอบหรือเฟรมที่เข้าถึงได้ในโครงสร้างเอกสารมีให้ และเรียกใช้เครื่องมือเหล่านั้นในนามของผู้ใช้ - การทดสอบและการแก้ไขข้อบกพร่องอัตโนมัติ: ชุดโปรแกรมทดสอบ (เช่น Playwright, Vitest หรือการทดสอบหน่วยในเบราว์เซอร์) ที่ตรวจสอบข้อมูลเมตาของเครื่องมือที่ลงทะเบียนและจำลองการเรียกใช้เครื่องมือของ Agent โดยไม่ต้องใช้ชุดทดสอบ LLM ภายนอกแบบเรียลไทม์
กำลังค้นหาเครื่องมือที่พร้อมใช้งานด้วย getTools()
ตัวแทนในหน้าเว็บจะเรียกใช้ document.modelContext.getTools() เพื่อดึงอาร์เรย์ของออบเจ็กต์ RegisteredTool จากเอกสารปัจจุบันและเฟรมที่เข้าถึงได้ในโครงสร้างเอกสาร
ตั้งแต่ Chrome 155 เป็นต้นไป ระบบจะแสดงผล RegisteredTool.inputSchema เป็นออบเจ็กต์ JavaScript โดยตรง (สำเนาแบบลึกของสคีมาที่ระบุไว้เมื่อลงทะเบียน) การเปลี่ยนแปลงออบเจ็กต์นี้จะไม่เปลี่ยนสคีมาจริงของเครื่องมือที่ลงทะเบียนไว้
// Example: An in-page AI assistant discovering tools available on the page:
const tools = await document.modelContext.getTools();
// In-page agents can listen for tools being registered or unregistered dynamically:
document.modelContext.addEventListener("toolchange", async () => {
const updatedTools = await document.modelContext.getTools();
console.log(`Active tools updated: ${updatedTools.map((t) => t.name).join(", ")}`);
});
หากต้องการค้นหาเครื่องมือที่ลงทะเบียนไว้ภายใน iframe ที่เป็นองค์ประกอบสืบทอดแบบข้ามต้นทาง (ซึ่งต้องให้สิทธิ์เข้าถึงอย่างชัดแจ้งผ่าน exposedTo ระหว่างการจดทะเบียน) ให้ส่ง fromOrigins ในพจนานุกรมตัวเลือก ดังนี้
// Query tools registered in the embedded cart frame that exposed them to this checkout origin:
const cartTools = await document.modelContext.getTools({
fromOrigins: ["https://cart.example.com"],
});
การเรียกใช้เครื่องมือด้วย executeTool()
เอเจนต์ในหน้าเว็บและสคริปต์ทดสอบจะเรียกใช้ document.modelContext.executeTool(tool, inputObject, options) เพื่อเรียกใช้เครื่องมือที่ลงทะเบียนไว้ เครื่องมือจะทำงานในเอกสารที่ลงทะเบียนไว้ และ Promise จะแสดงผลลัพธ์เป็นสตริงที่ได้จาก Callback execute ของเครื่องมือ
ตั้งแต่ Chrome 155 เป็นต้นมา executeTool() จะยอมรับออบเจ็กต์ JavaScript ธรรมดาโดยตรงสำหรับ inputObject ซึ่งตรงกับรูปแบบอินพุตที่ Callback execute ของเครื่องมือได้รับ
// 1. Discover the tool (typically done during agent initialization or test setup):
const tools = await document.modelContext.getTools();
const areaTool = tools.find((t) => t.name === "calculate_area");
if (areaTool) {
const controller = new AbortController();
// Example input payload matching the tool's inputSchema:
const inputObject = { width: 10, height: 20 };
const options = { signal: controller.signal };
// 2. Pass input arguments as a JavaScript object, with a JSON string fallback for Chrome <155:
let resultString;
try {
resultString = await document.modelContext.executeTool(areaTool, inputObject, options);
} catch (err) {
if (err?.message?.startsWith("Failed to parse input")) {
resultString = await document.modelContext.executeTool(
areaTool,
JSON.stringify(inputObject),
options
);
} else {
// Re-throw real tool execution or cancellation errors:
throw err;
}
}
console.log("Execution output string:", resultString);
}
ระบบจะปฏิเสธ Promise ที่แสดงผลในกรณีต่อไปนี้
inputObjectไม่ใช่ออบเจ็กต์หรือทำให้เป็นอนุกรมเป็นสตริง JSON ไม่ได้ (เช่น การอ้างอิงแบบวงกลมหรือค่าBigInt) โปรดทราบว่าค่าที่ละเว้นโดยการแปลงเป็นอนุกรม JSON (เช่น ฟังก์ชันและundefined) จะถูกละเว้นจากออบเจ็กต์ที่เครื่องมือได้รับ แทนที่จะทำให้เกิดการปฏิเสธ- การดำเนินการถูกยกเลิกผ่าน
options.signal - เครื่องมือถูกยกเลิกการลงทะเบียนก่อนการดำเนินการหรือพบข้อผิดพลาดขณะรันไทม์ที่ไม่ได้จัดการ
รูปแบบโรงงานเครื่องมือ
หากต้องการส่งบริบท (เช่น Store หรืออินสแตนซ์แอปพลิเคชัน) ไปยังเครื่องมือ ให้ใช้ฟังก์ชัน Factory
export function createInventoryTool(inventoryManager) {
return {
name: "get_inventory",
description: "Lists items in the inventory.",
inputSchema: { type: "object", properties: {} },
execute() {
return inventoryManager.getItems();
},
annotations: { readOnlyHint: true }
};
}
ประเภท TypeScript
ในโปรเจ็กต์ TypeScript อย่าเขียนการประกาศสำหรับ document.modelContext ด้วยตนเอง ติดตั้งแพ็กเกจ webmcp-types อย่างเป็นทางการ (npm install --save-dev webmcp-types) และเพิ่มลงใน tsconfig.json เนื่องจากระบบไม่ได้เลือกโดยอัตโนมัติ
{
"compilerOptions": {
"types": ["webmcp-types"]
}
}
document.modelContextมีประเภทเป็นไม่บังคับ ดังนั้นให้ป้องกันด้วยif (document.modelContext)ก่อนใช้งาน- เมื่อใช้
inputSchemaในบรรทัด ระบบจะอนุมานประเภทอินพุตexecuteจากสคีมา - ประเภทที่มีชื่อ เช่น
WebMCP.ModelContextToolเป็นแบบส่วนกลาง (ไม่จำเป็นต้องนำเข้า) ซึ่งมีประโยชน์สำหรับการพิมพ์โรงงานเครื่องมือ
การรองรับเฟรมเวิร์ก
บังคับ: หากแอปใช้ React, Angular หรือ Vue ให้ลงทะเบียนเครื่องมือผ่านการผสานรวม WebMCP อย่างเป็นทางการของเฟรมเวิร์กนั้นๆ ตามที่ระบุไว้ด้านล่าง อย่าเรียก document.modelContext.registerTool() จากคอมโพเนนต์หรือเขียน Wrapper วงจรของคุณเอง การผสานรวมแต่ละรายการจะจัดการการตรวจหาฟีเจอร์ การล้าง AbortSignal และเครื่องมือกำหนดขอบเขตให้กับคอมโพเนนต์หรือวงจรของ Injector อยู่แล้ว API เหล่านี้เป็นเวอร์ชันทดลอง ดังนั้นก่อนเขียนโค้ด ให้ค้นหาซิกเนเจอร์ปัจจุบันในประเภทหรือเอกสารของแพ็กเกจ
| เฟรมเวิร์ก | แพ็กเกจ | API | เอกสาร |
|---|---|---|---|
| React 18+ | use-webmcp-tool |
useWebMCP(options): การเรียกใช้ 1 ครั้งต่อเครื่องมือ |
npmjs.com/package/use-webmcp-tool |
| Angular | @angular/core, @angular/forms/signals |
provideExperimentalWebMcpTools([...]) (ผู้ให้บริการแอปหรือเส้นทาง), declareExperimentalWebMcpTool(...) (บริการภายใน), provideExperimentalWebMcpForms() + ตัวเลือก experimentalWebMcpTool ในแบบฟอร์มสัญญาณ |
angular.dev/ai/webmcp |
| Vue | @vueuse/core |
useWebMCP(options) Composable |
vueuse.org/core/usewebmcp |
กฎทั้งหมดในคู่มือนี้จะยังคงมีผลเมื่อคุณใช้การผสานรวมเหล่านี้
- คงรูปแบบคำจำกัดความของเครื่องมือไว้เหมือนเดิม ได้แก่
name,description,inputSchema,execute(input, { signal })และannotations - ปฏิบัติตามกฎสำหรับคำอธิบายและคำอธิบายประกอบ
- ตรวจสอบอินพุตและใช้ค่าเริ่มต้นภายใน
execute - ส่ง
signalไปยังงานที่ใช้เวลานาน - หากต้องการเสนอเครื่องมือเป็นบางครั้ง ให้ส่ง
enabled(React, Vue) อย่ารวมฮุกหรือการเรียก Composable ไว้ในเงื่อนไข - การผสานรวมอาจรวมผลลัพธ์และข้อผิดพลาด (เช่น เป็น
{ content, isError }) โปรดตรวจสอบเอกสารของการผสานรวมก่อนที่จะพึ่งพาวิธีที่ข้อผิดพลาดไปถึง Agent
หมายเหตุเกี่ยวกับ API
- annotations: (ไม่บังคับ) พจนานุกรมสำหรับข้อมูลเมตาของเครื่องมือ
- readOnlyHint: (ไม่บังคับ) ตั้งค่าเป็น
trueหากเครื่องมือไม่แก้ไขสถานะใดๆ และอ่านข้อมูลเท่านั้น ซึ่งจะช่วยให้ Agent ตัดสินใจได้ว่าเมื่อใดที่เรียกใช้เครื่องมือได้อย่างปลอดภัย - consequentialHint: (ไม่บังคับ, Chrome 154 ขึ้นไป) ตั้งค่าเป็น
trueสำหรับการดำเนินการที่มีความเสี่ยงสูง ย้อนกลับไม่ได้ หรือการดำเนินการในชีวิตจริง เพื่อให้ Agent ขอการยืนยันจากผู้ใช้ก่อน - untrustedContentHint: (ไม่บังคับ) ตั้งค่าเป็น
trueเมื่อเครื่องมือแสดงผลเนื้อหาที่เว็บไซต์ของคุณไม่ได้ควบคุม เช่น ข้อความที่ผู้ใช้สร้างขึ้นหรือการตอบกลับจาก API ของบุคคลที่สาม - debugging: (ไม่บังคับ, Chrome 156 ขึ้นไป) ตั้งค่าเป็น
trueเมื่อเครื่องมือมีไว้สำหรับการแก้ไขข้อบกพร่องและเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ ไม่ใช่งานของผู้ใช้ปลายทาง ค่าเริ่มต้นคือfalse
- readOnlyHint: (ไม่บังคับ) ตั้งค่าเป็น
- ตัวเลือกการลงทะเบียน
- signal: (ไม่บังคับ)
AbortSignalที่ใช้เพื่อยกเลิกการลงทะเบียนเครื่องมือเมื่อไม่จำเป็นต้องใช้แล้ว - exposedTo: (ไม่บังคับ) อาร์เรย์ของสตริงต้นทางที่ปลอดภัยซึ่งควบคุมว่าเอกสารใดในแผนผังเอกสารที่ได้รับอนุญาตให้ค้นพบและเรียกใช้เครื่องมือข้ามขอบเขตเฟรม
- signal: (ไม่บังคับ)
- ตัวเลือกการค้นพบเครื่องมือ (
ModelContextGetToolOptions)- fromOrigins: (ไม่บังคับ) อาร์เรย์ของสตริงต้นทางที่ปลอดภัยเพื่อค้นหาในเฟรมที่เข้าถึงได้ การเรียก
getTools()โดยไม่มีfromOriginsจะค้นหาเฉพาะเอกสารจากต้นทางเดียวกัน
- fromOrigins: (ไม่บังคับ) อาร์เรย์ของสตริงต้นทางที่ปลอดภัยเพื่อค้นหาในเฟรมที่เข้าถึงได้ การเรียก
- รูปแบบการแสดงผล: ฟังก์ชัน
executeสามารถแสดงผลค่าที่แปลงเป็น JSON ได้ (ออบเจ็กต์, อาร์เรย์, สตริง, ตัวเลข, บูลีน) ระบบจะไม่ส่งต่อข้อความของข้อยกเว้นที่ส่งมาจากexecuteไปยัง Agent ดังนั้นให้แสดงผลข้อผิดพลาดที่ดำเนินการได้เป็นเพย์โหลดข้อผิดพลาดที่มีโครงสร้าง (เช่น{ error: "..." }) ผ่านค่าที่แสดงผลของเครื่องมือเพื่อให้ Agent อ่านและดำเนินการกับข้อผิดพลาดเหล่านั้นได้ - บริบทที่ปลอดภัย: WebMCP ต้องใช้ HTTPS ต้นทางทั้งหมดใน
exposedToและfromOriginsต้องเชื่อถือได้ด้วย - เลิกใช้งาน/นำออก: ระบบไม่รองรับ
navigator.modelContext(เลิกใช้งานใน Chromium 150),unregisterTool(),provideContext()และclearContext()อีกต่อไป
กลยุทธ์สำรอง
ควรใช้ WebMCP Imperative API ร่วมกับการตรวจหาฟีเจอร์เพื่อให้มั่นใจว่าเข้ากันได้กับเบราว์เซอร์ที่ยังไม่รองรับ WebMCP
if ('modelContext' in document) {
// Register tools
}