एजेंटिक JavaScript टूल

वेब की सुविधाएं: document.modelContext

इंपेरेटिव एपीआई, JavaScript टूल को प्रोग्राम के हिसाब से तय करने के लिए, document.modelContext.registerTool() का इस्तेमाल करता है. यह एक पेज के ऐप्लिकेशन (एसपीए) के लिए सबसे सही है. इनमें मौजूदा रूट या उपयोगकर्ता की स्थिति के आधार पर, टूल जोड़ने या हटाने की ज़रूरत होती है.

WebMCP, प्रोड्यूसर/कंज़्यूमर आर्किटेक्चर पर काम करता है:

  • वेब पेज, टूल प्रोड्यूसर होते हैं: document.modelContext.registerTool() का इस्तेमाल करके, टूल तय किए जाते हैं और रजिस्टर किए जाते हैं. किसी वेब पेज को लागू करने के लिए, बस इतना ही करना ज़रूरी है. एजेंट को टूल दिखाने के लिए, आपको पेज पर getTools() या executeTool() को कॉल करने की ज़रूरत नहीं है.
  • ब्राउज़र और एक्सटेंशन एजेंट, मुख्य उपभोक्ता होते हैं: ब्राउज़र से या उसके ज़रिए उपलब्ध कराए गए एजेंट, रजिस्टर किए गए टूल को आउट-ऑफ़-बैंड खोजते हैं और उन्हें चालू करते हैं. इसके लिए, वे प्लैटफ़ॉर्म के इंटरनल मैकेनिज़्म का इस्तेमाल करते हैं. इन एजेंट में, ब्राउज़र का पहले से मौजूद एजेंट, ब्राउज़र एक्सटेंशन, DevTools, और सिस्टम-लेवल असिस्टेंट शामिल हैं.
  • इन-पेज एजेंट और टेस्ट हार्नेस: getTools() और executeTool() खास तौर पर, इन-पेज JavaScript असिस्टेंट (जैसे, एम्बेड किया गया चैट विजेट या <iframe>) और ऑटोमेटेड टेस्ट सुइट के लिए मौजूद हैं. इन्हें सीधे पेज के कॉन्टेक्स्ट में टूल खोजने और उन्हें शुरू करने की ज़रूरत होती है.

रजिस्ट्रेशन और लाइफ़साइकल

टूल को रजिस्टर करने के लिए, टूल की डेफ़िनिशन वाला ऑब्जेक्ट और विकल्प वाला ऑब्जेक्ट (ModelContextRegisterToolOptions) पास किया जाता है. विकल्प वाला ऑब्जेक्ट देना ज़रूरी नहीं है. इसमें दो मेंबर होते हैं, जिन्हें देना ज़रूरी नहीं है:

  • 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();

रजिस्ट्रेशन सिग्नल को रद्द करने से, सिर्फ़ टूल का रजिस्ट्रेशन रद्द होता है. इससे, पहले से चल रहे एक्ज़ीक्यूशन रद्द नहीं होते. लंबे समय तक चलने वाले काम को शुरू करने वाले टूल को, हर बार एक्ज़ीक्यूशन के लिए दिए गए सिग्नल का भी पालन करना चाहिए. इसके बारे में नीचे बताया गया है. ऐसा न करने पर, रजिस्ट्रेशन रद्द करने से अनुरोध अधूरे रह जाएंगे और यूज़र इंटरफ़ेस (यूआई) के अपडेट पुराने हो जाएंगे.

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"],
});
  • दोनों पक्षों की सहमति से शामिल होना: क्रॉस-ऑरिजिन टूल डिस्कवरी के लिए, दोनों पक्षों की सहमति ज़रूरी है. टूल प्रोवाइडर फ़्रेम, exposedTo के ज़रिए उपभोक्ता के ऑरिजिन को अनुमति देता है. साथ ही, उपभोक्ता फ़्रेम को getTools({ fromOrigins: [...] }) के ज़रिए, प्रोवाइडर के ऑरिजिन का अनुरोध करना चाहिए. fromOrigins के बिना, getTools() सिर्फ़ एक जैसे ऑरिजिन वाले दस्तावेज़ों को क्वेरी करता है.
  • ऑरिजिन मैचिंग: रजिस्ट्रेशन के दस्तावेज़ के ऑरिजिन के पास हमेशा ऐक्सेस होता है. exposedTo में बताए गए ऑरिजिन को, document.modelContext.getTools({ fromOrigins: [...] }) के ज़रिए टूल को खोजने और document.modelContext.executeTool() के ज़रिए उसे लागू करने की अनुमति दी जाती है.
  • सुरक्षा से जुड़ी ज़रूरी शर्त: exposedTo में मौजूद हर ऑरिजिन, भरोसेमंद होना चाहिए. जैसे, एचटीटीपीएस या लोकलहोस्ट. अमान्य या असुरक्षित ऑरिजिन पास करने पर, registerTool() को SecurityError के साथ अस्वीकार कर दिया जाता है.
  • स्कोप: exposedTo, दस्तावेज़ ट्री में मौजूद फ़्रेम के बीच, इन-पेज क्रॉस-डॉक्यूमेंट डिस्कवरी को कंट्रोल करता है.

