---
name: Web Mcp
description: Use when building browser-based tools for AI agents, integrating existing web apps with AI capabilities, or connecting desktop agents to website functionality. WebMCP is a W3C standard for exposing structured tools from websites to AI agents through document.modelContext.
metadata:
    mintlify-proj: webmcp
    version: "1.0"
---

# WebMCP Skill

## Product summary

WebMCP is a W3C browser standard that lets websites publish structured tools to AI agents through `document.modelContext`. Tools run inside the page's origin, authenticated session, and visible context—giving agents an explicit capability contract instead of inferring intent from screenshots or DOM automation.

MCP-B provides the implementation packages: `@mcp-b/webmcp-polyfill` (strict core), `@mcp-b/global` (full runtime with transports and MCP extensions), React hooks, local relay for desktop agents, and Chrome DevTools integration. Key files: tool registration happens in your app's entry point or component lifecycle. Configuration is done via `registerTool()` calls or React hooks. Transports and relays bridge tools across browser boundaries to desktop clients like Claude Desktop or Cursor.

**Primary docs:** https://docs.mcp-b.ai

## When to use

Reach for this skill when:

- **Building web apps with AI integration**: You want to expose search, form-filling, data lookup, or other app functionality to AI agents without building a separate API.
- **Adding tools to existing apps**: You have a working web application and want to let agents interact with it without rewriting around WebMCP.
- **Connecting desktop agents to browser tools**: You need Claude Desktop, Cursor, or other MCP clients to call tools running in your website.
- **Developing AI-driven workflows**: You're building tight feedback loops where an AI agent writes code, tests it, and iterates—using Chrome DevTools MCP for live discovery.
- **Choosing a runtime layer**: You need to decide between native browser API, strict polyfill, or full MCP-B runtime based on your feature needs.

Do not use this skill for: authentication setup, account creation, pricing questions, or dashboard-only operations.

## Quick reference

### Package layers (pick the smallest that fits)

| Package | Runtime | Core API | MCP extensions | Use when |
|---------|---------|----------|---|----------|
| `@mcp-b/webmcp-types` | No | Types only | Types only | You only need compile-time safety, no runtime |
| `@mcp-b/webmcp-polyfill` | Yes | `registerTool`, `getTools`, `executeTool` | No | You want strict W3C standard, no MCP-B additions |
| `@mcp-b/global` | Yes | `registerTool`, `getTools`, `executeTool` | `callTool`, `listTools`, prompts, resources, transports | You need full MCP-B runtime, desktop relay, or extensions |
| `usewebmcp` | Yes | Via hook | No | React + strict core only |
| `@mcp-b/react-webmcp` | Yes | Via hook | Full MCP-B surface | React + full MCP-B runtime |

### Tool registration (core pattern)

```ts
document.modelContext.registerTool({
  name: 'search_products',
  description: 'Search product catalog',
  inputSchema: {
    type: 'object',
    properties: {
      query: { type: 'string' },
      limit: { type: 'integer' }
    },
    required: ['query']
  },
  async execute(args) {
    const results = await searchProducts(args.query, args.limit ?? 10);
    return {
      content: [{ type: 'text', text: JSON.stringify(results) }],
      structuredContent: results
    };
  }
});
```

### Debugging tools

| Command | Purpose |
|---------|---------|
| `navigator.modelContextTesting.listTools()` | List all registered tools in console |
| `navigator.modelContextTesting.executeTool('name', '{}')` | Execute a tool from console |
| `document.modelContext.getTools()` | Get tools (requires `@mcp-b/global`) |
| `webmcp_list_sources` | List connected browser tabs (via local relay) |
| `webmcp_list_tools` | List all relayed tools (via local relay) |

### Input schema styles

| Style | Dependencies | Runtime validation | Type inference | Best for |
|-------|---|---|---|---|
| Plain JSON Schema | None | No | No | Quick prototyping |
| JSON Schema + `as const` | `@mcp-b/webmcp-types` (dev) | No | Yes | TypeScript without schema library |
| Zod / Standard Schema | Schema library | Yes | Yes | Production with validation |

## Decision guidance

### When to use native vs. polyfill vs. full runtime

| Question | Answer | Next step |
|----------|--------|-----------|
| Does target browser ship `document.modelContext` natively? | Yes, and it covers your use case | Use native API, no package needed |
| Do you need compile-time types only? | Yes | Install `@mcp-b/webmcp-types` as dev dependency |
| Do you need the WebMCP standard in older browsers? | Yes | Install `@mcp-b/webmcp-polyfill` |
| Do you need MCP bridge, `callTool`, prompts, resources, or desktop relay? | Yes | Install `@mcp-b/global` |
| Are you using React? | Yes, strict core only | Use `usewebmcp` |
| Are you using React? | Yes, full MCP-B | Use `@mcp-b/react-webmcp` |

### When to use each transport

| Transport | Use when | Setup |
|-----------|----------|-------|
| Local relay (`@mcp-b/webmcp-local-relay`) | Connecting browser tools to Claude Desktop, Cursor, or other desktop MCP clients | Add `embed.js` script to page, configure MCP client |
| Chrome DevTools MCP | Building tools with tight AI feedback loop (write → test → iterate) | Configure as MCP server in Claude Code or similar |
| Tab transport (`@mcp-b/transports`) | Bridging tools across same-origin tabs or iframes | Use `TabServerTransport` and `TabClientTransport` |
| Extension transport | Building browser extensions that call website tools | Use `ExtensionTransport` with proper origin validation |

## Workflow

### Add tools to an existing app

