Skip to main content
@mcp-b/webmcp-polyfill installs the strict WebMCP runtime on navigator.modelContext when no native implementation exists. It is the package to use when you want the browser standard in browsers today without MCP-B extensions.
npm install @mcp-b/webmcp-polyfill

Package selection

PackageUse When
@mcp-b/webmcp-typesYou need compile-time types only (no runtime)
@mcp-b/webmcp-polyfillYou want the WebMCP standard path in browsers today
@mcp-b/globalYou want the MCP-B runtime layer on top of that path

Minimal example

Functions

initializeWebMCPPolyfill(options?)

Installs the strict core polyfill on navigator.modelContext.
import { initializeWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';

initializeWebMCPPolyfill();
Behavior:
  • No-op in non-browser environments.
  • Non-destructive: if navigator.modelContext already exists (native or from a previous install), initialization is skipped.
  • Safe to call repeatedly.

Options

OptionTypeDefaultDescription
autoInitializebooleantrueSet false to disable auto-init from IIFE/import side effect.
installTestingShimboolean | 'always' | 'if-missing''if-missing'Controls whether navigator.modelContextTesting is installed.
disableIframeTransportByDefaultboolean-Deprecated no-op, kept for backward compatibility.

installTestingShim values

ValueBehavior
true or 'if-missing'Install only when modelContextTesting is not already present
'always'Install even when modelContextTesting already exists
falseDo not install

initializeWebModelContextPolyfill(options?)

Alias for initializeWebMCPPolyfill.

cleanupWebMCPPolyfill()

Restores previous navigator.modelContext and navigator.modelContextTesting property descriptors and resets the polyfill install state.
import { cleanupWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';

cleanupWebMCPPolyfill();

IIFE / script tag

The IIFE build auto-initializes on load. Configure via window.__webMCPPolyfillOptions:
<script>
  window.__webMCPPolyfillOptions = {
    installTestingShim: 'if-missing',
  };
</script>
<script src="https://unpkg.com/@mcp-b/webmcp-polyfill@latest/dist/index.iife.js"></script>

Methods on navigator.modelContext

After initialization, navigator.modelContext exposes these methods:

registerTool(tool)

Adds a single tool to the registry.
  • Requires a non-empty name, non-empty description, and execute function.
  • Throws on duplicate tool names.
  • If inputSchema is omitted, defaults to { type: "object", properties: {} }.

unregisterTool(name)

Removes a tool by name. Unknown names are a no-op.
The polyfill does not provide listTools() or callTool() on navigator.modelContext. For tool listing and execution, use navigator.modelContextTesting (when the testing shim is enabled) or switch to @mcp-b/global.

Testing shim

When installTestingShim is enabled, the polyfill installs navigator.modelContextTesting with the standard testing API:
MethodReturns
listTools()ModelContextTestingToolInfo[]
executeTool(toolName, inputArgsJson, options?)Promise<string | null>
registerToolsChangedCallback(callback)void
getCrossDocumentScriptToolResult()Promise<string> (always "[]" in polyfill)
initializeWebMCPPolyfill({ installTestingShim: true });

const tools = navigator.modelContextTesting?.listTools();
const result = await navigator.modelContextTesting?.executeTool(
  'search',
  JSON.stringify({ query: 'webmcp' })
);
For full details on the testing API, see WebMCP standard API.

Input schema support

The polyfill accepts three formats for inputSchema:
FormatDescription
Plain JSON SchemaInputSchema object
Standard Schema v1 validatorObject with ~standard.validate() (e.g., Zod 4)
Standard JSON Schema v1Object with ~standard.jsonSchema.input()
Standard JSON Schema conversion is attempted with targets draft-2020-12 first, then draft-07. When both Standard validator and Standard JSON Schema are present on the same object, JSON conversion is preferred.

Validation

The polyfill validates tool descriptors on registration:
ConditionError
tool is not an objectTypeError: registerTool(tool) requires a tool object
name is empty or not a stringTypeError: Tool "name" must be a non-empty string
description is empty or not a stringTypeError: Tool "description" must be a non-empty string
execute is not a functionTypeError: Tool "execute" must be a function
Duplicate tool nameError: Tool already registered: <name>
Invalid JSON Schema structureError: Invalid JSON Schema at <path>: <details>
Schema not JSON-serializableError: Invalid JSON Schema at <path>: schema must be JSON-serializable
Input arguments are validated at execution time using JSON Schema validation (via @cfworker/json-schema). Standard Schema validators are used when available.

Type inference

For compile-time type inference, pair the polyfill with @mcp-b/webmcp-types:
import type { JsonSchemaForInference } from '@mcp-b/webmcp-types';
import { initializeWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';

initializeWebMCPPolyfill();

const inputSchema = {
  type: 'object',
  properties: {
    query: { type: 'string' },
    limit: { type: 'integer', minimum: 1, maximum: 50 },
  },
  required: ['query'],
  additionalProperties: false,
} as const satisfies JsonSchemaForInference;

navigator.modelContext.registerTool({
  name: 'search',
  description: 'Search indexed docs',
  inputSchema,
  async execute(args) {
    // args inferred as: { query: string; limit?: number }
    return { content: [{ type: 'text', text: `Searching for ${args.query}` }] };
  },
});
For full inference documentation, see @mcp-b/webmcp-types.

Interop with @mcp-b/global

If the polyfill is installed first, @mcp-b/global wraps the existing context with BrowserMcpServer to add MCP-B extension APIs without replacing the core object identity. Use @mcp-b/global directly when you need callTool, resources, prompts, or transport. For guidance on choosing between them, see Choose a Runtime. For the layering rationale, see Native vs Polyfill vs Global.