> ## Documentation Index
> Fetch the complete documentation index at: https://mcp-b-sync-npm-packages-docs-bf03420.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# @mcp-b/global

> W3C Web Model Context API polyfill implementing navigator.modelContext. Turn JavaScript functions into AI-accessible tools with registerTool() for browser-based agent integration.

This package implements the W3C Web Model Context API specification, making `navigator.modelContext` available in your site. Instead of creating complex installation steps, it works out of the box with automatic detection of whether your app is running standalone or embedded in an iframe.

<Info>
  **Quick Start**: Use `registerTool()` to add tools. It's simple, automatic, and works everywhere.
</Info>

## Prerequisites

* **Modern browser** supporting ES2020+ (Chrome, Edge, Firefox, Safari)
* **[MCP-B Extension](https://chromewebstore.google.com/detail/mcp-b-extension/daohopfhkdelnpemnhlekblhnikhdhfa)** for testing tools
* **Node.js 18+** and package manager (for NPM method) OR basic HTML knowledge (for script tag method)

## Installation

### Via IIFE Script Tag (Easiest - No Build Required)

The **IIFE (Immediately Invoked Function Expression)** version bundles everything into a single file and auto-initializes when loaded. Perfect for simple HTML pages or prototyping.

Add the script to your HTML `<head>`:

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <!-- IIFE version - bundles all dependencies, auto-initializes -->
  <script src="https://unpkg.com/@mcp-b/global@latest/dist/index.iife.js"></script>
</head>
<body>
  <h1>My AI-Powered App</h1>

  <script>
    // window.navigator.modelContext is already available!
    // Register tools for AI agents (recommended approach)
    window.navigator.modelContext.registerTool({
      name: "get-page-title",
      description: "Get the current page title",
      inputSchema: {
        type: "object",
        properties: {}
      },
      async execute() {
        return {
          content: [{
            type: "text",
            text: document.title
          }]
        };
      }
    });
  </script>
</body>
</html>
```

**What you get:**

* ✅ **Self-contained** - All dependencies bundled (285KB minified)
* ✅ **Auto-initializes** - `window.navigator.modelContext` ready immediately
* ✅ **No build step** - Just drop it in your HTML
* ✅ **Works everywhere** - Compatible with all modern browsers
* ✅ **Global access** - Also exposes `window.WebMCP` for advanced usage

### Via NPM

For applications using a bundler (Vite, Webpack, etc.):

```bash theme={null}
npm install @mcp-b/global
```

```javascript theme={null}
import '@mcp-b/global';

// Register individual tools (recommended)
navigator.modelContext.registerTool({
  name: "my_tool",
  description: "Tool description",
  inputSchema: { type: "object", properties: {} },
  async execute(args) {
    return {
      content: [{ type: "text", text: "Result" }]
    };
  }
});
```

## Overview

This package implements the [W3C Web Model Context API](https://github.com/webmachinelearning/webmcp) specification, adding `navigator.modelContext` to your website. Your JavaScript functions become tools that AI agents can discover and call.

**Key Features:**

* **Automatic dual-server mode** - Tools accessible from both same-window clients AND parent pages (when in iframe)
* **Zero configuration** - Works out of the box, detects iframe context automatically
* **Production-ready** - Used in [real-world examples](/examples) like the TicTacToe mini-app

## Tool Registration

### The Default: `registerTool()`

For 99% of use cases, use `registerTool()` to add tools one at a time:

```javascript theme={null}
const registration = navigator.modelContext.registerTool({
  name: "add_to_cart",
  description: "Add a product to the shopping cart",
  inputSchema: {
    type: "object",
    properties: {
      productId: { type: "string" },
      quantity: { type: "number" }
    }
  },
  async execute({ productId, quantity }) {
    await addToCart(productId, quantity);
    return { content: [{ type: "text", text: `Added ${quantity} items` }] };
  }
});

// Optional: Unregister later
registration.unregister();
```

**Why this works great:**

* ✅ Simple and intuitive
* ✅ Automatic cleanup with `unregister()`
* ✅ Perfect for React/Vue component-scoped tools
* ✅ No need to worry about tool lifecycle management

<Accordion title="Advanced: provideContext() for base tools">
  Only use `provideContext()` when you need to define application-level base tools:

  ```javascript theme={null}
  navigator.modelContext.provideContext({
    tools: [
      {
        name: "app_info",
        description: "Get app information",
        inputSchema: { type: "object", properties: {} },
        async execute() {
          return { content: [{ type: "text", text: "App v1.0.0" }] };
        }
      }
    ]
  });
  ```

  **Important:** `provideContext()` replaces all base tools each time it's called. Most developers should use `registerTool()` instead.

  See [Two-Bucket Tool Management](#two-bucket-tool-management) below for details on how these work together.
</Accordion>

<Accordion title="Implementation Detail: Two-Bucket Tool Management">
  WebMCP uses a two-bucket system: base tools (via `provideContext()`) and dynamic tools (via `registerTool()`). Dynamic tools persist independently, making them perfect for component lifecycle management. See [Tool Registration](/concepts/tool-registration) for details.
</Accordion>

## API Reference

### `navigator.modelContext.registerTool(tool)` - Recommended

Register a single tool dynamically. This is the **recommended approach** for most use cases.

**Parameters:**

* `tool` - A single tool descriptor

**Returns:**

* Object with `unregister()` function to remove the tool

**Benefits:**

* ✅ Persist across `provideContext()` calls
* ✅ Perfect for component lifecycle management
* ✅ Fine-grained control over individual tools
* ✅ Can be unregistered when no longer needed

**Example:**

```javascript theme={null}
// Register a tool (recommended approach)
const registration = navigator.modelContext.registerTool({
  name: "add-todo",
  description: "Add a new todo item to the list",
  inputSchema: {
    type: "object",
    properties: {
      text: {
        type: "string",
        description: "The todo item text"
      },
      priority: {
        type: "string",
        enum: ["low", "medium", "high"],
        description: "Priority level"
      }
    },
    required: ["text"]
  },
  async execute({ text, priority = "medium" }) {
    const todo = addTodoItem(text, priority);
    return {
      content: [{
        type: "text",
        text: `Added todo: "${text}" with ${priority} priority`
      }]
    };
  }
});

// Later, unregister the tool if needed
registration.unregister();
```

### `navigator.modelContext.provideContext(context)` - Use Sparingly

Register base/app-level tools. **Use sparingly** - only for top-level base tools.

**Parameters:**

* `context.tools` - Array of tool descriptors

**Warning:** This replaces all base tools each time it's called. Tools registered via `registerTool()` are NOT affected.

**Example:**

```javascript theme={null}
// Only use for top-level base tools
navigator.modelContext.provideContext({
  tools: [
    {
      name: "app-info",
      description: "Get application information",
      inputSchema: { type: "object", properties: {} },
      async execute() {
        return {
          content: [{
            type: "text",
            text: JSON.stringify({ name: "MyApp", version: "1.0.0" })
          }]
        };
      }
    }
  ]
});
```

### Tool Descriptor

Each tool must have:

| Property      | Type       | Description                                        |
| ------------- | ---------- | -------------------------------------------------- |
| `name`        | `string`   | Unique identifier for the tool                     |
| `description` | `string`   | Natural language description of what the tool does |
| `inputSchema` | `object`   | JSON Schema defining input parameters              |
| `execute`     | `function` | Async function that implements the tool logic      |

### Tool Response Format

Tools must return an object with:

```typescript theme={null}
{
  content: [
    {
      type: "text",      // or "image", "resource"
      text: "Result..."  // the response content
    }
  ],
  isError?: boolean     // optional error flag
}
```

## Complete Examples

### Simple Todo Example

```javascript theme={null}
let todos = [];

navigator.modelContext.registerTool({
  name: "add-todo",
  description: "Add a new todo item",
  inputSchema: {
    type: "object",
    properties: {
      text: { type: "string" }
    },
    required: ["text"]
  },
  async execute({ text }) {
    todos.push({ id: Date.now(), text, done: false });
    return {
      content: [{ type: "text", text: `Added: "${text}"` }]
    };
  }
});
```

For more examples, see the [Examples page](/examples).

### Dynamic Tool Registration (Component Lifecycle)

Perfect for managing tools tied to component lifecycle:

```javascript theme={null}
import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // Register component-specific tool when component mounts (Bucket B)
    const registration = window.navigator.modelContext.registerTool({
      name: "component-action",
      description: "Action specific to this component",
      inputSchema: { type: "object", properties: {} },
      async execute() {
        // Access component state/methods here
        return {
          content: [{ type: "text", text: "Component action executed!" }]
        };
      }
    });

    // Cleanup: unregister when component unmounts
    return () => {
      registration.unregister();
    };
  }, []);

  return <div>My Component</div>;
}
```

### Tool Persistence Example

```javascript theme={null}
// Base tools via provideContext()
navigator.modelContext.provideContext({
  tools: [{ name: "app-info", description: "App info", inputSchema: {}, async execute() {} }]
});

// Dynamic tool via registerTool() - persists independently
const reg = navigator.modelContext.registerTool({
  name: "component-action",
  description: "Component action",
  inputSchema: { type: "object", properties: {} },
  async execute() {
    return { content: [{ type: "text", text: "Done!" }] };
  }
});

// Later: unregister when no longer needed
reg.unregister();
```

## Event-Based Tool Calls (Advanced)

For manifest-based or advanced scenarios, you can handle tool calls as events:

```javascript theme={null}
window.navigator.modelContext.addEventListener('toolcall', async (event) => {
  console.log(`Tool called: ${event.name}`, event.arguments);

  if (event.name === "custom-tool") {
    // Prevent default execution
    event.preventDefault();

    // Provide custom response
    event.respondWith({
      content: [{
        type: "text",
        text: "Custom response from event handler"
      }]
    });
  }

  // If not prevented, the tool's execute function will run normally
});
```

## Advanced Configuration

### Dual-Server Mode (Tab + Iframe)

By default, `@mcp-b/global` runs **two MCP servers** that share the same tool registry:

1. **Tab Server** (`TabServerTransport`) - For same-window communication (e.g., browser extensions)
2. **Iframe Server** (`IframeChildTransport`) - Auto-enabled when running in an iframe (`window.parent !== window`)

Both servers expose the same tools, allowing your tools to be accessed from:

* Same-window clients (e.g., browser extension content scripts)
* Parent pages (when your app runs in an iframe)

<Info>
  This dual-server architecture is **automatic** - no configuration needed for basic usage. The package detects when it's running in an iframe and enables both servers automatically.
</Info>

### How It Works

When you register tools via `registerTool()` or `provideContext()`, they become available on **both servers simultaneously**:

```typescript theme={null}
import '@mcp-b/global';

// Register a tool - automatically available on both servers!
navigator.modelContext.registerTool({
  name: "get_data",
  description: "Get application data",
  inputSchema: { type: "object", properties: {} },
  async execute() {
    return {
      content: [{ type: "text", text: "Data from iframe!" }]
    };
  }
});

// This tool is now accessible via:
// 1. TabServerTransport (same-window clients)
// 2. IframeChildTransport (parent page via IframeParentTransport)
```

### Usage in Iframes

When your application runs inside an iframe (like in the [MCP-UI integration pattern](/concepts/mcp-ui-integration)), the iframe server automatically enables:

**In the iframe (your app):**

```typescript theme={null}
import { initializeWebModelContext } from '@mcp-b/global';

// Initialize with default dual-server mode
initializeWebModelContext({
  transport: {
    tabServer: {
      allowedOrigins: ['*'], // Allow connections from same window
    },
    // iframeServer auto-enabled when window.parent !== window
  },
});

// Now register your tools
navigator.modelContext.registerTool({
  name: "tictactoe_get_state",
  description: "Get current game state",
  inputSchema: { type: "object", properties: {} },
  async execute() {
    // Your game logic here
    return {
      content: [{ type: "text", text: "Game state: X's turn" }]
    };
  }
});
```

**In the parent page:**

```typescript theme={null}
import { IframeParentTransport } from '@mcp-b/transports';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';

const iframe = document.querySelector('iframe');

// Connect to iframe's MCP server
const client = new Client({ name: 'parent', version: '1.0.0' });
const transport = new IframeParentTransport({
  iframe: iframe,
  targetOrigin: 'https://iframe-app.com',
});

await client.connect(transport);

// Discover tools from iframe
const { tools } = await client.listTools();
console.log('Tools from iframe:', tools);
// Output: [{ name: 'tictactoe_get_state', ... }]
```

### Configuration Options

Use `initializeWebModelContext(options)` to customize transport behavior:

```typescript theme={null}
import { initializeWebModelContext } from '@mcp-b/global';

initializeWebModelContext({
  transport: {
    // Tab server options (for same-window communication)
    tabServer: {
      allowedOrigins: ['https://your-app.com'],
      channelId: 'custom-channel', // Default: 'mcp-tab'
    },

    // Iframe server options (for parent-child communication)
    iframeServer: {
      allowedOrigins: ['https://parent-app.com'], // Only allow specific parent
      channelId: 'custom-iframe-channel', // Default: 'mcp-iframe'
    },
  },
});
```

**Disable Tab Server (iframe-only mode):**

```typescript theme={null}
initializeWebModelContext({
  transport: {
    tabServer: false, // Disable tab server
    iframeServer: {
      allowedOrigins: ['https://parent-app.com'],
    },
  },
});
```

**Disable Iframe Server (tab-only mode):**

```typescript theme={null}
initializeWebModelContext({
  transport: {
    tabServer: {
      allowedOrigins: ['*'],
    },
    iframeServer: false, // Disable iframe server
  },
});
```

**Custom Transport (advanced):**

```typescript theme={null}
import { CustomTransport } from './my-transport';

initializeWebModelContext({
  transport: {
    create: () => new CustomTransport(), // Replaces both servers
  },
});
```

### Data Attribute Configuration

When using the IIFE script tag, configure via data attributes:

```html theme={null}
<script
  src="https://unpkg.com/@mcp-b/global@latest/dist/index.iife.js"
  data-webmcp-allowed-origins="https://trusted-parent.com"
  data-webmcp-channel-id="my-channel"
></script>
```

Or use JSON for advanced configuration:

```html theme={null}
<script
  src="https://unpkg.com/@mcp-b/global@latest/dist/index.iife.js"
  data-webmcp-options='{"transport":{"iframeServer":{"allowedOrigins":["https://parent.com"]}}}'
></script>
```

### Real-World Example: TicTacToe Mini-App

The [TicTacToe example](/examples) demonstrates dual-server mode in production:

```typescript theme={null}
// mini-apps/tictactoe/main.tsx
import { initializeWebModelContext } from '@mcp-b/global';
import { TicTacToeWithWebMCP } from './TicTacToeWithWebMCP';

// CRITICAL: Initialize BEFORE rendering React
initializeWebModelContext({
  transport: {
    tabServer: {
      allowedOrigins: ['*'], // Allow parent to connect
    },
    // iframeServer auto-enabled when in iframe
  },
});

