@mcp-b/global 1.0.13 → 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,429 +1,658 @@
1
1
  # @mcp-b/global
2
2
 
3
+ > Web Model Context API polyfill - Implement `window.navigator.modelContext` for AI-powered web applications
4
+
3
5
  [![npm version](https://img.shields.io/npm/v/@mcp-b/global?style=flat-square)](https://www.npmjs.com/package/@mcp-b/global)
4
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
5
7
 
6
- **Empower your website with AI capabilities using a single script tag!**
7
-
8
- The `@mcp-b/global` package offers the easiest way to integrate MCP-B (Model Context Protocol for Browsers) into any website. It requires no build tools or complex configuration—just add a script tag to expose AI tools that leverage your site's existing functionality.
9
-
10
- ## ✨ Features
11
-
12
- - 🚀 **Zero-Config Setup**: Works instantly in any modern browser.
13
- - 🏷️ **Script Tag Integration**: Ideal for CDN deployment via unpkg or similar services.
14
- - 🔧 **Global API Exposure**: Automatically creates `window.mcp` upon loading.
15
- - 📦 **Multi-Format Support**: Compatible with ESM, CommonJS, and UMD.
16
- - 🎯 **TypeScript-Ready**: Includes comprehensive type definitions.
17
- - 🌐 **Framework-Agnostic**: Seamlessly integrates with vanilla JS, React, Vue, Angular, or any other framework.
8
+ This package implements the [W3C Web Model Context API](https://github.com/webmachinelearning/webmcp) (`window.navigator.modelContext`) specification, bridging it to the Model Context Protocol (MCP) SDK. It allows web developers to expose JavaScript functions as "tools" that AI agents can discover and invoke.
18
9
 
19
10
  ## 🚀 Quick Start
20
11
 
21
- ### Option 1: Script Tag (Easiest)
12
+ ### Via IIFE Script Tag (Easiest - No Build Required)
13
+
14
+ 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.
22
15
 
23
- Add this to your HTML for instant integration:
16
+ Add the script to your HTML `<head>`:
24
17
 
25
18
  ```html
26
19
  <!DOCTYPE html>
27
- <html lang="en">
28
- <head>
29
- <title>My AI-Enabled Site</title>
30
- </head>
31
- <body>
32
- <h1>Welcome</h1>
33
-
34
- <!-- Load MCP-B via CDN -->
35
- <script src="https://unpkg.com/@mcp-b/global@latest"></script>
36
-
37
- <!-- Your custom script -->
38
- <script>
39
- // Wait for MCP to initialize
40
- function initMCP() {
41
- if (!window.mcp?.registerTool) {
42
- return setTimeout(initMCP, 100);
43
- }
44
-
45
- // Register a simple tool
46
- window.mcp.registerTool(
47
- "getPageDetails",
48
- {
49
- title: "Retrieve Page Details",
50
- description: "Fetches information about the current webpage",
20
+ <html>
21
+ <head>
22
+ <!-- IIFE version - bundles all dependencies, auto-initializes -->
23
+ <script src="https://unpkg.com/@mcp-b/global@latest/dist/index.iife.js"></script>
24
+ </head>
25
+ <body>
26
+ <h1>My AI-Powered App</h1>
27
+
28
+ <script>
29
+ // window.navigator.modelContext is already available!
30
+ // Register tools with AI agents
31
+ window.navigator.modelContext.provideContext({
32
+ tools: [
33
+ {
34
+ name: "get-page-title",
35
+ description: "Get the current page title",
36
+ inputSchema: {
37
+ type: "object",
38
+ properties: {}
51
39
  },
52
- async () => {
40
+ async execute() {
53
41
  return {
54
- content: [
55
- {
56
- type: "text",
57
- text: JSON.stringify({
58
- title: document.title,
59
- url: window.location.href,
60
- timestamp: new Date().toISOString(),
61
- }),
62
- },
63
- ],
42
+ content: [{
43
+ type: "text",
44
+ text: document.title
45
+ }]
64
46
  };
65
47
  }
66
- );
48
+ }
49
+ ]
50
+ });
51
+ </script>
52
+ </body>
53
+ </html>
54
+ ```
67
55
 
68
- console.log("AI tools initialized!");
69
- }
56
+ **What you get:**
57
+ - ✅ **Self-contained** - All dependencies bundled (285KB minified)
58
+ - ✅ **Auto-initializes** - `window.navigator.modelContext` ready immediately
59
+ - ✅ **No build step** - Just drop it in your HTML
60
+ - ✅ **Works everywhere** - Compatible with all modern browsers
61
+ - ✅ **Global access** - Also exposes `window.WebMCP` for advanced usage
62
+
63
+ ### Via ES Module Script Tag
70
64
 
71
- // Run on page load
72
- document.addEventListener("DOMContentLoaded", initMCP);
73
- </script>
74
- </body>
65
+ If you prefer ES modules and have a build system, use the ESM version:
66
+
67
+ ```html
68
+ <!DOCTYPE html>
69
+ <html>
70
+ <head>
71
+ <!-- ESM version - smaller but requires module support -->
72
+ <script type="module">
73
+ import '@mcp-b/global';
74
+
75
+ // window.navigator.modelContext is now available
76
+ window.navigator.modelContext.provideContext({
77
+ tools: [/* your tools */]
78
+ });
79
+ </script>
80
+ </head>
81
+ <body>
82
+ <h1>My AI-Powered App</h1>
83
+ </body>
75
84
  </html>
76
85
  ```
77
86
 
78
- ### Option 2: NPM Installation (For Advanced Control)
87
+ **Note:** The ESM version is smaller (~16KB) but doesn't bundle dependencies - it expects them to be available via your module system or CDN.
88
+
89
+ ### Via NPM
79
90
 
80
- For projects using module bundlers or TypeScript:
91
+ For applications using a bundler (Vite, Webpack, etc.):
81
92
 
82
93
  ```bash
83
- npm install @mcp-b/global zod
94
+ npm install @mcp-b/global
84
95
  ```
85
96
 
86
- ```typescript
87
- import { initializeGlobalMCP } from "@mcp-b/global";
88
- import { z } from "zod";
97
+ ```javascript
98
+ import '@mcp-b/global';
89
99
 
90
- // Initialize the global MCP instance
91
- initializeGlobalMCP();
100
+ // window.navigator.modelContext is now available
101
+ window.navigator.modelContext.provideContext({
102
+ tools: [/* your tools */]
103
+ });
104
+ ```
92
105
 
93
- // Wait for readiness and register tools
94
- function initMCP() {
95
- if (!window.mcp?.registerTool) {
96
- return setTimeout(initMCP, 100);
97
- }
106
+ ## 📖 API Reference
98
107
 
99
- window.mcp.registerTool(
100
- "processMessage",
101
- {
102
- title: "Process User Message",
103
- description: "Handles and responds to a message",
104
- inputSchema: {
105
- message: z.string().describe("The message to process"),
106
- },
107
- },
108
- async ({ message }) => {
109
- return {
110
- content: [{ type: "text", text: `Processed: ${message}` }],
111
- };
112
- }
113
- );
114
- }
108
+ ### Two-Bucket Tool Management System
115
109
 
116
- initMCP();
117
- ```
110
+ This package uses a **two-bucket system** for tool management to support both app-level and component-level tools:
118
111
 
119
- ## 🛠️ API Reference
112
+ - **Bucket A (Base Tools)**: Registered via `provideContext()` - represents your app's core functionality
113
+ - **Bucket B (Dynamic Tools)**: Registered via `registerTool()` - component-scoped tools that persist across `provideContext()` calls
120
114
 
121
- ### Global Interface
115
+ **Key behaviors:**
116
+ - ✅ `provideContext()` only clears Bucket A, leaving Bucket B intact
117
+ - ✅ `registerTool()` adds to Bucket B and persists across `provideContext()` calls
118
+ - ✅ Tool name collisions between buckets throw an error
119
+ - ✅ Cannot `unregister()` a tool that was registered via `provideContext()`
122
120
 
123
- Loading the package attaches `mcp` to the window object:
121
+ **Use case:** React components can use `registerTool()` in `useEffect()` to manage tool lifecycle independently of the app's base tools.
124
122
 
125
- ```typescript
126
- interface Window {
127
- mcp: McpServer; // MCP server instance for tool registration
128
- }
123
+ ### `window.navigator.modelContext.provideContext(context)`
124
+
125
+ Register base/app-level tools (Bucket A). **This clears Bucket A only** and replaces with the provided array. Dynamic tools (Bucket B) registered via `registerTool()` are NOT affected.
126
+
127
+ **Parameters:**
128
+ - `context.tools` - Array of tool descriptors
129
+
130
+ **Example:**
131
+
132
+ ```javascript
133
+ window.navigator.modelContext.provideContext({
134
+ tools: [
135
+ {
136
+ name: "add-todo",
137
+ description: "Add a new todo item to the list",
138
+ inputSchema: {
139
+ type: "object",
140
+ properties: {
141
+ text: {
142
+ type: "string",
143
+ description: "The todo item text"
144
+ },
145
+ priority: {
146
+ type: "string",
147
+ enum: ["low", "medium", "high"],
148
+ description: "Priority level"
149
+ }
150
+ },
151
+ required: ["text"]
152
+ },
153
+ async execute({ text, priority = "medium" }) {
154
+ // Add todo to your app
155
+ const todo = addTodoItem(text, priority);
156
+
157
+ return {
158
+ content: [{
159
+ type: "text",
160
+ text: `Added todo: "${text}" with ${priority} priority`
161
+ }]
162
+ };
163
+ }
164
+ }
165
+ ]
166
+ });
129
167
  ```
130
168
 
131
- ### Key Methods
169
+ ### `window.navigator.modelContext.registerTool(tool)`
132
170
 
133
- #### `window.mcp.registerTool(name, config, handler)`
171
+ Register a single tool dynamically (Bucket B). Tools registered this way:
172
+ - ✅ Persist across `provideContext()` calls
173
+ - ✅ Perfect for component lifecycle management
174
+ - ✅ Can be unregistered via the returned `unregister()` function
175
+ - ❌ Cannot have the same name as a tool in Bucket A (provideContext)
134
176
 
135
- Registers an AI-callable tool.
177
+ **Parameters:**
178
+ - `tool` - A single tool descriptor
136
179
 
137
- - **name**: Unique tool identifier (string).
138
- - **config**: Object with `title` (string), `description` (string), and optional `inputSchema` (Zod schema for inputs).
139
- - **handler**: Async function that executes the tool logic and returns `{ content: [{ type: 'text', text: string }] }`.
180
+ **Returns:**
181
+ - Object with `unregister()` function to remove the tool
140
182
 
141
- Example:
183
+ **Example:**
142
184
 
143
- ```typescript
144
- import { z } from "zod";
145
-
146
- window.mcp.registerTool(
147
- "echoInput",
148
- {
149
- title: "Echo Tool",
150
- description: "Echoes the provided input",
151
- inputSchema: { input: z.string() },
185
+ ```javascript
186
+ // Register a tool dynamically (Bucket B)
187
+ const registration = window.navigator.modelContext.registerTool({
188
+ name: "get-timestamp",
189
+ description: "Get the current timestamp",
190
+ inputSchema: {
191
+ type: "object",
192
+ properties: {}
152
193
  },
153
- async ({ input }) => {
154
- return { content: [{ type: "text", text: `Echo: ${input}` }] };
194
+ async execute() {
195
+ return {
196
+ content: [{
197
+ type: "text",
198
+ text: new Date().toISOString()
199
+ }]
200
+ };
155
201
  }
156
- );
157
- ```
202
+ });
203
+
204
+ // Later, unregister the tool
205
+ registration.unregister();
158
206
 
159
- #### `initializeGlobalMCP()` (Optional)
207
+ // Note: You can call provideContext() and this tool will still be registered!
208
+ window.navigator.modelContext.provideContext({
209
+ tools: [/* other tools */]
210
+ });
211
+ // "get-timestamp" is still available because it's in Bucket B
212
+ ```
160
213
 
161
- Manually initializes the global MCP instance (automatic in script tag mode).
214
+ ### Tool Descriptor
162
215
 
163
- #### `cleanupGlobalMCP()` (Optional)
216
+ Each tool must have:
164
217
 
165
- Cleans up the global instance, useful for testing or single-page apps.
218
+ | Property | Type | Description |
219
+ |----------|------|-------------|
220
+ | `name` | `string` | Unique identifier for the tool |
221
+ | `description` | `string` | Natural language description of what the tool does |
222
+ | `inputSchema` | `object` | JSON Schema defining input parameters |
223
+ | `execute` | `function` | Async function that implements the tool logic |
166
224
 
167
- ### TypeScript Integration
225
+ ### Tool Response Format
168
226
 
169
- Import types for full autocompletion:
227
+ Tools must return an object with:
170
228
 
171
229
  ```typescript
172
- import "@mcp-b/global"; // Augments Window interface
173
-
174
- window.mcp.registerTool(
175
- "mathOperation",
176
- {
177
- title: "Perform Math",
178
- description: "Basic arithmetic",
179
- inputSchema: { num1: z.number(), num2: z.number() },
180
- },
181
- async ({ num1, num2 }) => {
182
- return { content: [{ type: "text", text: `${num1 + num2}` }] };
183
- }
184
- );
230
+ {
231
+ content: [
232
+ {
233
+ type: "text", // or "image", "resource"
234
+ text: "Result..." // the response content
235
+ }
236
+ ],
237
+ isError?: boolean // optional error flag
238
+ }
185
239
  ```
186
240
 
187
- ## 📖 Full Example: AI-Powered Todo App
241
+ ## 🎯 Complete Examples
188
242
 
189
- This complete HTML file creates a todo list with AI tools for adding, viewing, and deleting items:
243
+ ### Todo List Application
190
244
 
191
- ```html
192
- <!DOCTYPE html>
193
- <html lang="en">
194
- <head>
195
- <meta charset="UTF-8" />
196
- <title>AI Todo List</title>
197
- <style>
198
- body {
199
- font-family: sans-serif;
200
- max-width: 600px;
201
- margin: 2rem auto;
202
- padding: 1rem;
203
- }
204
- .todo {
205
- padding: 0.5rem;
206
- margin: 0.25rem 0;
207
- background: #f8f9fa;
208
- border-radius: 0.25rem;
209
- }
210
- .ai-feedback {
211
- background: #d4edda;
212
- color: #155724;
213
- padding: 0.75rem;
214
- border-radius: 0.5rem;
215
- margin: 0.5rem 0;
245
+ ```javascript
246
+ let todos = [];
247
+
248
+ window.navigator.modelContext.provideContext({
249
+ tools: [
250
+ {
251
+ name: "add-todo",
252
+ description: "Add a new todo item",
253
+ inputSchema: {
254
+ type: "object",
255
+ properties: {
256
+ text: { type: "string", description: "Todo text" }
257
+ },
258
+ required: ["text"]
259
+ },
260
+ async execute({ text }) {
261
+ const todo = { id: Date.now(), text, done: false };
262
+ todos.push(todo);
263
+ updateUI();
264
+ return {
265
+ content: [{ type: "text", text: `Added: "${text}"` }]
266
+ };
216
267
  }
217
- </style>
218
- </head>
219
- <body>
220
- <h1>AI-Enabled Todo List</h1>
221
- <div id="status">Initializing AI...</div>
222
- <div id="todos"></div>
223
-
224
- <!-- MCP-B Script -->
225
- <script src="https://unpkg.com/@mcp-b/global@latest"></script>
226
- <!-- Zod for Schemas -->
227
- <script src="https://unpkg.com/zod@latest/lib/index.umd.js"></script>
228
-
229
- <script>
230
- const { z } = window.Zod;
231
- const todos = ["Demo Todo 1", "Demo Todo 2"];
232
-
233
- function showFeedback(message) {
234
- const feedback = document.createElement("div");
235
- feedback.className = "ai-feedback";
236
- feedback.textContent = `AI Action: ${message}`;
237
- document.body.insertBefore(feedback, document.getElementById("todos"));
238
- setTimeout(() => feedback.remove(), 3000);
268
+ },
269
+ {
270
+ name: "list-todos",
271
+ description: "Get all todo items",
272
+ inputSchema: { type: "object", properties: {} },
273
+ async execute() {
274
+ const list = todos.map(t =>
275
+ `${t.done ? '✓' : '○'} ${t.text}`
276
+ ).join('\n');
277
+ return {
278
+ content: [{ type: "text", text: list || "No todos" }]
279
+ };
239
280
  }
240
-
241
- function updateTodos() {
242
- document.getElementById("todos").innerHTML = todos
243
- .map((todo, index) => `<div class="todo">${index + 1}. ${todo}</div>`)
244
- .join("");
281
+ },
282
+ {
283
+ name: "complete-todo",
284
+ description: "Mark a todo as complete",
285
+ inputSchema: {
286
+ type: "object",
287
+ properties: {
288
+ id: { type: "number", description: "Todo ID" }
289
+ },
290
+ required: ["id"]
291
+ },
292
+ async execute({ id }) {
293
+ const todo = todos.find(t => t.id === id);
294
+ if (!todo) {
295
+ return {
296
+ content: [{ type: "text", text: "Todo not found" }],
297
+ isError: true
298
+ };
299
+ }
300
+ todo.done = true;
301
+ updateUI();
302
+ return {
303
+ content: [{ type: "text", text: `Completed: "${todo.text}"` }]
304
+ };
245
305
  }
306
+ }
307
+ ]
308
+ });
246
309
 
247
- function initMCP() {
248
- if (!window.mcp?.registerTool) {
249
- return setTimeout(initMCP, 100);
250
- }
310
+ function updateUI() {
311
+ // Update your UI
312
+ document.getElementById('todo-list').innerHTML =
313
+ todos.map(t => `<li>${t.done ? '✓' : ''} ${t.text}</li>`).join('');
314
+ }
315
+ ```
251
316
 
252
- window.mcp.registerTool(
253
- "addTodoItem",
254
- {
255
- title: "Add Todo",
256
- description: "Adds a new todo item",
257
- inputSchema: { text: z.string().describe("Todo text") },
258
- },
259
- async ({ text }) => {
260
- todos.push(text);
261
- showFeedback(`Added "${text}"`);
262
- updateTodos();
263
- return { content: [{ type: "text", text: `Added: ${text}` }] };
264
- }
265
- );
317
+ ### E-commerce Product Search
266
318
 
267
- window.mcp.registerTool(
268
- "listTodos",
269
- {
270
- title: "List Todos",
271
- description: "Retrieves all todos",
319
+ ```javascript
320
+ window.navigator.modelContext.provideContext({
321
+ tools: [
322
+ {
323
+ name: "search-products",
324
+ description: "Search for products in the catalog",
325
+ inputSchema: {
326
+ type: "object",
327
+ properties: {
328
+ query: {
329
+ type: "string",
330
+ description: "Search query"
272
331
  },
273
- async () => {
274
- showFeedback("Listing todos");
275
- return { content: [{ type: "text", text: JSON.stringify(todos) }] };
276
- }
277
- );
278
-
279
- window.mcp.registerTool(
280
- "removeTodo",
281
- {
282
- title: "Remove Todo",
283
- description: "Deletes a todo by index (1-based)",
284
- inputSchema: { index: z.number().describe("Todo index") },
332
+ category: {
333
+ type: "string",
334
+ description: "Filter by category",
335
+ enum: ["electronics", "clothing", "books", "all"]
285
336
  },
286
- async ({ index }) => {
287
- const i = index - 1;
288
- if (i >= 0 && i < todos.length) {
289
- const removed = todos.splice(i, 1)[0];
290
- showFeedback(`Removed "${removed}"`);
291
- updateTodos();
292
- return {
293
- content: [{ type: "text", text: `Removed: ${removed}` }],
294
- };
295
- }
296
- return {
297
- content: [{ type: "text", text: `Invalid index: ${index}` }],
298
- };
337
+ maxPrice: {
338
+ type: "number",
339
+ description: "Maximum price filter"
299
340
  }
300
- );
301
-
302
- document.getElementById("status").textContent =
303
- "AI Ready! Tools available.";
304
- document.getElementById("status").style.background = "#d4edda";
305
- document.getElementById("status").style.color = "#155724";
306
- document.getElementById("status").style.padding = "0.5rem";
307
- document.getElementById("status").style.borderRadius = "0.25rem";
341
+ },
342
+ required: ["query"]
343
+ },
344
+ async execute({ query, category = "all", maxPrice }) {
345
+ const results = await searchProducts({
346
+ query,
347
+ category: category !== "all" ? category : undefined,
348
+ maxPrice
349
+ });
350
+
351
+ const summary = results.map(p =>
352
+ `${p.name} - $${p.price} (${p.category})`
353
+ ).join('\n');
354
+
355
+ return {
356
+ content: [{
357
+ type: "text",
358
+ text: `Found ${results.length} products:\n${summary}`
359
+ }]
360
+ };
308
361
  }
309
-
310
- document.addEventListener("DOMContentLoaded", () => {
311
- updateTodos();
312
- initMCP();
313
- });
314
- </script>
315
- </body>
316
- </html>
362
+ },
363
+ {
364
+ name: "add-to-cart",
365
+ description: "Add a product to the shopping cart",
366
+ inputSchema: {
367
+ type: "object",
368
+ properties: {
369
+ productId: { type: "string" },
370
+ quantity: { type: "number", default: 1 }
371
+ },
372
+ required: ["productId"]
373
+ },
374
+ async execute({ productId, quantity = 1 }) {
375
+ await addToCart(productId, quantity);
376
+ return {
377
+ content: [{
378
+ type: "text",
379
+ text: `Added ${quantity}x product ${productId} to cart`
380
+ }]
381
+ };
382
+ }
383
+ }
384
+ ]
385
+ });
317
386
  ```
318
387
 
319
- Save as `index.html` and open in a browser with the MCP-B extension installed.
388
+ ## 🔧 Dynamic Tool Registration (Component Lifecycle)
320
389
 
321
- ## 🎯 Getting Started with the Extension
390
+ ### React Component Example
322
391
 
323
- 1. Install the [MCP-B Extension](https://chromewebstore.google.com/detail/mcp-b/daohopfhkdelnpemnhlekblhnikhdhfa) from the Chrome Web Store.
324
- 2. Open your HTML file or site.
325
- 3. Use the extension's chat: Try "Add a todo: Buy milk" or "List all todos".
392
+ Perfect for managing tools tied to component lifecycle:
326
393
 
327
- The AI interacts directly with your site's tools!
394
+ ```javascript
395
+ import { useEffect } from 'react';
396
+
397
+ function MyComponent() {
398
+ useEffect(() => {
399
+ // Register component-specific tool when component mounts (Bucket B)
400
+ const registration = window.navigator.modelContext.registerTool({
401
+ name: "component-action",
402
+ description: "Action specific to this component",
403
+ inputSchema: { type: "object", properties: {} },
404
+ async execute() {
405
+ // Access component state/methods here
406
+ return {
407
+ content: [{ type: "text", text: "Component action executed!" }]
408
+ };
409
+ }
410
+ });
328
411
 
329
- ## 🌟 Use Cases
412
+ // Cleanup: unregister when component unmounts
413
+ return () => {
414
+ registration.unregister();
415
+ };
416
+ }, []);
330
417
 
331
- - **Quick Prototypes**: Add AI to static sites or landing pages.
332
- - **Legacy Upgrades**: Enhance old HTML with AI without refactoring.
333
- - **MVPs**: Rapidly build AI features for demos.
334
- - **Learning MCP-B**: Experiment with concepts in a simple environment.
418
+ return <div>My Component</div>;
419
+ }
420
+ ```
335
421
 
336
- For production apps, consider [@mcp-b/transports](https://www.npmjs.com/package/@mcp-b/transports) for deeper integration.
422
+ ### Persistence Across provideContext() Calls
337
423
 
338
- ## 📦 Distribution Formats
424
+ ```javascript
425
+ // Step 1: Register base tools (Bucket A)
426
+ window.navigator.modelContext.provideContext({
427
+ tools: [
428
+ { name: "base-tool-1", description: "Base tool", inputSchema: {}, async execute() {} }
429
+ ]
430
+ });
431
+ // Tools: ["base-tool-1"]
432
+
433
+ // Step 2: Register dynamic tool (Bucket B)
434
+ const reg = window.navigator.modelContext.registerTool({
435
+ name: "dynamic-tool",
436
+ description: "Dynamic tool",
437
+ inputSchema: { type: "object", properties: {} },
438
+ async execute() {
439
+ return { content: [{ type: "text", text: "Dynamic!" }] };
440
+ }
441
+ });
442
+ // Tools: ["base-tool-1", "dynamic-tool"]
443
+
444
+ // Step 3: Update base tools via provideContext
445
+ window.navigator.modelContext.provideContext({
446
+ tools: [
447
+ { name: "base-tool-2", description: "New base tool", inputSchema: {}, async execute() {} }
448
+ ]
449
+ });
450
+ // Tools: ["base-tool-2", "dynamic-tool"]
451
+ // ✅ "dynamic-tool" persists! Only "base-tool-1" was cleared
452
+
453
+ // Step 4: Clean up dynamic tool
454
+ reg.unregister();
455
+ // Tools: ["base-tool-2"]
456
+ ```
339
457
 
340
- - **UMD**: `dist/index.umd.js` – For script tags/AMDs.
341
- - **ESM**: `dist/index.js` – Modern modules.
342
- - **CommonJS**: `dist/index.cjs` – Node.js compatibility.
343
- - **Types**: `dist/index.d.ts` – TypeScript support.
458
+ ### Name Collision Protection
344
459
 
345
- Examples:
460
+ ```javascript
461
+ // Register a base tool
462
+ window.navigator.modelContext.provideContext({
463
+ tools: [
464
+ { name: "my-tool", description: "Base", inputSchema: {}, async execute() {} }
465
+ ]
466
+ });
467
+
468
+ // This will throw an error!
469
+ try {
470
+ window.navigator.modelContext.registerTool({
471
+ name: "my-tool", // ❌ Name collision with Bucket A
472
+ description: "Dynamic",
473
+ inputSchema: {},
474
+ async execute() {}
475
+ });
476
+ } catch (error) {
477
+ console.error(error.message);
478
+ // Error: Tool name collision: "my-tool" is already registered via provideContext()
479
+ }
346
480
 
347
- ```html
348
- <!-- UMD CDN -->
349
- <script src="https://unpkg.com/@mcp-b/global@latest"></script>
481
+ // Similarly, can't unregister a base tool
482
+ const baseToolList = window.navigator.modelContext.provideContext({
483
+ tools: [{ name: "base", description: "Base", inputSchema: {}, async execute() {} }]
484
+ });
485
+
486
+ // This will also throw an error!
487
+ try {
488
+ // Assuming we got a reference somehow
489
+ // registration.unregister(); would fail for a base tool
490
+ } catch (error) {
491
+ // Error: Cannot unregister tool "base": This tool was registered via provideContext()
492
+ }
350
493
  ```
351
494
 
495
+ ## 🔧 Event-Based Tool Calls (Advanced)
496
+
497
+ For manifest-based or advanced scenarios, you can handle tool calls as events:
498
+
352
499
  ```javascript
353
- // ESM
354
- import { initializeGlobalMCP } from "@mcp-b/global";
500
+ window.navigator.modelContext.addEventListener('toolcall', async (event) => {
501
+ console.log(`Tool called: ${event.name}`, event.arguments);
502
+
503
+ if (event.name === "custom-tool") {
504
+ // Prevent default execution
505
+ event.preventDefault();
506
+
507
+ // Provide custom response
508
+ event.respondWith({
509
+ content: [{
510
+ type: "text",
511
+ text: "Custom response from event handler"
512
+ }]
513
+ });
514
+ }
515
+
516
+ // If not prevented, the tool's execute function will run normally
517
+ });
355
518
  ```
356
519
 
357
- ## 🔧 Advanced Features
520
+ ### Hybrid Approach
521
+
522
+ The API supports both approaches simultaneously:
358
523
 
359
- ### Error Management
524
+ 1. **Event dispatched first** - `toolcall` event is fired
525
+ 2. **Event can override** - Call `event.preventDefault()` and `event.respondWith()`
526
+ 3. **Default execution** - If not prevented, the tool's `execute()` function runs
360
527
 
361
- Handle failures gracefully:
528
+ This allows flexibility for different use cases.
529
+
530
+ ## 🏗️ Architecture
531
+
532
+ ```
533
+ ┌─────────────────┐
534
+ │ AI Agent │
535
+ │ (MCP Client) │
536
+ └────────┬────────┘
537
+ │ MCP Protocol
538
+ │ (JSON-RPC)
539
+ ┌────────▼────────┐
540
+ │ MCP Server │
541
+ │ (Internal) │
542
+ └────────┬────────┘
543
+
544
+ ┌────────▼───────────────────┐
545
+ │ navigator.modelContext │ ◄── Your app registers tools here
546
+ │ (This pkg) │
547
+ └────────────────────────────┘
548
+ ```
549
+
550
+ This package:
551
+ 1. Exposes `window.navigator.modelContext` API (W3C Web Model Context standard)
552
+ 2. Internally creates an MCP Server
553
+ 3. Bridges tool calls between the two protocols
554
+ 4. Uses TabServerTransport for browser communication
555
+
556
+ ## 🔍 Feature Detection
557
+
558
+ Check if the API is available:
362
559
 
363
560
  ```javascript
364
- window.mcp.registerTool(
365
- "riskyTask",
366
- {
367
- title: "Risky Task",
368
- description: "May fail",
369
- },
370
- async () => {
371
- try {
372
- // Logic here
373
- return { content: [{ type: "text", text: "Success!" }] };
374
- } catch (err) {
375
- return {
376
- content: [{ type: "text", text: `Failed: ${err.message}` }],
377
- isError: true,
378
- };
379
- }
380
- }
381
- );
561
+ if ("modelContext" in navigator) {
562
+ // API is available
563
+ navigator.modelContext.provideContext({ tools: [...] });
564
+ } else {
565
+ console.warn("Web Model Context API not available");
566
+ }
382
567
  ```
383
568
 
384
- ### User-Specific Tools
569
+ ## 🐛 Debugging
385
570
 
386
- Register tools dynamically:
571
+ In development mode, access the internal bridge:
387
572
 
388
573
  ```javascript
389
- function addUserTools(user) {
390
- if (user.isAdmin) {
391
- window.mcp.registerTool(
392
- "adminTool",
393
- {
394
- title: "Admin Tool",
395
- description: "Admin-only",
396
- },
397
- async () => {
398
- /* ... */
399
- }
400
- );
401
- }
574
+ if (window.__mcpBridge) {
575
+ console.log("MCP Server:", window.__mcpBridge.server);
576
+ console.log("Registered tools:", window.__mcpBridge.tools);
402
577
  }
403
578
  ```
404
579
 
405
- ## 🚨 Key Considerations
580
+ ## 📦 What's Included
581
+
582
+ - **Web Model Context API** - Standard `window.navigator.modelContext` interface
583
+ - **Dynamic Tool Registration** - `registerTool()` with `unregister()` function
584
+ - **MCP Bridge** - Automatic bridging to Model Context Protocol
585
+ - **Tab Transport** - Communication layer for browser contexts
586
+ - **Event System** - Hybrid tool call handling
587
+ - **TypeScript Types** - Full type definitions included
588
+
589
+ ## 🔒 Security Considerations
406
590
 
407
- - **Browser-Only**: Designed exclusively for web environments.
408
- - **Extension Needed**: Users require the MCP-B extension for AI interactions.
409
- - **Security**: Tools inherit your site's permissions—expose only safe operations.
410
- - **Readiness Check**: Always verify `window.mcp` before use.
591
+ ### Origin Restrictions
592
+
593
+ By default, the MCP transport allows connections from any origin (`*`). For production, you should configure allowed origins:
594
+
595
+ ```javascript
596
+ // Future configuration API
597
+ window.navigator.modelContext.configure({
598
+ allowedOrigins: [
599
+ 'https://your-app.com',
600
+ 'https://trusted-agent.com'
601
+ ]
602
+ });
603
+ ```
604
+
605
+ ### Tool Validation
606
+
607
+ Always validate inputs in your tool implementations:
608
+
609
+ ```javascript
610
+ {
611
+ name: "delete-item",
612
+ description: "Delete an item",
613
+ inputSchema: {
614
+ type: "object",
615
+ properties: {
616
+ id: { type: "string", pattern: "^[a-zA-Z0-9]+$" }
617
+ },
618
+ required: ["id"]
619
+ },
620
+ async execute({ id }) {
621
+ // Additional validation
622
+ if (!isValidId(id)) {
623
+ return {
624
+ content: [{ type: "text", text: "Invalid ID" }],
625
+ isError: true
626
+ };
627
+ }
628
+
629
+ // Proceed with deletion
630
+ await deleteItem(id);
631
+ return {
632
+ content: [{ type: "text", text: "Item deleted" }]
633
+ };
634
+ }
635
+ }
636
+ ```
411
637
 
412
- ## 🔗 Related Resources
638
+ ## 🤝 Related Packages
413
639
 
414
- - [@mcp-b/transports](https://www.npmjs.com/package/@mcp-b/transports): Advanced transport layer.
415
- - [@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk): Core MCP SDK.
416
- - [MCP-B Extension](https://chromewebstore.google.com/detail/mcp-b/daohopfhkdelnpemnhlekblhnikhdhfa): Browser extension for tool interaction.
417
- - [Documentation](https://mcp-b.ai): Full guides and specs.
640
+ - [`@mcp-b/transports`](../transports) - MCP transport implementations
641
+ - [`@mcp-b/mcp-react-hooks`](../mcp-react-hooks) - React hooks for MCP
642
+ - [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk) - Official MCP SDK
418
643
 
419
- ## 📄 License
644
+ ## 📚 Resources
420
645
 
421
- MIT See [LICENSE](https://github.com/MiguelsPizza/WebMCP/blob/main/LICENSE).
646
+ - [Web Model Context API Explainer](https://github.com/webmachinelearning/webmcp)
647
+ - [Model Context Protocol Spec](https://modelcontextprotocol.io/)
648
+ - [Microsoft Edge Explainer](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/WebModelContext/explainer.md)
422
649
 
423
- ## 🤝 Contributing
650
+ ## 📝 License
424
651
 
425
- Welcome! Check the [main repo](https://github.com/MiguelsPizza/WebMCP) for guidelines.
652
+ MIT - see [LICENSE](../../LICENSE) for details
426
653
 
427
- ---
654
+ ## 🙋 Support
428
655
 
429
- **Unlock AI for your site today—start with a script tag!** 🚀
656
+ - [GitHub Issues](https://github.com/WebMCP-org/npm-packages/issues)
657
+ - [Documentation](https://docs.mcp-b.ai)
658
+ - [Discord Community](https://discord.gg/a9fBR6Bw)