पैरामीटर तय करना

पैरामीटर (params) को inputSchema प्रॉपर्टी का इस्तेमाल करके तय किया जाता है. यह एक JSON स्कीमा ऑब्जेक्ट होना चाहिए, जो उस स्ट्रक्चर्ड डेटा के बारे में बताता हो जिसकी टूल को उम्मीद है.

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 }
});

लिखने के लिए टूल और पैरामीटर की जानकारी

एजेंट को पहले ही पूरा inputSchema मिल जाता है. इसलिए, description को सिर्फ़ यह बताना होता है कि टूल क्या करता है और इसका इस्तेमाल कब करना है. भूलकर भी पैरामीटर के नाम, टाइप, enum वैल्यू, डिफ़ॉल्ट वैल्यू या सीमाओं को न दोहराएं. इसके बजाय, उन्हें स्कीमा (enum, default, minimum/maximum) में डिक्लेयर करें. पैरामीटर के ब्यौरे के लिए भी यही नियम लागू होता है: वैल्यू का मतलब बताएं, न कि उसका टाइप या अनुमति वाली वैल्यू.

ब्राउज़र, inputSchema के लिए आर्ग्युमेंट की पुष्टि नहीं करता है या default वैल्यू लागू नहीं करता है. इसलिए, 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 कॉलबैक को हमेशा दो आर्ग्युमेंट मिलते हैं: इनपुट ऑब्जेक्ट और विकल्पों वाला ऑब्जेक्ट, जिसमें AbortSignal — execute(inputObject, { signal }) होता है.

async execute का इस्तेमाल कब करना चाहिए