// Render app
createRoot(document.getElementById('root')!).render(
  <TicTacToeWithWebMCP />
);
```

The game component registers three tools that become available to both:

* **Tab clients** (browser extensions in the same window)
* **Parent page** (chat UI via IframeParentTransport)

See the [complete TicTacToe example](https://github.com/WebMCP-org/mcp-ui-webmcp) in the mcp-ui-webmcp repository for the full implementation.

### Security Best Practices

<Warning>
  **Production Security:**

  * **Never use `allowedOrigins: ['*']` in production** for iframe server
  * Always specify explicit parent origins: `allowedOrigins: ['https://trusted-parent.com']`
  * Tab server can use `['*']` for same-window clients (less risky)
  * Validate all tool inputs regardless of origin
</Warning>

```typescript theme={null}
// ✅ Good - Explicit origins for iframe server
initializeWebModelContext({
  transport: {
    tabServer: {
      allowedOrigins: ['*'], // OK for same-window
    },
    iframeServer: {
      allowedOrigins: ['https://parent-app.com'], // Explicit for cross-origin
    },
  },
});

// ❌ Bad - Wildcard for iframe server
initializeWebModelContext({
  transport: {
    iframeServer: {
      allowedOrigins: ['*'], // DANGER: Any parent can connect!
    },
  },
});
```

## Feature Detection

Check if the API is available:

```javascript theme={null}
if ("modelContext" in navigator) {
  // API is available
  navigator.modelContext.provideContext({ tools: [...] });
} else {
  console.warn("Web Model Context API not available");
}
```

## Debugging

In development mode, access the internal bridge:

```javascript theme={null}
if (window.__mcpBridge) {
  console.log("MCP Server:", window.__mcpBridge.server);
  console.log("Registered tools:", window.__mcpBridge.tools);
}
```

## What's Included

* **Web Model Context API** - Standard `window.navigator.modelContext` interface
* **Dynamic Tool Registration** - `registerTool()` with `unregister()` function
* **MCP Bridge** - Automatic bridging to Model Context Protocol
* **Dual-Server Mode** - Tab + Iframe servers sharing the same tool registry
* **Tab Transport** - Communication layer for same-window contexts
* **Iframe Transport** - Cross-origin parent-child communication (auto-enabled in iframes)
* **Event System** - Hybrid tool call handling
* **TypeScript Types** - Full type definitions included

## Security Considerations

### Tool Validation

Always validate inputs in your tool implementations:

```javascript theme={null}
{
  name: "delete-item",
  description: "Delete an item",
  inputSchema: {
    type: "object",
    properties: {
      id: { type: "string", pattern: "^[a-zA-Z0-9]+$" }
    },
    required: ["id"]
  },
  async execute({ id }) {
    // Additional validation
    if (!isValidId(id)) {
      return {
        content: [{ type: "text", text: "Invalid ID" }],
        isError: true
      };
    }

    // Proceed with deletion
    await deleteItem(id);
    return {
      content: [{ type: "text", text: "Item deleted" }]
    };
  }
}
```

## Related Documentation

<CardGroup cols={2}>
  <Card title="@mcp-b/react-webmcp" icon="react" href="/packages/react-webmcp">
    React hooks with automatic lifecycle
  </Card>

  <Card title="@mcp-b/transports" icon="arrows-left-right" href="/packages/transports">
    Transport layer implementation
  </Card>

  <Card title="Core Concepts" icon="diagram-project" href="/concepts/overview">
    Two-bucket tool management
  </Card>

  <Card title="Security Guide" icon="shield-halved" href="/security">
    Tool security best practices
  </Card>

  <Card title="Quick Start" icon="rocket" href="/quickstart">
    Get started guide
  </Card>

  <Card title="Examples" icon="code" href="/examples">
    Working implementations
  </Card>
</CardGroup>

## External Resources

* [@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk) - Official MCP SDK
* [Web Model Context API Explainer](https://github.com/webmachinelearning/webmcp) - W3C proposal
* [Model Context Protocol Spec](https://modelcontextprotocol.io/) - Protocol specification
* [Microsoft Edge Explainer](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/WebModelContext/explainer.md) - Browser integration

## License

MIT - see [LICENSE](https://github.com/WebMCP-org/npm-packages/blob/main/LICENSE) for details

## Support

* [GitHub Issues](https://github.com/WebMCP-org/npm-packages/issues)
* [Discord Community](https://discord.gg/a9fBR6Bw)
