Realigns the library with the current WebMCP
spec. This is a clean break — the public surface (<WebMCPProvider>, useMcpTool,
useWebMCPStatus) is unchanged in shape, but the underlying WebMCP wiring has breaking
changes.
Breaking changes
-
API moved to
document.modelContext. The registration API is now installed and detected
ondocument.modelContextinstead ofnavigator.modelContext. Native detection is
document-only —navigator.modelContextis no longer read or written. (The testing/consumer
API stays onnavigator.modelContextTesting.) -
registerToolreturns aPromise. The polyfill'sregisterTool(tool, options?)now
returns aPromise<undefined>that rejects on:- an empty/missing name, a name longer than 128 chars, or a name not matching
^[A-Za-z0-9_.-]+$; - a duplicate name already registered;
- an empty/missing description;
- an
executethat is not a function; - a non-serializable
inputSchema; - an
exposedToentry that is not a parseable, potentially-trustworthy origin.
Already-aborted
AbortSignalpassed toregisterToolresolves as a no-op (registration is
skipped), matching native Chrome 151. (Note: WebMCP spec PR #202 specifies rejection; native had
not shipped that as of Chrome 151. Revisit if native changes.)useMcpToolroutes these rejections intostate.errorandonError, exceptAbortError
(lifecycle teardown), which is ignored. - an empty/missing name, a name longer than 128 chars, or a name not matching
-
Unregistration is AbortSignal-only. There is no
unregisterTool. Tools are removed by
aborting theAbortSignalpassed viaregisterTool's options;useMcpTooldoes this on
unmount. -
Single-argument handlers. Tool
execute(input)and userhandler(args)now take a single
argument.ModelContextClientandrequestUserInteractionare removed entirely. -
ToolAnnotationsnarrowed to{ readOnlyHint?, untrustedContentHint? }. The classic MCP
hints (destructiveHint,idempotentHint,openWorldHint) andannotations.titleare
removed. -
Top-level
title?added to the tool config and descriptor (replacing the dropped
annotations.title). -
exposedTo?: string[]added to the tool config andRegisterToolOptionsfor cross-frame
origin visibility. ChangingexposedTore-registers the tool. -
toolchangeevent.document.modelContextis anEventTargetthat fires a bare
toolchangeevent (nodetail) on tool register/unregister.addEventListener("toolchange", ...)and anontoolchangehandler are both supported.
Retained library extensions
outputSchema(Zodoutput/ JSON-SchemaoutputSchema) is kept as a documented library
extension, not part of the spec descriptor.structuredContentonCallToolResultis retained.- Handlers always return a
CallToolResultwith acontentarray (including error results
withisError: true) — a deliberate convention layered over the spec's looser return type so
results bridge cleanly to desktop MCP clients.
Notes
- The already-aborted-signal behavior was confirmed against native Chrome 151: native skips
registration and resolves withundefined(a no-op) rather than rejecting, so the polyfill
matches. (WebMCP spec PR #202 specifies rejection; native had not shipped that as of Chrome 151.
Revisit if native changes.)