async का इस्तेमाल तब करें, जब टूल में ऐसे ऑपरेशन शामिल हों जो प्रॉमिस रिटर्न करते हैं या जिन्हें पूरा होने में समय लगता है:

  • नेटवर्क कॉल: एपीआई से डेटा फ़ेच करना.
  • एसिंक्रोनस स्टोरेज: 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 कोई गड़बड़ी दिखाता है (या अस्वीकार किया गया प्रॉमिस दिखाता है), तो एजेंट को सिर्फ़ टास्क पूरा न होने की सामान्य गड़बड़ी मिलती है. गड़बड़ी का मैसेज, एजेंट को नहीं भेजा जाता. अगर आपके टूल को ऐसी गड़बड़ी मिलती है जिसे ठीक किया जा सकता है या जिससे वापस पाया जा सकता है (जैसे, अमान्य इनपुट, मौजूद न होने वाले आइटम या एचटीटीपी स्टेटस का काम न करना), तो throw new Error(...). इसके बजाय, टूल की सामान्य रिटर्न वैल्यू के ज़रिए स्ट्रक्चर्ड गड़बड़ी का पेलोड दिखाएं, ताकि एआई एजेंट को गड़बड़ी की जानकारी मिल सके और वह खुद को ठीक कर सके या फिर से कोशिश कर सके:

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 का पालन करना ज़रूरी है. ऐसा न करने पर, रद्द किए गए टास्क संसाधनों का इस्तेमाल करते रहते हैं. साथ ही, एजेंट के आगे बढ़ने के बाद, यूज़र इंटरफ़ेस (यूआई) में पुराना डेटा सेव कर सकते हैं.

  • सिग्नल स्वीकार करने वाले एपीआई (fetch(), addEventListener(), ReadableStream रीडर): signal को सीधे पास करें.
  • ऐसे एपीआई जो (setTimeout, setInterval, पोलिंग लूप, await-हैवी पाइपलाइन): चरणों के बीच signal.throwIfAborted() को कॉल करते हैं और/या signal.addEventListener('abort', ...) पर अस्वीकार करते हैं. टाइमर कोई सिग्नल स्वीकार नहीं करते. इसलिए, आपको उन्हें अबॉर्ट लिसनर में खुद ही हटाना होगा.
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 पर सेट करें. ऐसा उन टूल के लिए करें जो अहम, वापस न लिए जा सकने वाले या असल दुनिया में होने वाली कार्रवाइयां करते हैं. जैसे, यात्रा की बुकिंग करना, पैसे ट्रांसफ़र करना, मैसेज भेजना या डेटा मिटाना. यह एजेंट को निर्देश देता है कि वह कार्रवाई करने से पहले, उपयोगकर्ता से साफ़ तौर पर पुष्टि करने के लिए कहे.

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 पर सेट करें. उदाहरण: ऐप्लिकेशन की इंटरनल स्थिति को डंप करना, फ़ीचर फ़्लैग को टॉगल करना या टेस्ट डेटा को सीड करना. इससे एजेंट, सिर्फ़ डेवलपर के लिए उपलब्ध टूल और उपयोगकर्ता के लिए उपलब्ध टूल के बीच अंतर कर पाते हैं. यह डिफ़ॉल्ट रूप से false पर सेट होता है. इन-पेज एजेंट और टेस्ट हार्नेस, getTools() के ज़रिए RegisteredTool.annotations.debugging से इसे पढ़ सकते हैं.

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() की ज़रूरत नहीं होती. ब्राउज़र एजेंट, ब्राउज़र एक्सटेंशन, DevTools, और सिस्टम-लेवल असिस्टेंट को आपके टूल खोजने और उन्हें आउट-ऑफ़-बैंड चलाने के लिए, सिर्फ़ document.modelContext.registerTool() को कॉल करना ज़रूरी है.

getTools() और executeTool() तरीके, खास तौर पर JavaScript एनवायरमेंट में काम करने वाले उपभोक्ताओं के लिए मौजूद हैं:

  1. पेज में मौजूद JavaScript एजेंट: पेज में सीधे तौर पर एम्बेड किया गया या <iframe> में चल रहा कोई एआई असिस्टेंट, कोपायलट विजेट या चैट इंटरफ़ेस. इसे यह पता लगाना होता है कि आस-पास के पेज या दस्तावेज़ ट्री में ऐक्सेस किए जा सकने वाले फ़्रेम में कौनसे टूल उपलब्ध हैं. साथ ही, उपयोगकर्ता की ओर से उन्हें शुरू करना होता है.
  2. ऑटोमेटेड टेस्टिंग और डीबगिंग: टेस्ट सुइट (जैसे, Playwright, Vitest या इन-ब्राउज़र यूनिट टेस्ट), जो रजिस्टर किए गए टूल के मेटाडेटा की जांच करते हैं और एजेंट टूल के कॉल को सिम्युलेट करते हैं. इसके लिए, लाइव बाहरी एलएलएम हार्नेस की ज़रूरत नहीं होती.

getTools() के साथ उपलब्ध टूल एक्सप्लोर करना

इन-पेज एजेंट, मौजूदा दस्तावेज़ और दस्तावेज़ ट्री में मौजूद किसी भी ऐक्सेस किए जा सकने वाले फ़्रेम से, RegisteredTool ऑब्जेक्ट का कलेक्शन पाने के लिए, document.modelContext.getTools() को कॉल करते हैं.

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 में रजिस्टर किए गए टूल खोजने के लिए, विकल्पों की डिक्शनरी में fromOrigins पास करें. इन iframe को रजिस्ट्रेशन के दौरान, exposedTo के ज़रिए साफ़ तौर पर ऐक्सेस देना ज़रूरी है:

// 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) को कॉल करती हैं. यह टूल उस दस्तावेज़ पर चलता है जहां इसे रजिस्टर किया गया था. साथ ही, टूल के execute कॉलबैक से मिले स्ट्रिंगिफ़ाइड नतीजे के लिए प्रॉमिस रिज़ॉल्व होता है.

Chrome 155 से, executeTool() सीधे तौर पर inputObject के लिए एक सामान्य JavaScript ऑब्जेक्ट स्वीकार करता है. यह आपके टूल के 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);
}

वापस किया गया प्रॉमिस तब अस्वीकार कर दिया जाता है, जब:

  • inputObject कोई ऑब्जेक्ट नहीं है या इसे JSON स्ट्रिंग में सीरियलाइज़ नहीं किया जा सकता. जैसे, सर्कुलर रेफ़रंस या BigInt वैल्यू. ध्यान दें कि JSON सीरियलाइज़ेशन से हटाई गई वैल्यू (जैसे, फ़ंक्शन और undefined), टूल को मिले ऑब्जेक्ट से हटा दी जाएंगी. हालांकि, इन्हें अस्वीकार नहीं किया जाएगा.
  • options.signal की मदद से, प्रोग्राम चलाने की प्रोसेस को रद्द कर दिया गया है.
  • टूल को चलाने से पहले ही उसका रजिस्ट्रेशन रद्द कर दिया गया था या रनटाइम के दौरान कोई ऐसी गड़बड़ी हुई जिसे ठीक नहीं किया जा सका.

टूल फ़ैक्ट्री पैटर्न

अपने टूल को कॉन्टेक्स्ट (जैसे, स्टोर या ऐप्लिकेशन इंस्टेंस) पास करने के लिए, फ़ैक्ट्री फ़ंक्शन का इस्तेमाल करें.

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 इंटिग्रेशन के ज़रिए टूल रजिस्टर करें. इसकी सूची यहां दी गई है. DO NOT call document.modelContext.registerTool() from components or write your own lifecycle wrapper. हर इंटिग्रेशन, कॉम्पोनेंट या इंजेक्टर लाइफ़साइकल के लिए, सुविधा की पहचान, AbortSignal क्लीनअप, और स्कोपिंग टूल को पहले से ही मैनेज करता है. ये एपीआई एक्सपेरिमेंट के तौर पर उपलब्ध हैं. इसलिए, कोड लिखने से पहले, पैकेज के टाइप या दस्तावेज़ों में मौजूदा सिग्नेचर देखें.

फ़्रेमवर्क पैकेज एपीआई Docs
React 18+ use-webmcp-tool useWebMCP(options): हर टूल के लिए एक कॉल 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) कंपोज़ेबल vueuse.org/core/usewebmcp

इन इंटिग्रेशन का इस्तेमाल करने पर, इस गाइड में दिए गए सभी नियम अब भी लागू होते हैं:

  • टूल की परिभाषा का शेप एक जैसा रखें: name, description, inputSchema, execute(input, { signal }), और annotations.
  • ब्यौरों और एनोटेशन के लिए बने नियमों का पालन करें.
  • इनपुट की पुष्टि करें और execute में डिफ़ॉल्ट वैल्यू लागू करें.
  • लंबे समय तक चलने वाले काम के लिए, signal को पास करें.
  • किसी टूल को सिर्फ़ कुछ समय के लिए उपलब्ध कराने के लिए, enabled (React, Vue) पास करें. हुक या कंपोज़ेबल कॉल को किसी शर्त में रैप न करें.
  • इंटिग्रेशन, नतीजों और गड़बड़ियों को रैप कर सकते हैं. उदाहरण के लिए, { content, isError } के तौर पर. एजेंट तक गड़बड़ियां कैसे पहुंचती हैं, इस पर भरोसा करने से पहले इंटिग्रेशन के दस्तावेज़ देखें.

