DEV Community

Cover image for Scope WebMCP Tools to the Open React Workflow

Scope WebMCP Tools to the Open React Workflow

On the Events list, the browser discovered zero WebMCP tools. Opening an event draft exposed four. Switching to a trip draft replaced them with five trip tools.

That route sequence is the behavior I wanted when Trip Workbench gained a second workflow. Registering every operation at startup would have exposed two unrelated domains even when only one editor was visible.

Page-scoped tools make the current context clearer. They also create a design question: how does an agent enter a workflow whose tools exist only after the right page is open?

Keep domain identity in the contract

The event editor has a title, date range, time zone, location mode, location label, and notes. The trip editor has airports, travel dates, cabin, traveler count, and purpose.

Both workflows reuse authorization, revision, and command-receipt patterns, but they keep separate coordinators, services, tables, validation rules, policy versions, and identifiers. Event tools accept eventId; trip tools accept draftId.

The event editor exposes:

Tool Purpose
get_event_draft Read saved fields, revision, status, and unsaved-change state
update_event_draft Apply an allowed patch to an expected revision
validate_event_draft Return field issues and policy findings
prepare_event_review Show findings while the event remains a draft

This synthetic example does not send invitations, connect to calendars, or book venues.

Register when the editor has context

The React editor registers tools only after it has a draft identity and status. A condensed lifecycle looks like this:

useEffect(() => {
  if (!eventId || draftStatus !== "draft") return;

  const registration = new AbortController();

  registerEventDraftTools({
    eventId,
    canMutate: Boolean(canMutate),
    coordinator: eventCoordinator,
    signal: registration.signal,
    onStatus: setRegistration,
  });

  return () => registration.abort();
}, [eventId, draftStatus, canMutate, eventCoordinator]);
Enter fullscreen mode Exit fullscreen mode

Chrome’s current imperative API documents this signal-based lifecycle. As of Chrome 153, aborting the registration removes the tool without cancelling an already-running execution. That is helpful for component cleanup, but it means route cleanup and in-flight operation safety are separate responsibilities.

The draft identity belongs in the dependency list. React may retain the same component type while moving from one event to another; the old tools must disappear and the new handlers must bind to the new event.

Test the exact route sequence

The native browser run signed in normally, used visible navigation, created a synthetic event draft, and inspected the browser’s real tool collection. It did not call the coordinator directly.

Context Discovered interface
Traveler on Trips list none
Traveler on Events list none
Traveler editing an event four event tools
Traveler editing a trip five trip tools
Traveler back on Events list none
Traveler reopening the event four event tools
Observer editing the event read, validate, prepare
Observer back on Events list none

An exact-name assertion catches stale registrations:

const expected = [
  "get_event_draft",
  "prepare_event_review",
  "update_event_draft",
  "validate_event_draft",
];

const actual = page.webmcp.tools()
  .map((tool) => tool.name)
  .sort();

assert.deepEqual(actual, expected);
Enter fullscreen mode Exit fullscreen mode

The observer result is useful but limited. Omitting a mutation tool reduces accidental exposure; it does not authorize anything. The server must still reject writes from an actor without permission.

Execute a useful operation, not just discovery

Tool names alone do not prove that the page contract works. The run updated a synthetic workshop, validated it, and prepared an inline review.

{
  "title": "Customer engineering workshop",
  "startDate": "2026-11-25",
  "endDate": "2026-11-26",
  "timeZone": "America/Los_Angeles",
  "locationMode": "manual",
  "locationLabel": "Demo workshop room",
  "notes": "Synthetic example; no invitations"
}
Enter fullscreen mode Exit fullscreen mode

The accepted update moved the draft from revision 1 to 2. prepare_event_review displayed a MANUAL_LOCATION requirement with canSubmit: true and submitted: false. The visible title matched an independent database query, and the event remained a draft with zero submissions.

The injected test clock was October 14, 2026, so the dates were still in the future. Pinning time matters when validation depends on dates.

A narrow interface needs a way in

The Events list intentionally exposes no editor tools, so those tools cannot open their own workflow.

The recorded run used the normal Events link and “New event draft” button. A browser agent with navigation and actuation can take a similar path. A client limited to WebMCP calls cannot.

There are two defensible designs:

  1. Treat browser navigation as part of the client contract.
  2. Add a bounded list-level tool to open an authorized draft or create a new one.

I would avoid a generic “call any API” or “run arbitrary JavaScript” escape hatch. It destroys the narrow schemas and server checks that make the editor tools reviewable.

Do not turn tool count into a performance claim

This run proves that the discovered interface changes with route and role. It does not prove that a model completes tasks faster with four tools than with nine.

That requires a separate evaluation: keep the task and executable behavior fixed, vary the visible tool set, and measure wrong-target updates, workflow-entry failures, correct persisted outcomes, recovery steps, and final-answer accuracy.

The current evidence supports a narrower conclusion: expose editing tools where the relevant object is visible, remove them when the context ends, preserve server authorization, and design an explicit entry path for the clients you actually support.

Top comments (3)

Collapse
 
komopdf profile image
KomoPDF •

That Chrome 153 detail about registration.abort() unregistering the tool without cancelling an in-flight call creates a tricky React edge case when a user switches directly from one draft to another on the same mounted editor component. Because React keeps the component instance alive and re-runs useEffect, an update_event_draft call bound to the previous eventId can resolve after the route has already swapped to the new draft. Passing expectedRevision protects the server record from a stale write, though the client callback still needs a per-effect cancellation token or a currentDraftId check before merging the response into React state.

On your entry-path tradeoff, exposing a narrow list-level open_event_draft tool that only transitions to an authorized route works well for clients that cannot click DOM links, without opening the door to bulk mutations from the index view. Keeping write tools locked to the mounted editor while leaving discovery and navigation on the list keeps the blast radius small and the schemas easy to audit.

Collapse
 
paullovelace profile image
Paul Lovelace •

The part I keep coming back to is the entry-path tradeoff — the Events list deliberately exposes no tools, so the tools can't open their own workflow, and yet a browser agent still has to get in somehow. I'm with you on treating navigation as part of the contract for now, though I can see KomoPDF's point that a narrow open_event_draft is the friendlier option for clients that can't click DOM links. Either way, the refusal to turn four tools versus nine into a speed claim is the honest bit; that's a separate evaluation, and most posts would have just claimed it.

Collapse
 
mp3sss31 profile image
mp3sss •

This context-scoped registration maps neatly onto how we gate IPC handlers in desktop apps: don't expose every capability at startup, register a window/view's handlers only after it has its identity and is ready, so the agent can't reach across an unrelated domain. Keeping the domain identity in the contract (eventId vs draftId, expected revision, policy version) is what makes calls auditable and lets you reject stale-patch conflicts instead of silently applying them. The open question — how an agent enters a workflow whose tools only exist after the right page opens — sounds solvable with a small discovery/context tool or a route-state broadcast that points the agent to the right draft before the scoped tools appear.