1. **Choose a runtime**: Read [Choose a Runtime](/how-to/choose-runtime). If unsure, start with `@mcp-b/global`.

2. **Install the package**:
   ```bash
   npm install @mcp-b/global
   ```

3. **Import at entry point** (before any tool registration):
   ```ts
   import '@mcp-b/global';
   ```

4. **Identify functions to expose**: List app functions agents would find useful (search, add to cart, submit form, fetch data).

5. **Register each as a tool**:
   - Write a tool descriptor with `name`, `description`, `inputSchema`, `execute`
   - Call `document.modelContext.registerTool(descriptor)`
   - Return `{ content: [...], structuredContent: ... }` from `execute`

6. **Test from console**:
   ```js
   const tools = navigator.modelContextTesting.listTools();
   const result = await navigator.modelContextTesting.executeTool('tool_name', '{}');
   ```

7. **Connect to desktop agent** (optional):
   - Add `embed.js` script to your page
   - Configure local relay in your MCP client
   - Verify with `webmcp_list_sources`

### Build a tool with React

1. **Install packages**:
   ```bash
   npm install @mcp-b/react-webmcp @mcp-b/global zod
   ```

2. **Import runtime** in your app root:
   ```ts
   import '@mcp-b/global';
   ```

3. **Use the hook in your component**:
   ```tsx
   import { useWebMCP } from '@mcp-b/react-webmcp';
   import { z } from 'zod';

   function SearchTool() {
     const tool = useWebMCP({
       name: 'search',
       description: 'Search products',
       inputSchema: {
         query: z.string(),
         limit: z.number().optional()
       },
       handler: async (input) => {
         return { results: await search(input.query) };
       }
     });

     return <div>Executions: {tool.state.executionCount}</div>;
   }
   ```

4. **Hook handles registration and cleanup** automatically on mount/unmount.

### Debug tools not appearing

1. **Verify runtime is loaded**:
   ```js
   console.log(typeof document.modelContext); // should be 'object'
   ```

2. **List registered tools**:
   ```js
   navigator.modelContextTesting.listTools();
   ```

3. **Check import order**: Polyfill must load before tool registration code.

4. **For desktop relay**: Confirm `embed.js` loaded and relay process is running.

5. **Use Chrome DevTools MCP**: Ask agent to run `debug-webmcp` prompt with your page URL.

## Common gotchas

- **Polyfill import order**: `import '@mcp-b/global'` must run before any `registerTool()` calls. Move it to the top of your entry file.

- **Duplicate tool names**: Calling `registerTool` with a name that already exists throws an error. Use unique names or abort the previous registration signal before re-registering.

- **Missing `type: 'object'` in inputSchema**: JSON Schema at the top level must have `type: 'object'`. Schemas without it fail validation.

- **Forgetting to return both `content` and `structuredContent`**: Always return `{ content: [...], structuredContent: ... }`. If you omit `content`, the runtime wraps the structured data in a text block.

- **Tools registering after agent queries**: If tools register asynchronously (after a fetch or user action), the agent may have already queried and found nothing. Register tools as early as possible, or emit `toolchange` events when tools become available.

- **Origin mismatch in transports**: When using `TabServerTransport` or iframe transports, `targetOrigin` and `allowedOrigins` must match exactly. Using `"*"` disables origin checking and is only safe during development.

- **Chrome flags not enabled for native API**: If testing the native browser API without the polyfill, enable `chrome://flags#enable-experimental-web-platform-features` and relaunch Chrome.

- **Confusing strict core vs. MCP-B extensions**: The polyfill gives you `registerTool`, `getTools`, `executeTool` only. Prompts, resources, `callTool`, `listTools`, and transports require `@mcp-b/global`.

- **Forgetting to handle errors**: Return `{ content: [...], isError: true }` instead of throwing. This gives agents a structured signal to retry or adjust.

## Verification checklist

Before submitting work:

- [ ] Runtime is imported at the top of your entry point (before tool registration)
- [ ] Each tool has a unique, action-oriented name (e.g., `search_products`, not `tool1`)
- [ ] `inputSchema` has `type: 'object'` at the top level
- [ ] All required properties are listed in `required` array
- [ ] Tool `execute` function returns `{ content: [...], structuredContent: ... }`
- [ ] Tools are registered before the agent queries them (or `toolchange` events are emitted)
- [ ] Tested from console: `navigator.modelContextTesting.listTools()` shows your tools
- [ ] Tested from console: `navigator.modelContextTesting.executeTool('name', '{}')` executes without error
- [ ] For React: Hook is used in a component that mounts before agent discovery
- [ ] For desktop relay: `embed.js` is loaded and relay process is running
- [ ] For desktop relay: `webmcp_list_sources` shows your page connected
- [ ] Error paths return `{ content: [...], isError: true }` instead of throwing

## Resources

**Comprehensive navigation:** https://docs.mcp-b.ai/llms.txt

**Critical pages:**
- [Choose a Runtime](/how-to/choose-runtime) — Decide which package layer you need
- [Add Tools to an Existing App](/how-to/add-tools-to-an-existing-app) — Core pattern for exposing app functionality
- [Use Schemas and Structured Output](/how-to/use-schemas-and-structured-output) — Input/output schema patterns and type inference
- [Connect Desktop Agents with Local Relay](/how-to/connect-desktop-agents-with-local-relay) — Bridge tools to Claude Desktop or Cursor
- [Debug and Troubleshoot](/how-to/debug-and-troubleshoot) — Resolve common registration and discovery issues

---

> For additional documentation and navigation, see: https://docs.mcp-b.ai/llms.txt