एआई नोट्स

  • annotations: (ज़रूरी नहीं) टूल के मेटाडेटा के लिए डिक्शनरी.
    • readOnlyHint: (ज़रूरी नहीं) अगर टूल किसी भी स्थिति में बदलाव नहीं करता है और सिर्फ़ डेटा को पढ़ता है, तो इसे true पर सेट करें. इससे एजेंट को यह तय करने में मदद मिलती है कि टूल को कब कॉल करना सुरक्षित है.
    • consequentialHint: (ज़रूरी नहीं, Chrome 154 और इसके बाद के वर्शन के लिए) इसे true पर सेट करें. इससे एजेंट, अहम, वापस न ली जा सकने वाली या असल दुनिया में होने वाली कार्रवाइयों के लिए, पहले उपयोगकर्ता से पुष्टि करने का अनुरोध करेंगे.
    • untrustedContentHint: (ज़रूरी नहीं) इसे true पर सेट करें. ऐसा तब करें, जब टूल ऐसा कॉन्टेंट दिखाता हो जो आपकी साइट के कंट्रोल में न हो. जैसे, उपयोगकर्ता का जनरेट किया गया टेक्स्ट या तीसरे पक्ष के एपीआई से मिली जानकारी.
    • debugging: (ज़रूरी नहीं, Chrome 156 और इसके बाद के वर्शन के लिए) अगर टूल का इस्तेमाल असली उपयोगकर्ता के टास्क के लिए नहीं, बल्कि डीबग करने और डेवलपर टूल के लिए किया जाना है, तो इसे true पर सेट करें. डिफ़ॉल्ट रूप से, यह false पर सेट होता है.
  • रजिस्ट्रेशन के विकल्प:
    • signal: (ज़रूरी नहीं) यह एक AbortSignal है. इसका इस्तेमाल, टूल की ज़रूरत न होने पर उसका रजिस्ट्रेशन रद्द करने के लिए किया जाता है.
    • exposedTo: (ज़रूरी नहीं) सुरक्षित ऑरिजिन स्ट्रिंग का कलेक्शन. इससे यह कंट्रोल किया जाता है कि दस्तावेज़ ट्री में मौजूद किन दस्तावेज़ों को फ़्रेम की सीमाओं के पार टूल को खोजने और उसे लागू करने की अनुमति है.
  • टूल खोजने के विकल्प (ModelContextGetToolOptions):
    • fromOrigins: (ज़रूरी नहीं) ऐक्सेस किए जा सकने वाले फ़्रेम में क्वेरी करने के लिए, सुरक्षित ऑरिजिन स्ट्रिंग की कलेक्शन. getTools() को fromOrigins के बिना कॉल करने पर, सिर्फ़ एक जैसे ऑरिजिन वाले दस्तावेज़ों के लिए क्वेरी की जाती है.
  • रिटर्न फ़ॉर्मैट: execute फ़ंक्शन, JSON-सीरियलाइज़ेबल वैल्यू (ऑब्जेक्ट, कलेक्शन, स्ट्रिंग, नंबर, बूलियन) दिखा सकता है. execute से मिले अपवाद का मैसेज, एजेंट को फ़ॉरवर्ड नहीं किया जाता. इसलिए, टूल की रिटर्न वैल्यू के ज़रिए, गड़बड़ियों को स्ट्रक्चर्ड गड़बड़ी के पेलोड (जैसे, { error: "..." }) के तौर पर दिखाएं, ताकि एजेंट उन्हें पढ़ सके और उन पर कार्रवाई कर सके.
  • सुरक्षित कॉन्टेक्स्ट: WebMCP के लिए एचटीटीपीएस ज़रूरी है. exposedTo और fromOrigins में मौजूद सभी ऑरिजिन भी भरोसेमंद होने चाहिए.
  • अब इस्तेमाल नहीं किया जा सकता/हटा दिया गया है: navigator.modelContext (Chromium 150 में अब इस्तेमाल नहीं किया जा सकता), unregisterTool(), provideContext(), और clearContext() अब काम नहीं करते.

फ़ॉलबैक रणनीतियां

WebMCP Imperative API का इस्तेमाल, सुविधा की पहचान करने के साथ किया जाना चाहिए. इससे यह पक्का किया जा सकेगा कि यह उन ब्राउज़र के साथ काम करे जो फ़िलहाल WebMCP के साथ काम नहीं करते.

if ('modelContext' in document) {
  // Register tools
}