Skip to content
WebMCP Agents
Esc
↑↓navigate↵open⌘Jpreview
On this page

callModelContextTool

Runs one page tool for an agent through core's executeTool, so the agent cursor plays and Chrome and polyfill differences are absorbed.

Runs one page tool for an agent through core’s executeTool, so the agent cursor plays and Chrome and polyfill differences are absorbed. Use it in an adapter that does not use the session: it never throws, every outcome is a result the model can read, and failures carry an error code.

Import

import {
  callModelContextTool,
  CANCELLED,
  isCancelled,
  NAVIGATED,
  TOOL_TIMEOUT_MS,
} from "@webmcp-agents/chat";
import type { CallToolOptions } from "@webmcp-agents/chat";

Example

What a custom adapter does for a tool call the model made: run it with the person’s Stop signal and a longer limit, and warn unless the person cancelled.

import {
  callModelContextTool,
  isCancelled,
  listToolDescriptors,
} from "@webmcp-agents/chat";

// What a custom adapter does for each tool call the model makes.
const stop = new AbortController();
const [first] = await listToolDescriptors();

if (first) {
  const output = await callModelContextTool(
    { name: first.name, input: {} },
    { signal: stop.signal, timeoutMs: 60_000 },
  );

  const text = output.content[0]?.text ?? "";
  if (output.isError && !isCancelled(text)) console.warn(text);
}

Options

callModelContextTool(call, options?). The first argument is the call, the second a CallToolOptions.

Name Type Default Description
call { name: string; input: unknown } required The tool’s name and its arguments. An input that is not an object is sent as {}.
signal AbortSignal not set The person’s Stop. Aborting cancels the call, which answers CANCELLED.
timeoutMs number TOOL_TIMEOUT_MS (30 000) How long the tool may take before the agent gets a timeout error and can move on. 0 waits forever. The clock stops for good once the tool waits for the person: see the time limit.

Returns

A Promise<ToolOutput> (an MCP result: { content, isError?, structuredContent? }):

Outcome Result
The tool answered Its result as is.
The tool answered "Error: …" (or set isError) without a code isError: true, the text recoded as Error [failed]: …, structuredContent.error added; the tool’s own structuredContent is kept.
The tool answered with a code already Its result with isError: true.
The page navigated (Chrome resolves such calls to null) The text NAVIGATED, not an error.
signal aborted Error [cancelled]: Cancelled by the user. (CANCELLED), isError: true.
No answer within timeoutMs Error [timeout]: "<tool>" didn't answer within N s, so it was stopped. …; the call is cancelled.
The page cancelled the call (a navigation, the tool re-registered) Error [interrupted]: The page cancelled this call before it finished …
No such tool (Unknown tool …) Error [unavailable]: Tool "<tool>" is not on this page right now. …
The tool threw Error [failed]: <message>

Coded failures have structuredContent.error = { code, retryable }. See tool error codes for what each code means.

The time limit and waitingForUser

The clock stops for good once the tool waits for the person, since they may take their time. That is detected two ways: a core park event for this tool (a confirm, or waitingForUser()), or, when the timer fires, a declarative form[toolname="<tool>"] on the page whose submit is paused for the click ([data-tool-submit-active] or :tool-submit-active). The park event needs the visuals installed, so the page check covers pages without them.

CANCELLED and isCancelled

CANCELLED is "Error [cancelled]: Cancelled by the user.", what a call the user stopped answers. isCancelled(text) is true for text starting with Error [cancelled], or with Cancelled by the user (conversations saved before codes existed). The session shows such calls as cancelled, not failed.

NAVIGATED is “The page navigated away while this tool ran, so its result is unknown. Check the page before retrying.” TOOL_TIMEOUT_MS is 30_000.

Notes

  • Only the person’s Stop answers cancelled. A call the page cancelled is interrupted, so the agent checks the page and carries on instead of stopping.
  • A timeout stops the call, but the tool may or may not have done its work; the message says to check the page.
  • useAgentSession passes its own signal; you rarely need this directly unless you write an adapter that does not use the widget.

See also

Was this page helpful?