WebMCP  /  imperative API

The imperative API

The JavaScript side of WebMCP. You call document.modelContext.registerTool(), hand it a name, a description, a typed input schema, and a function to run, and an in-browser agent can call that function like any other tool.

document.modelContext .registerTool({ name: "search", description: "...", inputSchema: {...}, execute: async (a) => // run your code }); agent sees: search(query) → AI
Emerging

This documents a draft API in a Chrome origin trial. Method names and shapes are current as of 23 July 2026 and are changing; confirm against the specification before you build.

When to use the imperative API

Reach for the imperative API when the action is dynamic: a search that queries your back end, a filter that recomputes results, anything that already runs in your front-end JavaScript. It gives you full control over the tool's inputs, how it executes, and what it returns. For a standard form you already have, the declarative API is usually less work. Most real sites use both.

Registering a tool

A tool is registered with document.modelContext.registerTool(). It takes an object describing the tool and an optional options object. The four parts of the description are the name, a plain-language description, an input schema written as JSON Schema, and an execute callback the browser runs when an agent calls the tool.

// Register a search tool an in-browser agent can call.
await document.modelContext.registerTool({
  name: "search-inventory",
  description: "Search current inventory by keyword and return matching items.",
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string", description: "What to search for" },
      inStockOnly: { type: "boolean" }
    },
    required: ["query"]
  },
  execute: async (args) => {
    const results = await findItems(args.query, args.inStockOnly);
    return { content: results };
  }
});

Signatures are current as of 23 July 2026. Confirm names against the primary source before shipping.

The parts of a tool

  • name: a short identifier the agent uses to refer to the tool.
  • description: plain language telling the agent what the tool does and when to use it. This is not a formality. An agent decides whether to call a tool from its description, so vague text produces wrong or missing calls.
  • inputSchema: a JSON Schema object, with type, properties, and required, describing the arguments. The schema is how the agent learns what to pass and in what shape.
  • execute: an async callback that receives the validated arguments, does the work, and returns a result. This is your code, running in the page, as the signed-in user.

Scoping and permissions

Registration accepts options that control exposure. A tool can carry an exposedTo setting so it is offered only to the origins or agents you intend, rather than to anything in the browser. WebMCP is restricted to secure contexts, so document.modelContext exists only on HTTPS pages. Access from cross-origin iframes is governed by a Permission Policy: when the tools policy is not granted, a call is rejected with a NotAllowedError. Treat a registered tool as a public entry point into your page and validate its arguments exactly as you would validate any request you did not write.

What is not settled yet

Disputed / open

These are marked to-be-specified in the draft. Do not build load-bearing code on them yet.

  • Companion methods for reading and invoking tools, noted in the draft as getTools() and executeTool(), are still to be specified.
  • The exact return shape of execute, and how rich a result a tool may hand back, is still being worked out.
  • The namespace itself moved from navigator.modelContext to document.modelContext in July 2026, with the older location deprecated in Chrome 150. See the naming note.

Sources

Reviewed 23 July 2026. The code above illustrates the current design; it is not a stable contract while WebMCP is in origin trial.

The other half

Not everything needs JavaScript.

If you already have a form, the declarative API can turn it into a tool with a couple of attributes.

The declarative API Is it worth acting on? →