WebMCP Imperative API: A Beginner’s Guide to registerTool()
The JavaScript side of WebMCP gives developers full control over the tools agents can call. Here's how registerTool() works, with simple examples and safety tips.
In this article
- Why use the WebMCP imperative API?
- Before you start: the WebMCP imperative API name
- The parts of a WebMCP tool
- Step 1: Register a tool with the imperative API
- Step 2: Write a description agents understand
- Step 3: Add WebMCP imperative API annotations
- Step 4: Remove tools when they no longer apply
- Step 5: Limit who can see your tools
- Step 6: Handle errors gracefully
- A worked example: a small restaurant
- Step 7: Test the tool
- WebMCP imperative API or declarative API?
- WebMCP imperative API: FAQs
- Sources
WebMCP imperative API: the short answer
The WebMCP imperative API lets a web page register tools for AI agents with JavaScript, using document.modelContext.registerTool(). Each tool has a name, a description, an input schema and an execute function that runs your own page code. Optional hints mark tools as read-only or consequential, so agents and browsers can ask the person before acting. As of September 2026 it is experimental and used by Chrome’s trial and ChatGPT’s site tools.
The WebMCP imperative API is the main way developers expose a website’s actions to AI agents. Unlike the declarative approach, which works on plain HTML forms, it uses JavaScript. As a result, it gives you far more control over what a tool does, when it exists and what it returns.
This guide explains the API step by step for developers and curious site owners. It uses short, simple examples based on Chrome’s imperative API documentation, the WebMCP explainer and the draft spec, all checked in September 2026. Because WebMCP is still a draft, names and details can change. If you want the big picture first, read what is WebMCP.
Why use the WebMCP imperative API?
The declarative API is great for a single form. However, many useful actions don’t fit that shape. For example, adding a topping to a pizza, filtering a list of flights or reading the items in a basket all involve page logic rather than one form.
The WebMCP imperative API handles those cases instead. You write a small JavaScript function for each tool, and the browser offers it to supporting agents. In addition, it is currently the only approach ChatGPT’s site tools support. OpenAI’s developer notes say to “use JavaScript to register tools in the top-level page,” and that declarative HTML tools aren’t supported yet.
Before you start: the WebMCP imperative API name
If you read older tutorials, you may see navigator.modelContext. That was the name in early previews, as VentureBeat reported in February 2026. However, Chrome’s current docs, updated September 21, 2026, uses document.modelContext. The explainer on GitHub uses the same name. So use document.modelContext for new code, and check for it before calling it:
if (document.modelContext) {
// register tools here
}
That simple check also keeps your page working in browsers without WebMCP support.
The parts of a WebMCP tool
According to the draft spec and Chrome’s docs, a tool setup has these parts:
| Field | Required? | What it does |
|---|---|---|
name | Yes | A unique ID, such as add-todo |
title | No | A human-readable label |
description | Yes | Plain-language explanation of what the tool does |
inputSchema | No | A JSON Schema listing the inputs the tool needs |
annotations | No | Hints such as read-only or consequential |
execute | Yes | The function that does the work and returns a result |
The spec allows names of 1 to 128 characters, using letters, numbers, hyphens, underscores and dots. That said, Chrome’s security guidance suggests keeping names under 30 characters.
Step 1: Register a tool with the imperative API
Here is a short example, adapted from the WebMCP explainer. It lets an agent add an item to a to-do list:
await document.modelContext.registerTool({
name: "add-todo",
description: "Add a new item to the user's todo list",
inputSchema: {
type: "object",
properties: {
text: { type: "string", description: "The todo item text" }
},
required: ["text"]
},
async execute({ text }) {
await addTodoItem(text);
return `Added todo item: "${text}"`;
}
});
Notice that execute calls your existing function, addTodoItem. That is the point of the WebMCP imperative API. You reuse the code your page already has, and the change appears on screen as normal.
Step 2: Write a description agents understand
The description is what the AI reads to decide whether to use your tool. So, above all, it deserves care. Chrome’s best practices offer clear advice:
- Use precise verbs.
create-eventis better thanstart-event-creation-process. - Be positive. “This tool can create a calendar event” works better than “Don’t use this tool for weather.”
- Accept raw input. Let the tool handle dates and conversions, rather than asking the AI to do maths.
- Use words, not codes. Accept “Express” rather than a shipping ID such as 1.
Chrome’s security guidance also suggests limits: descriptions under 500 characters, parameter descriptions under 150 characters, and outputs under about 1,500 characters.
Step 3: Add WebMCP imperative API annotations
Next, annotations are optional hints about what a tool does. The draft spec and Chrome’s docs list four:
| Annotation | Use it when |
|---|---|
readOnlyHint | The tool only reads data and changes nothing |
consequentialHint | The tool has real-world effects, such as a booking or payment |
untrustedContentHint | The output includes user-generated or outside content |
debugging | The tool is meant for developers (Chrome 156 and later) |
Chrome says consequentialHint lets “the agent or browser” request user confirmation before running the tool. Similarly, untrustedContentHint warns the agent that the output needs extra caution, which helps against prompt injection. For example:
annotations: { readOnlyHint: true }
ChatGPT’s developer notes say it honours readOnlyHint. Its site tools panel even groups tools into read and write, such as “3 read, 7 write tools.”
Step 4: Remove tools when they no longer apply
Also, tools should match what the page can do right now. For example, a “checkout” tool makes little sense on an empty basket. The WebMCP imperative API handles this with an AbortController:
const controller = new AbortController();
await document.modelContext.registerTool(tool, { signal: controller.signal });
// later, when the tool no longer applies:
controller.abort();
Chrome notes that from Chrome 153, aborting unregisters the tool without breaking a call that is already running. Also, the explainer describes a toolchange event that tells agents when tools are added, removed or updated.
Step 5: Limit who can see your tools
By default, however, tools belong to your page. The explainer and Chrome’s docs describe an exposedTo option, which shares a tool only with specific trusted origins. Chrome’s advice is direct: “Only expose your tools to origins that you trust.”
In addition, Chrome’s rules apply at page level. WebMCP only works in origin-isolated documents. A “tools” permissions policy controls it, and cross-origin iframes need allow="tools". Note that ChatGPT’s site tools don’t discover tools inside iframes at all.
Step 6: Handle errors gracefully
Agents make mistakes. Similarly, networks fail. Chrome’s guidance says tools should “fail gracefully and enable recovery.” In practice, that means returning a clear message instead of throwing a vague error.
For example, if a date is missing, return “Please provide a check-in date in YYYY-MM-DD format.” If a rate limit is hit, say so and suggest the person finish the task by hand. Chrome also recommends strict validation in code but loose validation in the schema, so the tool can return a helpful message rather than a hard failure.
A worked example: a small restaurant
To make this concrete, imagine a small restaurant website with an online booking page. The page already has code that checks free tables and saves a booking. With the WebMCP imperative API, the owner could offer two tools.
The first tool, check-availability, would take a date, a time and a party size. It would only read data, so it gets readOnlyHint. As a result, an agent can call it freely to find a free slot.
The second tool, book-table, would take the same details plus a name. However, it creates a real booking, so it gets consequentialHint. That way, the agent or browser can ask the diner to confirm before anything is saved.
In practice, a diner might say, “Find me a table for four on Friday evening.” The agent checks availability, suggests 7.30pm, and then asks the diner to confirm the booking. Meanwhile, the page shows the booking form updating on screen, so the diner can see what is happening. Chrome’s Le Petit Bistro demo shows a similar idea using the declarative approach.
Step 7: Test the tool
Finally, once your tool is registered, test it in three ways:
- By hand. Enable
chrome://flags/#enable-webmcp-testingand install Google’s Model Context Tool Inspector extension. You can then see your tools and run them manually. - In code. Chrome’s evaluation guide suggests calling
document.modelContext.executeTool(...)directly to test a single tool. - With an agent. The inspector can run tools with Gemini. Also, test in ChatGPT’s desktop browser if your audience uses it.
Chrome’s Pizza Maker demo is a good reference for the WebMCP imperative API. Our WebMCP best practices guide covers testing and evaluation in more depth.
WebMCP imperative API or declarative API?
| Question | Imperative API | Declarative API |
|---|---|---|
| Needs JavaScript? | Yes | No, for the basics |
| Best for | Complex actions, app-like pages | Simple forms |
| ChatGPT site tools support | Yes | Not yet |
| Mozilla’s preference | Preferred | Less favoured |
| Control over results | Full | Limited |
For most real sites, the WebMCP imperative API is the safer bet today. However, the WebMCP declarative API is still worth adding to simple forms, since browsers without support simply ignore the attributes.
Key takeaways
- The WebMCP imperative API registers tools with document.modelContext.registerTool(); older articles may show navigator.modelContext.
- Each tool needs a name, a description and an execute function; an input schema and annotations are optional but helpful.
- Annotations such as readOnlyHint and consequentialHint help agents and browsers decide when to ask the person first.
- Use an AbortController to remove tools that no longer apply, and exposedTo to limit which origins can see them.
- It is the approach ChatGPT’s site tools support, but the whole standard remains experimental as of September 2026.
WebMCP imperative API: FAQs
Current Chrome documentation, updated September 2026, and the WebMCP explainer use document.modelContext. Early 2026 previews used navigator.modelContext, so older tutorials may be out of date.
Chrome’s docs shows tools returning text. Keep results short and clear; Chrome suggests keeping outputs under about 1,500 characters.
Mark the tool with consequentialHint. Chrome says this lets the agent or browser request user confirmation before execution.
Yes. ChatGPT’s site tools, in its desktop app’s built-in browser, use JavaScript-registered tools in the top-level page.
Sources
- Chrome for Developers, “Imperative API” (updated September 21, 2026)
- webmachinelearning, explainer on GitHub (accessed September 2026)
- W3C Web Machine Learning Community Group, Draft Community Group Report (September 26, 2026)
- Chrome for Developers, “Best practices” (updated May 18, 2026)
- Chrome for Developers, “Secure your tools” (updated September 1, 2026)
- Chrome for Developers, “Build tools” (updated August 26, 2026)
- Chrome for Developers, “Evaluate your tools” (updated May 28, 2026)
- Chrome for Developers, overview page (updated August 7, 2026)
- ChatGPT Learn, “Site tools” developer guide (accessed September 2026)
- VentureBeat, “Google Chrome ships WebMCP in early preview” (February 12, 2026)



