Editorial

WebMCP · executeTool · browser interoperability · 13 September 2026

WebMCP executeTool input errors: separate the current draft from runtime drift

If document.modelContext.getTools() succeeds but manual execution fails, inspect the API boundary before rewriting the tool. The current 10 September WebMCP draft requires an object as executeTool input and exposes RegisteredTool.inputSchema as an object. A live implementation report filed on 1 September observed the opposite shape: JSON-string input succeeded and inputSchema arrived as serialized text.

Published 13 September 2026 · sources checked 13 September 2026

Object

Current draft inputObject requirement

RegisteredTool

Pass the object returned by getTools(), not only its name

object

Current draft inputSchema shape on RegisteredTool

DOMString

Current draft executeTool return type

Current normative target

The 10 September draft is unambiguous about the object boundary

The current WebMCP Draft Community Group Report defines executeTool(RegisteredTool tool, optional any inputObject). Its algorithm rejects an inputObject that is not an Object, then serializes that object to JSON internally before dispatching the tool. The draft example likewise calls executeTool(tool, {a: 10}).

For discovery, getTools() currently constructs a RegisteredTool whose inputSchema member is an object. The algorithm parses the internally stored JSON string back into a JavaScript value before returning the tool, and the specification describes that value as a deep copy of the schema supplied at registration.

The return boundary is intentionally different: the current draft says executeTool resolves to the stringified result of the tool execution. Do not use a string return value as evidence that input arguments should also be strings.

Why developers are still seeing the opposite

A current implementation report documents exactly this mismatch

WebMCP issue #278, opened 1 September 2026, reports a tested browser implementation where an object argument caused an input parsing/type error, while JSON.stringify({ message: "hello" }) succeeded. The same report observed tool.inputSchema as a string containing serialized JSON Schema.

The project also has an open pull request titled Clarify executeTool input and schema values. Taken together with the newer 10 September draft text, that is a strong signal to treat this failure as browser/spec-version interoperability drift rather than as proof that every WebMCP client should encode arguments as JSON text.

Fast diagnosis

Read the raw runtime shape before changing your tool

Observed signalWhat it suggestsFirst action
executeTool(tool, {…}) throws a parse/type errorRuntime may lag the current draft or expose a transitional implementationCapture browser/build and retry with the smallest object payload before changing application logic.
executeTool(tool, JSON.stringify({…})) worksObserved compatibility behavior, not the current draft contractTreat it as a gated runtime workaround, not a portable API assumption.
typeof tool.inputSchema === 'string'Runtime is exposing serialized schema textParse only for inspection/validation; current draft RegisteredTool.inputSchema is an object.
executeTool resolves but typeof result === 'string'Expected by the current draftParse the result only when your tool contract says its payload is JSON.
A tool name string is passed instead of the returned tool objectWrong executeTool target shapeUse the RegisteredTool returned by getTools().

Minimal current-draft probe

Test the portable shape first and log what the browser actually returns

const tools = await document.modelContext.getTools();
const tool = tools.find((entry) => entry.name === "example_tool");

if (!tool) throw new Error("example_tool not registered");

console.log({
  toolName: tool.name,
  schemaType: typeof tool.inputSchema,
  inputSchema: tool.inputSchema,
});

const result = await document.modelContext.executeTool(
  tool,
  { message: "hello" },
);

console.log({ resultType: typeof result, result });

This follows the current draft: a RegisteredTool from getTools(), an object input, and a string result. If that exact probe fails while a JSON-string input succeeds, record the browser/version and isolate the workaround. That evidence is more useful than changing the tool schema until the failure disappears.

Compatibility pattern

Gate transitional behavior; do not let it become your permanent contract

  1. 1. Feature-detect the current surface. Prefer document.modelContext; do not assume an old tutorial targets the current draft.
  2. 2. Await registration and discovery. Keep a clear boundary between registering a tool and retrieving the RegisteredTool that an in-page caller executes.
  3. 3. Inspect the schema value. If a runtime returns a string, parse it only where needed for diagnostics or validation. Do not double-stringify a value merely because one implementation did so.
  4. 4. Try the current draft shape first. Pass an object to executeTool. If a known runtime requires JSON text, scope that fallback to the detected implementation and keep telemetry around it.
  5. 5. Keep consequences server-authorized. A compatibility branch must not weaken authentication, spending limits, idempotency or confirmation rules for state-changing tools.
  6. 6. Remove the fallback when the runtime converges. WebMCP is a draft. Compatibility code should have an owner, a target environment and an expiry condition.

Do not confuse three different JSON boundaries

Registration schema, execution input and execution result have different shapes

BoundaryCurrent 10 Sep draftDebugging rule
registerTool inputSchemaJavaScript object describing JSON SchemaKeep it serializable and valid; the browser stores a serialized form internally.
RegisteredTool.inputSchemaObject / deep copy from getTools()If the runtime returns a string, record it as version drift and parse defensively.
executeTool inputObjectObject; non-Objects are rejected by the current algorithmObject first. JSON-string fallback only for a verified affected runtime.
executeTool resultStringified tool resultParse only when the tool contract says the returned text contains JSON.

Continue from diagnosis to agent-ready delivery

Primary sources

WebMCP remains a Draft Community Group Report rather than a W3C Standard. Browser behavior and the specification can change; verify the current draft and your target runtime before treating this page as a frozen API contract.