Skip to content

Signaling tool stability to agents #328

Description

@domfarolino

Unlike many MCP servers, where the available tool set is relatively stable for the lifetime of the server, WebMCP tools may change frequently as the user moves through a site:

  • Framework components mount and unmount
  • Async hydration completes after the page's load event
  • SPA navigations / route changes
  • Full-on MPA navigations
  • Changes in UI state that usher in new tools and unregister irrelevant ones

In our experience, agents operating web pages generally have a heuristic for deciding when a page has "loaded" or "settled" enough to create a page observation for the model, including the page's list of WebMCP tool.

The problem is that registration of all of a site's relevant tools might not be synchronized with the agent's page-stability heuristic. A page may "look ready" to the agent while an important batch of tools is still being registered, and an observation might then end up with a partial view of relevant tools designed for it.

Based on how we've seen agents being built, we anticipate this will be an issue, but we'd love feedback from other real-world browser-use agents to know if this problem statement resonates. We'd love to get a signal from at least the following folks:

Does your experience with browser agents resonate with the issue described above, whether related to WebMCP or beyond it? Would your agents benefit from letting developers provide input to existing page/tool stability heuristics?

We propose an API to let developers signal to any listening agents:

"My currently registered tools are still in flux. If you are about to take an initial or refreshed observation of my tools, please wait until I signal that this transition is complete."

We don't intend to standardize how page observations are taken. This is just about giving developers a way to provide a signal that agents can incorporate in their observation heuristics.

Example problem

Consider a page whose initial HTML becomes interactive before its WebMCP-specific code finishes loading:

// The page may already appear "loaded" or "settled" to an agent.

await import("./webmcp-tools.js");

document.modelContext.registerTool({
  name: "search_products",
  // ...
});

document.modelContext.registerTool({
  name: "issue_refund",
  // ...
});

document.modelContext.registerTool({
  name: "add_review",
  // ...
});

If the agent decides to observe the page between page readiness and completion of these registrations, the model may see only a partial tool set.

A similar issue can occur during SPA navigations, where a route transition causes one group of tools to disappear and another group to be registered asynchronously.

Strawman API proposal

One possible shape is an explicit begin/end signal:

const stability = document.modelContext.beginToolUpdate();

try {
  const tools = await import("./webmcp-tools.js");
  await tools.register();
} finally {
  stability.end();
}

While the tool-update scope is active, the page is indicating that its registered tool set should not yet be considered stable. The API could be nestable so that independent components can participate without coordinating through a single global promise:

const a = document.modelContext.beginToolUpdate();
const b = document.modelContext.beginToolUpdate();

a.end();
// Tool set is still unstable.

b.end();
// Tool set is now stable.

The browser should impose an upper bound on how long an outstanding stability signal can delay an observation, and agents will likely need their own preotections regardless. Both of these mreasures prevent a broken (or misbehaving) page from indefinitely blocking an agent.

(Disclaimer: the exact shape of the API above are only illustrative and are very up for debate).

SPA and dynamic transitions

One of the most common use cases for this API would be during SPA navigations, which are common on the web, and where agent page stability heuristics are likely to vary a lot:

async function navigate(path) {
  const update = document.modelContext.beginToolUpdate();

  try {
    await router.navigate(path);
    await registerToolsForRoute(path);
  } finally {
    update.end();
  }
}

Initial page load

To signal tool instability on initial page load, I think we have two options:

  1. Force developers to call beginToolUpdate() super early, in <head> JavaScript for example; or
  2. Provide a declarative, <meta> tag way to load a page with an immediate signal of tool instability, and make developers signal the end of that imperatively with JS
<meta name="tool-stability" content="pending">

<script>
  await App.slowHydration(); // Loads lots of tools asynchronously.
  document.modelContext.toolsAreStable();
</script>

Alternatives considered: "tool snapshot requested" event

Another possible design is for the browser to fire an event immediately before it intends to observe tools:

[SecureContext, Exposed=Window]
interface ToolObservationEvent : Event {
  undefined waitUntil(Promise<any> promise);
};

partial interface ModelContext {
  attribute EventHandler ontoolobservation;
};

A page could then delay the agent's observation with waitUntil(). This is attractive because it directly synchronizes the page with an observation attempt. But it assumes that agents have a discrete "tool snapshot" step that the browser can expose, and achieves the same thing as our above proposal, while unnecessarily exposing implementation details of the agent. It also gets confusing to developers when there are multiple agents driving a page.

The developer would likely use this API like this:

window.toolsAreStable = true;

async function loadMoreTools() {
  window.toolsAreStable = false;
  // Load more tools
  // ...
  window.toolsAreStable = true;
}

document.modelContext.ontoolsnapshotrequested = e => {
  if (!window.toolsAreStable) {
    e.waitUntil(/*some promise*/);
  }

  // Otherwise, do nothing.
}

In this case, the developer isn't interested in knowing when the agent is grabbing the list of tools, or how many agents are grabbing the list of tools. Instead, they're maintaining their own tool stability bookkeeping that simple gets surfaced to the agent through the event, making the event unimportant in the exchange.

Relationship to toolchange

Agents can still react incrementally to toolchange throughout the lifetime of the document, but since we've observed that an agent's heavy "page snapshot" / "page observation" infrastructure is unlikely to take place on every toolchange event, we still wind up with the page observation gap that motivates this issue.

Activity

  1. sjdallst2 commented on Oct 1, 2026

    @sjdallst2

    @domfarolino, for future communications, @bwalderman is working on multiple projects, and I am now the main point of contact for WebMCP dev at Microsoft.

    I like the idea of the proposal. Judging from the code we have, there is a clear information issue where we do not know when tools are available, and we have to guess when a page will be ready. And, like you said, page snapshots can be heavy.

    I like the idea of keeping everything within the websites control instead of the proposal where the agent sends an event that the page must respond to.

    Have you thought about having the modelContext be unstable by default (no declaration necessary), then adding something like an isFinal parameter for ModelContextRegisterToolOptions, or would that be confusing?

  2. dhrumil83 commented on Oct 1, 2026

    @dhrumil83

    I work on ArcGIS AI Components, where we use browser-native orchestration to run agents, skills and tools. We’re exploring how external agents could access those capabilities through WebMCP.

    One use case for this is progressive disclosure of tools through skills.
    For example, a page supports three skills and 20 tools across those skills. Initially, it exposes only a load_skill tool, with the three available skills as options.

    When the external agent loads a skill, the page returns its instructions and registers the eight tools needed for that workflow. The external agent then orchestrates those tools using its own model.

    A tool-stability signal would help the external agent know when all the skill’s tools are registered and ready to use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions