# @nxisai/webmcp

> TypeScript polyfill for the WebMCP API (document.modelContext / navigator.modelContext)

Latest version **0.1.0** (published 2026-07-13) · MIT license · 0 weekly downloads

## Install

```sh
npm install @nxisai/webmcp
pnpm add @nxisai/webmcp
yarn add @nxisai/webmcp
bun add @nxisai/webmcp
```

## Health

**Score 50/100 (C)** — status: active.

Positive: no vulnerabilities; recently updated.

Warnings: low downloads; no types; no esm support; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.1.0 |
| Published | 2026-07-13 |
| First published | 2026-07-13 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | nxisai_admin |
| Keywords | webmcp, mcp, model-context-protocol, modelcontext, polyfill, agents |

## Links

- npm: https://www.npmjs.com/package/@nxisai/webmcp
- Repository: https://github.com/nxisai/nxis-webmcp
- Homepage: https://github.com/nxisai/nxis-webmcp#readme
- Issues: https://github.com/nxisai/nxis-webmcp/issues
- npm.io page: https://npm.io/package/@nxisai/webmcp

## Recent versions

- 0.1.0 (latest) — 2026-07-13

## README

# @nxisai/webmcp

A TypeScript polyfill for the [WebMCP API](https://developer.chrome.com/docs/ai/webmcp) — the proposed web standard ([webmachinelearning/webmcp](https://github.com/webmachinelearning/webmcp)) that lets web pages expose Model Context Protocol–style tools to browser AI agents via `document.modelContext`.

WebMCP ships natively behind an origin trial starting in Chrome 149 (`chrome://flags/#enable-webmcp-testing`). This polyfill provides the same imperative API surface everywhere else, so you can:

- write against `document.modelContext` today without feature-gating your code,
- test tool registration and execution in unit tests / Node / non-Chromium browsers,
- let in-page or extension-based agents discover and call your tools via `getTools()` / `executeTool()`.

When a native implementation exists, the polyfill steps aside automatically.

## Install

```sh
npm install @nxisai/webmcp
```

## Usage

### Auto-install (recommended)

```ts
import "@nxisai/webmcp/auto";

const controller = new AbortController();

document.modelContext.registerTool(
  {
    name: "add-todo",
    description: "Add a new item to the user's active todo list",
    inputSchema: {
      type: "object",
      properties: {
        text: { type: "string", description: "The text content of the todo item" },
      },
      required: ["text"],
    },
    async execute({ text }) {
      await addTodoItemToCollection(text);
      return {
        content: [{ type: "text", text: `Added todo item: "${text}" successfully.` }],
      };
    },
  },
  { signal: controller.signal }
);

// Later: unregister by aborting.
controller.abort();
```

### Explicit install

```ts
import { installWebMCPPolyfill, isWebMCPSupported } from "@nxisai/webmcp/polyfill";

if (!isWebMCPSupported()) {
  installWebMCPPolyfill();
}
```

### Page-level context with `provideContext()`

Each call replaces the full set of page-level tools (tools added with `registerTool()` are unaffected) — useful for SPA route changes:

```ts
document.modelContext.provideContext({
  tools: [searchFlightsTool, filterResultsTool],
});

// Navigating to checkout? Swap the toolset wholesale:
document.modelContext.provideContext({ tools: [checkoutTool] });
```

### Agent side: discovery and execution

```ts
const tools = await document.modelContext.getTools();
// [{ name, description, inputSchema, annotations?, origin }]

document.modelContext.addEventListener("toolchange", async () => {
  console.log("toolset changed:", await document.modelContext.getTools());
});

// Input may be a JSON string (native API shape) or a plain object.
const result = await document.modelContext.executeTool(
  "add-todo",
  JSON.stringify({ text: "buy milk" })
);
// => { content: [{ type: "text", text: 'Added todo item: "buy milk" successfully.' }] }
```

## API

| Member | Description |
| --- | --- |
| `registerTool(tool, { signal?, exposedTo? })` | Register one tool. Re-registering a name replaces it; abort the signal to unregister. |
| `provideContext({ tools? })` | Set the page-level toolset; each call replaces the previous one. |
| `getTools({ fromOrigins? })` | Resolve the list of registered tools (without `execute`). |
| `executeTool(name, input?, { signal? })` | Validate input against the tool's `inputSchema` and run it. Returns a normalized `{ content: [...] }` response. |
| `toolchange` event / `ontoolchange` | Fired (coalesced per microtask) when the toolset changes. |
| `unregisterTool(name)`, `clearContext()` | Polyfill conveniences, not part of the proposal. |

Error semantics for `executeTool()`:

- unknown tool → rejects with `NotFoundError`
- malformed JSON or schema-invalid input → rejects with `TypeError`
- abort → rejects with `AbortError` (the tool's `execute` also receives a `signal` it can observe)
- exception thrown *inside* the tool → resolves with `{ isError: true, content: [...] }`, mirroring MCP tool-result error semantics

Input validation uses a built-in lightweight JSON Schema checker (`type`, `properties`/`required`, `items`, `enum`/`const`, `additionalProperties`, numeric/string/array bounds, `pattern`, `anyOf`/`oneOf`/`allOf`). It's also exported standalone as `validateAgainstSchema()`.

## What a polyfill can't do

- **Connect you to a real agent.** Native WebMCP lets the *browser's* agent (or an assistant like Gemini in Chrome) call your tools. A polyfill can only make the API surface available — something in the page (a script, test harness, or extension content script) still has to call `getTools()`/`executeTool()`.
- **Cross-origin tool exposure.** `exposedTo` and `getTools({ fromOrigins })` are accepted for API compatibility but not enforced/implemented; native behavior depends on the `tools` Permissions Policy and origin isolation (`Origin-Agent-Cluster`).
- **The declarative (HTML form annotation) API.** Only the imperative API is polyfilled.

## Compatibility notes

- Installed at `document.modelContext` (current spec, Chrome 150+) **and** `navigator.modelContext` (deprecated alias used by earlier explainer revisions and Chrome 149), so code written against either keeps working. Disable the alias with `installWebMCPPolyfill({ installNavigatorAlias: false })`.
- Works in any environment with `EventTarget`, `AbortController`, and `structuredClone` (all modern browsers; Node 17+).

## Development

```sh
npm install
npm test        # vitest
npm run build   # emits dist/
```

---
_Source: https://npm.io/package/@nxisai/webmcp · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
