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

deferRelease

Runs release on a later macrotask unless cancelled first, and keeps waiting while isBusy() is true.

Runs release on a later macrotask unless cancelled first, and keeps waiting while isBusy() is true. Use it for anything that unregisters a tool from UI code: Chrome cancels a call whose tool changes, and React unmounts and remounts on purpose.

Import

import { deferRelease, RESPONSE_GRACE_MS } from "@webmcp-agents/core";
import type { DeferReleaseOptions } from "@webmcp-agents/core";

Example

The pattern for a tool registered from an effect: register with a call tracker, and on cleanup release later, after the calls in flight are answered. A setup in the same tick (StrictMode) cancels the release.

import {
  createCallTracker,
  defineWebTool,
  deferRelease,
  RESPONSE_GRACE_MS,
  registerWebTool,
} from "@webmcp-agents/core";

const tool = defineWebTool({
  id: "get_cart",
  description: "Read the cart.",
  readOnly: true,
  execute: () => ({ items: 2 }),
});

// Setup: register, and count the calls that reach the tool.
const calls = createCallTracker();
const unregister = registerWebTool(tool, { calls });

// Cleanup: not now. Wait a tick, then for calls to be answered.
const pending = deferRelease(unregister, {
  isBusy: calls.busy,
  graceMs: RESPONSE_GRACE_MS,
});

// Setup again in the same tick (React StrictMode): keep the tool.
pending.cancel();

Options

deferRelease(release, options?). The first argument is the work; the second is a DeferReleaseOptions.

Name Type Default Description
release () => void required The work to defer, usually the function registerWebTool returned. Runs at most once.
isBusy () => boolean never busy While this returns true, keep waiting: pass a CallTracker’s busy so a call in flight finishes first.
graceMs number 0 (polls every 50 ms) How often to re-check isBusy, in ms. Values under 50 are raised to 50. Pass RESPONSE_GRACE_MS for registrations.

RESPONSE_GRACE_MS

A constant, 500: the time, in ms, for the browser to deliver a settled response before a tool may change.

Returns

{ cancel(): void }. cancel() stops a pending release; after release has run, it does nothing.

Notes

  • The first check is always on a setTimeout(…, 0), so a remount in the same tick can cancel it.
  • createCallTracker’s busy() already includes RESPONSE_GRACE_MS after the last call, so the release waits for the call and then for its answer.
  • createToolRegistry and useWebTool in @webmcp-agents/react use this with graceMs: RESPONSE_GRACE_MS.
  • While isBusy() stays true the release keeps polling; nothing times it out.

See also

Was this page helpful?