@mcp-b/global 1.0.15 → 1.1.0
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 +111 -0
- package/dist/index.d.ts +55 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.iife.js +4 -4
- package/dist/index.js +173 -48
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TabServerTransport } from "@mcp-b/transports";
|
|
1
|
+
import { IframeChildTransport, TabServerTransport } from "@mcp-b/transports";
|
|
2
2
|
import { CallToolRequestSchema, ListToolsRequestSchema, Server } from "@mcp-b/webmcp-ts-sdk";
|
|
3
3
|
import { jsonSchemaToZod } from "@composio/json-schema-to-zod";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -200,10 +200,7 @@ var WebModelContext = class {
|
|
|
200
200
|
this.provideContextTools.set(tool.name, validatedTool);
|
|
201
201
|
}
|
|
202
202
|
this.updateBridgeTools();
|
|
203
|
-
|
|
204
|
-
method: "notifications/tools/list_changed",
|
|
205
|
-
params: {}
|
|
206
|
-
});
|
|
203
|
+
this.notifyToolsListChanged();
|
|
207
204
|
}
|
|
208
205
|
/**
|
|
209
206
|
* Register a single tool dynamically (Bucket B)
|
|
@@ -236,10 +233,7 @@ var WebModelContext = class {
|
|
|
236
233
|
this.dynamicTools.set(tool.name, validatedTool);
|
|
237
234
|
this.registrationTimestamps.set(tool.name, now);
|
|
238
235
|
this.updateBridgeTools();
|
|
239
|
-
|
|
240
|
-
method: "notifications/tools/list_changed",
|
|
241
|
-
params: {}
|
|
242
|
-
});
|
|
236
|
+
this.notifyToolsListChanged();
|
|
243
237
|
const unregisterFn = () => {
|
|
244
238
|
console.log(`[Web Model Context] Unregistering tool: ${tool.name}`);
|
|
245
239
|
if (this.provideContextTools.has(tool.name)) throw new Error(`[Web Model Context] Cannot unregister tool "${tool.name}": This tool was registered via provideContext(). Use provideContext() to update the base tool set.`);
|
|
@@ -251,10 +245,7 @@ var WebModelContext = class {
|
|
|
251
245
|
this.registrationTimestamps.delete(tool.name);
|
|
252
246
|
this.unregisterFunctions.delete(tool.name);
|
|
253
247
|
this.updateBridgeTools();
|
|
254
|
-
|
|
255
|
-
method: "notifications/tools/list_changed",
|
|
256
|
-
params: {}
|
|
257
|
-
});
|
|
248
|
+
this.notifyToolsListChanged();
|
|
258
249
|
};
|
|
259
250
|
this.unregisterFunctions.set(tool.name, unregisterFn);
|
|
260
251
|
return { unregister: unregisterFn };
|
|
@@ -270,6 +261,19 @@ var WebModelContext = class {
|
|
|
270
261
|
console.log(`[Web Model Context] Updated bridge with ${this.provideContextTools.size} base tools + ${this.dynamicTools.size} dynamic tools = ${this.bridge.tools.size} total`);
|
|
271
262
|
}
|
|
272
263
|
/**
|
|
264
|
+
* Notify all servers that the tools list has changed
|
|
265
|
+
*/
|
|
266
|
+
notifyToolsListChanged() {
|
|
267
|
+
if (this.bridge.tabServer.notification) this.bridge.tabServer.notification({
|
|
268
|
+
method: "notifications/tools/list_changed",
|
|
269
|
+
params: {}
|
|
270
|
+
});
|
|
271
|
+
if (this.bridge.iframeServer?.notification) this.bridge.iframeServer.notification({
|
|
272
|
+
method: "notifications/tools/list_changed",
|
|
273
|
+
params: {}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
273
277
|
* Execute a tool with hybrid approach:
|
|
274
278
|
* 1. Validate input arguments
|
|
275
279
|
* 2. Dispatch toolcall event first
|
|
@@ -335,59 +339,111 @@ var WebModelContext = class {
|
|
|
335
339
|
}
|
|
336
340
|
};
|
|
337
341
|
/**
|
|
338
|
-
* Initialize the MCP bridge
|
|
342
|
+
* Initialize the MCP bridge with dual-server support
|
|
343
|
+
* Creates both TabServer (same-window) and IframeChildServer (parent-child) by default
|
|
339
344
|
*/
|
|
340
|
-
function initializeMCPBridge() {
|
|
345
|
+
function initializeMCPBridge(options) {
|
|
341
346
|
console.log("[Web Model Context] Initializing MCP bridge");
|
|
342
|
-
const
|
|
343
|
-
|
|
347
|
+
const hostname = window.location.hostname || "localhost";
|
|
348
|
+
const transportOptions = options?.transport;
|
|
349
|
+
const setupServerHandlers = (server, bridge$1) => {
|
|
350
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
351
|
+
console.log("[MCP Bridge] Handling list_tools request");
|
|
352
|
+
return { tools: bridge$1.modelContext.listTools() };
|
|
353
|
+
});
|
|
354
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
355
|
+
console.log(`[MCP Bridge] Handling call_tool request: ${request.params.name}`);
|
|
356
|
+
const toolName = request.params.name;
|
|
357
|
+
const args = request.params.arguments || {};
|
|
358
|
+
try {
|
|
359
|
+
const response = await bridge$1.modelContext.executeTool(toolName, args);
|
|
360
|
+
return {
|
|
361
|
+
content: response.content,
|
|
362
|
+
isError: response.isError
|
|
363
|
+
};
|
|
364
|
+
} catch (error) {
|
|
365
|
+
console.error(`[MCP Bridge] Error calling tool ${toolName}:`, error);
|
|
366
|
+
throw error;
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
const customTransport = transportOptions?.create?.();
|
|
371
|
+
if (customTransport) {
|
|
372
|
+
console.log("[Web Model Context] Using custom transport");
|
|
373
|
+
const server = new Server({
|
|
374
|
+
name: hostname,
|
|
375
|
+
version: "1.0.0"
|
|
376
|
+
}, { capabilities: { tools: { listChanged: true } } });
|
|
377
|
+
const bridge$1 = {
|
|
378
|
+
tabServer: server,
|
|
379
|
+
tools: /* @__PURE__ */ new Map(),
|
|
380
|
+
modelContext: void 0,
|
|
381
|
+
isInitialized: true
|
|
382
|
+
};
|
|
383
|
+
bridge$1.modelContext = new WebModelContext(bridge$1);
|
|
384
|
+
setupServerHandlers(server, bridge$1);
|
|
385
|
+
server.connect(customTransport);
|
|
386
|
+
console.log("[Web Model Context] MCP server connected with custom transport");
|
|
387
|
+
return bridge$1;
|
|
388
|
+
}
|
|
389
|
+
console.log("[Web Model Context] Using dual-server mode");
|
|
390
|
+
const tabServerEnabled = transportOptions?.tabServer !== false;
|
|
391
|
+
const tabServer = new Server({
|
|
392
|
+
name: `${hostname}-tab`,
|
|
344
393
|
version: "1.0.0"
|
|
345
394
|
}, { capabilities: { tools: { listChanged: true } } });
|
|
346
395
|
const bridge = {
|
|
347
|
-
|
|
396
|
+
tabServer,
|
|
348
397
|
tools: /* @__PURE__ */ new Map(),
|
|
349
398
|
modelContext: void 0,
|
|
350
399
|
isInitialized: true
|
|
351
400
|
};
|
|
352
401
|
bridge.modelContext = new WebModelContext(bridge);
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
402
|
+
setupServerHandlers(tabServer, bridge);
|
|
403
|
+
if (tabServerEnabled) {
|
|
404
|
+
const { allowedOrigins,...restTabServerOptions } = typeof transportOptions?.tabServer === "object" ? transportOptions.tabServer : {};
|
|
405
|
+
const tabTransport = new TabServerTransport({
|
|
406
|
+
allowedOrigins: allowedOrigins ?? ["*"],
|
|
407
|
+
...restTabServerOptions
|
|
408
|
+
});
|
|
409
|
+
tabServer.connect(tabTransport);
|
|
410
|
+
console.log("[Web Model Context] Tab server connected");
|
|
411
|
+
}
|
|
412
|
+
const isInIframe = typeof window !== "undefined" && window.parent !== window;
|
|
413
|
+
const iframeServerConfig = transportOptions?.iframeServer;
|
|
414
|
+
if (iframeServerConfig !== false && (iframeServerConfig !== void 0 || isInIframe)) {
|
|
415
|
+
console.log("[Web Model Context] Enabling iframe server");
|
|
416
|
+
const iframeServer = new Server({
|
|
417
|
+
name: `${hostname}-iframe`,
|
|
418
|
+
version: "1.0.0"
|
|
419
|
+
}, { capabilities: { tools: { listChanged: true } } });
|
|
420
|
+
setupServerHandlers(iframeServer, bridge);
|
|
421
|
+
const { allowedOrigins,...restIframeServerOptions } = typeof iframeServerConfig === "object" ? iframeServerConfig : {};
|
|
422
|
+
const iframeTransport = new IframeChildTransport({
|
|
423
|
+
allowedOrigins: allowedOrigins ?? ["*"],
|
|
424
|
+
...restIframeServerOptions
|
|
425
|
+
});
|
|
426
|
+
iframeServer.connect(iframeTransport);
|
|
427
|
+
bridge.iframeServer = iframeServer;
|
|
428
|
+
console.log("[Web Model Context] Iframe server connected");
|
|
429
|
+
}
|
|
375
430
|
return bridge;
|
|
376
431
|
}
|
|
377
432
|
/**
|
|
378
433
|
* Initialize the Web Model Context API (window.navigator.modelContext)
|
|
379
434
|
*/
|
|
380
|
-
function initializeWebModelContext() {
|
|
435
|
+
function initializeWebModelContext(options) {
|
|
381
436
|
if (typeof window === "undefined") {
|
|
382
437
|
console.warn("[Web Model Context] Not in browser environment, skipping initialization");
|
|
383
438
|
return;
|
|
384
439
|
}
|
|
440
|
+
const effectiveOptions = options ?? window.__webModelContextOptions;
|
|
385
441
|
if (window.navigator.modelContext) {
|
|
386
442
|
console.warn("[Web Model Context] window.navigator.modelContext already exists, skipping initialization");
|
|
387
443
|
return;
|
|
388
444
|
}
|
|
389
445
|
try {
|
|
390
|
-
const bridge = initializeMCPBridge();
|
|
446
|
+
const bridge = initializeMCPBridge(effectiveOptions);
|
|
391
447
|
Object.defineProperty(window.navigator, "modelContext", {
|
|
392
448
|
value: bridge.modelContext,
|
|
393
449
|
writable: false,
|
|
@@ -410,9 +466,10 @@ function initializeWebModelContext() {
|
|
|
410
466
|
function cleanupWebModelContext() {
|
|
411
467
|
if (typeof window === "undefined") return;
|
|
412
468
|
if (window.__mcpBridge) try {
|
|
413
|
-
window.__mcpBridge.
|
|
469
|
+
window.__mcpBridge.tabServer.close();
|
|
470
|
+
if (window.__mcpBridge.iframeServer) window.__mcpBridge.iframeServer.close();
|
|
414
471
|
} catch (error) {
|
|
415
|
-
console.warn("[Web Model Context] Error closing MCP
|
|
472
|
+
console.warn("[Web Model Context] Error closing MCP servers:", error);
|
|
416
473
|
}
|
|
417
474
|
delete window.navigator.modelContext;
|
|
418
475
|
delete window.__mcpBridge;
|
|
@@ -421,10 +478,78 @@ function cleanupWebModelContext() {
|
|
|
421
478
|
|
|
422
479
|
//#endregion
|
|
423
480
|
//#region src/index.ts
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
481
|
+
function mergeTransportOptions(base, override) {
|
|
482
|
+
if (!base) return override;
|
|
483
|
+
if (!override) return base;
|
|
484
|
+
return {
|
|
485
|
+
...base,
|
|
486
|
+
...override,
|
|
487
|
+
tabServer: {
|
|
488
|
+
...base.tabServer ?? {},
|
|
489
|
+
...override.tabServer ?? {}
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
function mergeInitOptions(base, override) {
|
|
494
|
+
if (!base) return override;
|
|
495
|
+
if (!override) return base;
|
|
496
|
+
return {
|
|
497
|
+
...base,
|
|
498
|
+
...override,
|
|
499
|
+
transport: mergeTransportOptions(base.transport ?? {}, override.transport ?? {})
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function parseScriptTagOptions(script) {
|
|
503
|
+
if (!script || !script.dataset) return;
|
|
504
|
+
const { dataset } = script;
|
|
505
|
+
if (dataset.webmcpOptions) try {
|
|
506
|
+
return JSON.parse(dataset.webmcpOptions);
|
|
507
|
+
} catch (error) {
|
|
508
|
+
console.error("[Web Model Context] Invalid JSON in data-webmcp-options:", error);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const options = {};
|
|
512
|
+
let hasOptions = false;
|
|
513
|
+
if (dataset.webmcpAutoInitialize !== void 0) {
|
|
514
|
+
options.autoInitialize = dataset.webmcpAutoInitialize !== "false";
|
|
515
|
+
hasOptions = true;
|
|
516
|
+
}
|
|
517
|
+
const tabServerOptions = {};
|
|
518
|
+
let hasTabServerOptions = false;
|
|
519
|
+
if (dataset.webmcpAllowedOrigins) {
|
|
520
|
+
const origins = dataset.webmcpAllowedOrigins.split(",").map((origin) => origin.trim()).filter((origin) => origin.length > 0);
|
|
521
|
+
if (origins.length > 0) {
|
|
522
|
+
tabServerOptions.allowedOrigins = origins;
|
|
523
|
+
hasOptions = true;
|
|
524
|
+
hasTabServerOptions = true;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (dataset.webmcpChannelId) {
|
|
528
|
+
tabServerOptions.channelId = dataset.webmcpChannelId;
|
|
529
|
+
hasOptions = true;
|
|
530
|
+
hasTabServerOptions = true;
|
|
531
|
+
}
|
|
532
|
+
if (hasTabServerOptions) options.transport = {
|
|
533
|
+
...options.transport ?? {},
|
|
534
|
+
tabServer: {
|
|
535
|
+
...options.transport?.tabServer ?? {},
|
|
536
|
+
...tabServerOptions
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
return hasOptions ? options : void 0;
|
|
540
|
+
}
|
|
541
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
542
|
+
const globalOptions = window.__webModelContextOptions;
|
|
543
|
+
const scriptElement = document.currentScript;
|
|
544
|
+
const scriptOptions = parseScriptTagOptions(scriptElement);
|
|
545
|
+
const mergedOptions = mergeInitOptions(globalOptions, scriptOptions) ?? globalOptions ?? scriptOptions;
|
|
546
|
+
if (mergedOptions) window.__webModelContextOptions = mergedOptions;
|
|
547
|
+
const shouldAutoInitialize = mergedOptions?.autoInitialize !== false;
|
|
548
|
+
try {
|
|
549
|
+
if (shouldAutoInitialize) initializeWebModelContext(mergedOptions);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
console.error("[Web Model Context] Auto-initialization failed:", error);
|
|
552
|
+
}
|
|
428
553
|
}
|
|
429
554
|
|
|
430
555
|
//#endregion
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["jsonSchemaToZod","convertJsonSchemaToZod","properties: Record<string, { type: string; description?: string; [key: string]: unknown }>","required: string[]","enumValues: unknown[] | undefined","items: unknown | undefined","propertySchema: { type: string; description?: string; [key: string]: unknown }","validatedTool: ValidatedToolDescriptor","McpServer","bridge: MCPBridge"],"sources":["../src/validation.ts","../src/global.ts","../src/index.ts"],"sourcesContent":["// validation.ts - JSON Schema <-> Zod conversion and validation utilities\n\nimport { jsonSchemaToZod as convertJsonSchemaToZod } from '@composio/json-schema-to-zod';\nimport { z } from 'zod';\nimport type { InputSchema } from './types.js';\n\n/**\n * Detect if a schema is a Zod schema object (Record<string, ZodType>)\n * or a JSON Schema object\n */\nexport function isZodSchema(schema: unknown): boolean {\n if (typeof schema !== 'object' || schema === null) {\n return false;\n }\n\n // JSON Schema always has a 'type' property at the root\n if ('type' in schema && typeof (schema as { type: unknown }).type === 'string') {\n return false; // This is JSON Schema\n }\n\n // Check if any property value is a Zod type instance\n const values = Object.values(schema);\n if (values.length === 0) {\n return false; // Empty object, treat as JSON Schema\n }\n\n // If any value is a ZodType, it's a Zod schema\n return values.some((val) => val instanceof z.ZodType);\n}\n\n/**\n * Convert JSON Schema to Zod validator\n * Uses @composio/json-schema-to-zod for conversion\n */\nexport function jsonSchemaToZod(jsonSchema: InputSchema): z.ZodType {\n try {\n // convertJsonSchemaToZod returns a Zod schema from JSON Schema\n const zodSchema = convertJsonSchemaToZod(jsonSchema as unknown as object);\n return zodSchema;\n } catch (error) {\n console.warn('[Web Model Context] Failed to convert JSON Schema to Zod:', error);\n // Fallback: accept anything with passthrough\n return z.object({}).passthrough();\n }\n}\n\n/**\n * Convert Zod schema object to JSON Schema\n * Based on react-webmcp implementation\n */\nexport function zodToJsonSchema(schema: Record<string, z.ZodTypeAny>): InputSchema {\n const properties: Record<string, { type: string; description?: string; [key: string]: unknown }> =\n {};\n const required: string[] = [];\n\n for (const [key, zodType] of Object.entries(schema)) {\n // Extract description if available\n const description = (zodType as { description?: string }).description || undefined;\n\n // Infer JSON Schema type from Zod type\n let type = 'string';\n let enumValues: unknown[] | undefined;\n let items: unknown | undefined;\n\n if (zodType instanceof z.ZodString) {\n type = 'string';\n } else if (zodType instanceof z.ZodNumber) {\n type = 'number';\n } else if (zodType instanceof z.ZodBoolean) {\n type = 'boolean';\n } else if (zodType instanceof z.ZodArray) {\n type = 'array';\n // Try to get array item type\n const elementType = (zodType as { element?: z.ZodTypeAny }).element;\n if (elementType instanceof z.ZodString) {\n items = { type: 'string' };\n } else if (elementType instanceof z.ZodNumber) {\n items = { type: 'number' };\n } else if (elementType instanceof z.ZodBoolean) {\n items = { type: 'boolean' };\n } else {\n items = { type: 'string' };\n }\n } else if (zodType instanceof z.ZodObject) {\n type = 'object';\n } else if (zodType instanceof z.ZodEnum) {\n type = 'string';\n // Extract enum values\n const enumDef = (zodType as { _def?: { values?: unknown[] } })._def;\n if (enumDef?.values) {\n enumValues = enumDef.values;\n }\n }\n\n const propertySchema: { type: string; description?: string; [key: string]: unknown } = { type };\n if (description) {\n propertySchema.description = description;\n }\n if (enumValues) {\n propertySchema.enum = enumValues;\n }\n if (items) {\n propertySchema.items = items;\n }\n\n properties[key] = propertySchema;\n\n // Check if field is required (not optional)\n if (!zodType.isOptional()) {\n required.push(key);\n }\n }\n\n return {\n type: 'object',\n properties,\n ...(required.length > 0 && { required }),\n };\n}\n\n/**\n * Normalize a schema to both JSON Schema and Zod formats\n * Detects which format is provided and converts to the other\n */\nexport function normalizeSchema(schema: InputSchema | Record<string, z.ZodTypeAny>): {\n jsonSchema: InputSchema;\n zodValidator: z.ZodType;\n} {\n const isZod = isZodSchema(schema);\n\n if (isZod) {\n // Input is Zod schema object → convert to JSON Schema and wrap in z.object()\n const jsonSchema = zodToJsonSchema(schema as Record<string, z.ZodTypeAny>);\n const zodValidator = z.object(schema as Record<string, z.ZodTypeAny>);\n return { jsonSchema, zodValidator };\n }\n\n // Input is JSON Schema → convert to Zod\n const jsonSchema = schema as InputSchema;\n const zodValidator = jsonSchemaToZod(jsonSchema);\n return { jsonSchema, zodValidator };\n}\n\n/**\n * Validate data with Zod schema and return formatted result\n */\nexport function validateWithZod(\n data: unknown,\n validator: z.ZodType\n): { success: true; data: unknown } | { success: false; error: string } {\n const result = validator.safeParse(data);\n\n if (!result.success) {\n // Format Zod errors into readable message\n const errors = result.error.errors\n .map((err) => ` - ${err.path.join('.') || 'root'}: ${err.message}`)\n .join('\\n');\n return {\n success: false,\n error: `Validation failed:\\n${errors}`,\n };\n }\n\n return {\n success: true,\n data: result.data,\n };\n}\n","// global.ts - Web Model Context API Implementation\n// Bridges the Web Model Context API (window.navigator.modelContext) to MCP SDK\n\nimport { TabServerTransport } from '@mcp-b/transports';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n Server as McpServer,\n} from '@mcp-b/webmcp-ts-sdk';\nimport type {\n InternalModelContext,\n MCPBridge,\n ModelContextInput,\n ToolCallEvent,\n ToolDescriptor,\n ToolResponse,\n ValidatedToolDescriptor,\n} from './types.js';\nimport { normalizeSchema, validateWithZod } from './validation.js';\n\n/**\n * Custom ToolCallEvent implementation\n */\nclass WebToolCallEvent extends Event implements ToolCallEvent {\n public name: string;\n public arguments: Record<string, unknown>;\n private _response: ToolResponse | null = null;\n private _responded = false;\n\n constructor(toolName: string, args: Record<string, unknown>) {\n super('toolcall', { cancelable: true });\n this.name = toolName;\n this.arguments = args;\n }\n\n respondWith(response: ToolResponse): void {\n if (this._responded) {\n throw new Error('Response already provided for this tool call');\n }\n this._response = response;\n this._responded = true;\n }\n\n getResponse(): ToolResponse | null {\n return this._response;\n }\n\n hasResponse(): boolean {\n return this._responded;\n }\n}\n\n/**\n * Time window (in ms) to detect rapid duplicate registrations\n * Registrations within this window are likely due to React Strict Mode\n */\nconst RAPID_DUPLICATE_WINDOW_MS = 50;\n\n/**\n * ModelContext implementation that bridges to MCP SDK\n * Implements the W3C Web Model Context API proposal with two-bucket tool management\n *\n * Two-Bucket System:\n * - Bucket A (provideContextTools): Tools registered via provideContext() - base/app-level tools\n * - Bucket B (dynamicTools): Tools registered via registerTool() - component-scoped tools\n *\n * Benefits:\n * - provideContext() only clears Bucket A, leaving Bucket B intact\n * - Components can manage their own tool lifecycle independently\n * - Final tool list = Bucket A + Bucket B (merged, with collision detection)\n */\nclass WebModelContext implements InternalModelContext {\n private bridge: MCPBridge;\n private eventTarget: EventTarget;\n\n // Bucket A: Tools from provideContext() - cleared when provideContext is called again\n private provideContextTools: Map<string, ValidatedToolDescriptor>;\n\n // Bucket B: Tools from registerTool() - persist across provideContext calls\n private dynamicTools: Map<string, ValidatedToolDescriptor>;\n\n // Track registration timestamps for rapid duplicate detection (React Strict Mode)\n private registrationTimestamps: Map<string, number>;\n\n // Store unregister functions for returning on rapid duplicates\n private unregisterFunctions: Map<string, () => void>;\n\n constructor(bridge: MCPBridge) {\n this.bridge = bridge;\n this.eventTarget = new EventTarget();\n this.provideContextTools = new Map();\n this.dynamicTools = new Map();\n this.registrationTimestamps = new Map();\n this.unregisterFunctions = new Map();\n }\n\n /**\n * Add event listener (compatible with ModelContext interface)\n */\n addEventListener(\n type: 'toolcall',\n listener: (event: ToolCallEvent) => void | Promise<void>,\n options?: boolean | AddEventListenerOptions\n ): void {\n this.eventTarget.addEventListener(type, listener as EventListener, options);\n }\n\n /**\n * Remove event listener\n */\n removeEventListener(\n type: 'toolcall',\n listener: (event: ToolCallEvent) => void | Promise<void>,\n options?: boolean | EventListenerOptions\n ): void {\n this.eventTarget.removeEventListener(type, listener as EventListener, options);\n }\n\n /**\n * Dispatch event\n */\n dispatchEvent(event: Event): boolean {\n return this.eventTarget.dispatchEvent(event);\n }\n\n /**\n * Provide context (tools) to AI models\n * Clears and replaces Bucket A (provideContext tools), leaving Bucket B (dynamic tools) intact\n */\n provideContext(context: ModelContextInput): void {\n console.log(`[Web Model Context] Registering ${context.tools.length} tools via provideContext`);\n\n // Clear only Bucket A (provideContext tools)\n this.provideContextTools.clear();\n\n // Process each tool: normalize schemas and create validated descriptors\n for (const tool of context.tools) {\n // Check for name collisions with Bucket B (dynamic tools)\n if (this.dynamicTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Tool name collision: \"${tool.name}\" is already registered via registerTool(). ` +\n 'Please use a different name or unregister the dynamic tool first.'\n );\n }\n\n // Normalize input schema (convert to both JSON Schema and Zod)\n const { jsonSchema: inputJson, zodValidator: inputZod } = normalizeSchema(tool.inputSchema);\n\n // Normalize output schema if provided\n const normalizedOutput = tool.outputSchema ? normalizeSchema(tool.outputSchema) : null;\n\n // Create validated tool descriptor\n const validatedTool: ValidatedToolDescriptor = {\n name: tool.name,\n description: tool.description,\n inputSchema: inputJson,\n ...(normalizedOutput && { outputSchema: normalizedOutput.jsonSchema }),\n ...(tool.annotations && { annotations: tool.annotations }),\n execute: tool.execute,\n inputValidator: inputZod,\n ...(normalizedOutput && { outputValidator: normalizedOutput.zodValidator }),\n };\n\n // Add to Bucket A\n this.provideContextTools.set(tool.name, validatedTool);\n }\n\n // Update the merged tool list in bridge\n this.updateBridgeTools();\n\n // Notify that tools list changed\n if (this.bridge.server.notification) {\n this.bridge.server.notification({\n method: 'notifications/tools/list_changed',\n params: {},\n });\n }\n }\n\n /**\n * Register a single tool dynamically (Bucket B)\n * Returns an object with an unregister function to remove the tool\n * Tools registered via this method persist across provideContext() calls\n */\n registerTool(tool: ToolDescriptor<any, any>): { unregister: () => void } {\n console.log(`[Web Model Context] Registering tool dynamically: ${tool.name}`);\n\n // Check for rapid duplicate registration (React Strict Mode detection)\n const now = Date.now();\n const lastRegistration = this.registrationTimestamps.get(tool.name);\n\n if (lastRegistration && now - lastRegistration < RAPID_DUPLICATE_WINDOW_MS) {\n console.warn(\n `[Web Model Context] Tool \"${tool.name}\" registered multiple times within ${RAPID_DUPLICATE_WINDOW_MS}ms. ` +\n 'This is likely due to React Strict Mode double-mounting. Ignoring duplicate registration.'\n );\n\n // Return the existing unregister function\n const existingUnregister = this.unregisterFunctions.get(tool.name);\n if (existingUnregister) {\n return { unregister: existingUnregister };\n }\n }\n\n // Check for name collision with Bucket A (provideContext tools)\n if (this.provideContextTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Tool name collision: \"${tool.name}\" is already registered via provideContext(). ` +\n 'Please use a different name or update your provideContext() call.'\n );\n }\n\n // Check for name collision within Bucket B (genuine duplicate, not rapid)\n if (this.dynamicTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Tool name collision: \"${tool.name}\" is already registered via registerTool(). ` +\n 'Please unregister it first or use a different name.'\n );\n }\n\n // Normalize input schema (convert to both JSON Schema and Zod)\n const { jsonSchema: inputJson, zodValidator: inputZod } = normalizeSchema(tool.inputSchema);\n\n // Normalize output schema if provided\n const normalizedOutput = tool.outputSchema ? normalizeSchema(tool.outputSchema) : null;\n\n // Create validated tool descriptor\n const validatedTool: ValidatedToolDescriptor = {\n name: tool.name,\n description: tool.description,\n inputSchema: inputJson,\n ...(normalizedOutput && { outputSchema: normalizedOutput.jsonSchema }),\n ...(tool.annotations && { annotations: tool.annotations }),\n execute: tool.execute,\n inputValidator: inputZod,\n ...(normalizedOutput && { outputValidator: normalizedOutput.zodValidator }),\n };\n\n // Add to Bucket B (dynamic tools)\n this.dynamicTools.set(tool.name, validatedTool);\n\n // Store registration timestamp for rapid duplicate detection\n this.registrationTimestamps.set(tool.name, now);\n\n // Update the merged tool list in bridge\n this.updateBridgeTools();\n\n // Notify that tools list changed\n if (this.bridge.server.notification) {\n this.bridge.server.notification({\n method: 'notifications/tools/list_changed',\n params: {},\n });\n }\n\n // Create unregister function\n const unregisterFn = () => {\n console.log(`[Web Model Context] Unregistering tool: ${tool.name}`);\n\n // Check if this tool was registered via provideContext\n if (this.provideContextTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Cannot unregister tool \"${tool.name}\": ` +\n 'This tool was registered via provideContext(). Use provideContext() to update the base tool set.'\n );\n }\n\n // Remove from Bucket B\n if (!this.dynamicTools.has(tool.name)) {\n console.warn(\n `[Web Model Context] Tool \"${tool.name}\" is not registered, ignoring unregister call`\n );\n return;\n }\n\n this.dynamicTools.delete(tool.name);\n\n // Clean up tracking data\n this.registrationTimestamps.delete(tool.name);\n this.unregisterFunctions.delete(tool.name);\n\n // Update the merged tool list in bridge\n this.updateBridgeTools();\n\n // Notify that tools list changed\n if (this.bridge.server.notification) {\n this.bridge.server.notification({\n method: 'notifications/tools/list_changed',\n params: {},\n });\n }\n };\n\n // Store unregister function for rapid duplicate detection\n this.unregisterFunctions.set(tool.name, unregisterFn);\n\n // Return unregister function\n return { unregister: unregisterFn };\n }\n\n /**\n * Update the bridge tools map with merged tools from both buckets\n * Final tool list = Bucket A (provideContext) + Bucket B (dynamic)\n */\n private updateBridgeTools(): void {\n // Clear the bridge tools map\n this.bridge.tools.clear();\n\n // Add tools from Bucket A (provideContext tools)\n for (const [name, tool] of this.provideContextTools) {\n this.bridge.tools.set(name, tool);\n }\n\n // Add tools from Bucket B (dynamic tools)\n for (const [name, tool] of this.dynamicTools) {\n this.bridge.tools.set(name, tool);\n }\n\n console.log(\n `[Web Model Context] Updated bridge with ${this.provideContextTools.size} base tools + ${this.dynamicTools.size} dynamic tools = ${this.bridge.tools.size} total`\n );\n }\n\n /**\n * Execute a tool with hybrid approach:\n * 1. Validate input arguments\n * 2. Dispatch toolcall event first\n * 3. If not prevented, call tool's execute function\n * 4. Validate output (permissive mode - warn only)\n */\n async executeTool(toolName: string, args: Record<string, unknown>): Promise<ToolResponse> {\n const tool = this.bridge.tools.get(toolName);\n if (!tool) {\n throw new Error(`Tool not found: ${toolName}`);\n }\n\n // 1. VALIDATE INPUT ARGUMENTS\n console.log(`[Web Model Context] Validating input for tool: ${toolName}`);\n const validation = validateWithZod(args, tool.inputValidator);\n if (!validation.success) {\n console.error(\n `[Web Model Context] Input validation failed for ${toolName}:`,\n validation.error\n );\n return {\n content: [\n {\n type: 'text',\n text: `Input validation error for tool \"${toolName}\":\\n${validation.error}`,\n },\n ],\n isError: true,\n };\n }\n\n // Use validated data for execution\n const validatedArgs = validation.data as Record<string, unknown>;\n\n // 2. Create toolcall event\n const event = new WebToolCallEvent(toolName, validatedArgs);\n\n // Dispatch event to listeners\n this.dispatchEvent(event);\n\n // If event was prevented and response provided, use that\n if (event.defaultPrevented && event.hasResponse()) {\n const response = event.getResponse();\n if (response) {\n console.log(`[Web Model Context] Tool ${toolName} handled by event listener`);\n return response;\n }\n }\n\n // 3. Execute the tool's execute function\n console.log(`[Web Model Context] Executing tool: ${toolName}`);\n try {\n const response = await tool.execute(validatedArgs);\n\n // 4. VALIDATE OUTPUT (permissive mode - warn only, don't block)\n if (tool.outputValidator && response.structuredContent) {\n const outputValidation = validateWithZod(response.structuredContent, tool.outputValidator);\n if (!outputValidation.success) {\n console.warn(\n `[Web Model Context] Output validation failed for ${toolName}:`,\n outputValidation.error\n );\n // Continue anyway - permissive mode\n }\n }\n\n return response;\n } catch (error) {\n console.error(`[Web Model Context] Error executing tool ${toolName}:`, error);\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * Get list of registered tools in MCP format\n * Includes full MCP spec: annotations, outputSchema, etc.\n */\n listTools() {\n return Array.from(this.bridge.tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n ...(tool.outputSchema && { outputSchema: tool.outputSchema }),\n ...(tool.annotations && { annotations: tool.annotations }),\n }));\n }\n}\n\n/**\n * Initialize the MCP bridge\n */\nfunction initializeMCPBridge(): MCPBridge {\n console.log('[Web Model Context] Initializing MCP bridge');\n\n const hostname = window.location.hostname || 'localhost';\n\n // Create MCP server\n const server = new McpServer(\n {\n name: hostname,\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {\n listChanged: true,\n },\n },\n }\n );\n\n // Create bridge object (modelContext is assigned after instantiation)\n const bridge: MCPBridge = {\n server,\n tools: new Map(),\n modelContext: undefined as unknown as InternalModelContext,\n isInitialized: true,\n };\n\n // Create modelContext and attach to bridge\n const modelContext = new WebModelContext(bridge);\n bridge.modelContext = modelContext;\n\n // Set up MCP server handlers\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n console.log('[MCP Bridge] Handling list_tools request');\n return {\n tools: bridge.modelContext.listTools(),\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n console.log(`[MCP Bridge] Handling call_tool request: ${request.params.name}`);\n\n const toolName = request.params.name;\n const args = (request.params.arguments || {}) as Record<string, unknown>;\n\n try {\n const response = await bridge.modelContext.executeTool(toolName, args);\n // Return in MCP SDK format\n return {\n content: response.content,\n isError: response.isError,\n };\n } catch (error) {\n console.error(`[MCP Bridge] Error calling tool ${toolName}:`, error);\n throw error;\n }\n });\n\n // Connect transport\n const transport = new TabServerTransport({\n allowedOrigins: ['*'], // TODO: Make this configurable\n });\n\n server.connect(transport);\n\n console.log('[Web Model Context] MCP server connected');\n\n return bridge;\n}\n\n/**\n * Initialize the Web Model Context API (window.navigator.modelContext)\n */\nexport function initializeWebModelContext(): void {\n if (typeof window === 'undefined') {\n console.warn('[Web Model Context] Not in browser environment, skipping initialization');\n return;\n }\n\n if (window.navigator.modelContext) {\n console.warn(\n '[Web Model Context] window.navigator.modelContext already exists, skipping initialization'\n );\n return;\n }\n\n try {\n // Initialize MCP bridge\n const bridge = initializeMCPBridge();\n\n // Expose shared modelContext instance\n Object.defineProperty(window.navigator, 'modelContext', {\n value: bridge.modelContext,\n writable: false,\n configurable: false,\n });\n\n // Expose bridge for debugging\n Object.defineProperty(window, '__mcpBridge', {\n value: bridge,\n writable: false,\n configurable: true,\n });\n\n console.log('✅ [Web Model Context] window.navigator.modelContext initialized successfully');\n } catch (error) {\n console.error('[Web Model Context] Failed to initialize:', error);\n throw error;\n }\n}\n\n/**\n * Cleanup function (for testing/development)\n */\nexport function cleanupWebModelContext(): void {\n if (typeof window === 'undefined') return;\n\n if (window.__mcpBridge) {\n try {\n window.__mcpBridge.server.close();\n } catch (error) {\n console.warn('[Web Model Context] Error closing MCP server:', error);\n }\n }\n\n delete (window.navigator as unknown as { modelContext?: unknown }).modelContext;\n delete (window as unknown as { __mcpBridge?: unknown }).__mcpBridge;\n\n console.log('[Web Model Context] Cleaned up');\n}\n","// index.ts - Entry point for Web Model Context API polyfill\n\nimport { initializeWebModelContext } from './global.js';\n\n// Auto-initialize immediately when script loads in browser environments\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n try {\n initializeWebModelContext();\n } catch (error) {\n console.error('[Web Model Context] Auto-initialization failed:', error);\n }\n}\n\n// For manual initialization (when using as ES module)\nexport { cleanupWebModelContext, initializeWebModelContext } from './global.js';\nexport type * from './types.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["jsonSchemaToZod","convertJsonSchemaToZod","properties: Record<string, { type: string; description?: string; [key: string]: unknown }>","required: string[]","enumValues: unknown[] | undefined","items: unknown | undefined","propertySchema: { type: string; description?: string; [key: string]: unknown }","validatedTool: ValidatedToolDescriptor","bridge","customTransport: Transport | undefined","McpServer","bridge: MCPBridge","options: WebModelContextInitOptions","tabServerOptions: TabServerConfig"],"sources":["../src/validation.ts","../src/global.ts","../src/index.ts"],"sourcesContent":["// validation.ts - JSON Schema <-> Zod conversion and validation utilities\n\nimport { jsonSchemaToZod as convertJsonSchemaToZod } from '@composio/json-schema-to-zod';\nimport { z } from 'zod';\nimport type { InputSchema } from './types.js';\n\n/**\n * Detect if a schema is a Zod schema object (Record<string, ZodType>)\n * or a JSON Schema object\n */\nexport function isZodSchema(schema: unknown): boolean {\n if (typeof schema !== 'object' || schema === null) {\n return false;\n }\n\n // JSON Schema always has a 'type' property at the root\n if ('type' in schema && typeof (schema as { type: unknown }).type === 'string') {\n return false; // This is JSON Schema\n }\n\n // Check if any property value is a Zod type instance\n const values = Object.values(schema);\n if (values.length === 0) {\n return false; // Empty object, treat as JSON Schema\n }\n\n // If any value is a ZodType, it's a Zod schema\n return values.some((val) => val instanceof z.ZodType);\n}\n\n/**\n * Convert JSON Schema to Zod validator\n * Uses @composio/json-schema-to-zod for conversion\n */\nexport function jsonSchemaToZod(jsonSchema: InputSchema): z.ZodType {\n try {\n // convertJsonSchemaToZod returns a Zod schema from JSON Schema\n const zodSchema = convertJsonSchemaToZod(jsonSchema as unknown as object);\n return zodSchema;\n } catch (error) {\n console.warn('[Web Model Context] Failed to convert JSON Schema to Zod:', error);\n // Fallback: accept anything with passthrough\n return z.object({}).passthrough();\n }\n}\n\n/**\n * Convert Zod schema object to JSON Schema\n * Based on react-webmcp implementation\n */\nexport function zodToJsonSchema(schema: Record<string, z.ZodTypeAny>): InputSchema {\n const properties: Record<string, { type: string; description?: string; [key: string]: unknown }> =\n {};\n const required: string[] = [];\n\n for (const [key, zodType] of Object.entries(schema)) {\n // Extract description if available\n const description = (zodType as { description?: string }).description || undefined;\n\n // Infer JSON Schema type from Zod type\n let type = 'string';\n let enumValues: unknown[] | undefined;\n let items: unknown | undefined;\n\n if (zodType instanceof z.ZodString) {\n type = 'string';\n } else if (zodType instanceof z.ZodNumber) {\n type = 'number';\n } else if (zodType instanceof z.ZodBoolean) {\n type = 'boolean';\n } else if (zodType instanceof z.ZodArray) {\n type = 'array';\n // Try to get array item type\n const elementType = (zodType as { element?: z.ZodTypeAny }).element;\n if (elementType instanceof z.ZodString) {\n items = { type: 'string' };\n } else if (elementType instanceof z.ZodNumber) {\n items = { type: 'number' };\n } else if (elementType instanceof z.ZodBoolean) {\n items = { type: 'boolean' };\n } else {\n items = { type: 'string' };\n }\n } else if (zodType instanceof z.ZodObject) {\n type = 'object';\n } else if (zodType instanceof z.ZodEnum) {\n type = 'string';\n // Extract enum values\n const enumDef = (zodType as { _def?: { values?: unknown[] } })._def;\n if (enumDef?.values) {\n enumValues = enumDef.values;\n }\n }\n\n const propertySchema: { type: string; description?: string; [key: string]: unknown } = { type };\n if (description) {\n propertySchema.description = description;\n }\n if (enumValues) {\n propertySchema.enum = enumValues;\n }\n if (items) {\n propertySchema.items = items;\n }\n\n properties[key] = propertySchema;\n\n // Check if field is required (not optional)\n if (!zodType.isOptional()) {\n required.push(key);\n }\n }\n\n return {\n type: 'object',\n properties,\n ...(required.length > 0 && { required }),\n };\n}\n\n/**\n * Normalize a schema to both JSON Schema and Zod formats\n * Detects which format is provided and converts to the other\n */\nexport function normalizeSchema(schema: InputSchema | Record<string, z.ZodTypeAny>): {\n jsonSchema: InputSchema;\n zodValidator: z.ZodType;\n} {\n const isZod = isZodSchema(schema);\n\n if (isZod) {\n // Input is Zod schema object → convert to JSON Schema and wrap in z.object()\n const jsonSchema = zodToJsonSchema(schema as Record<string, z.ZodTypeAny>);\n const zodValidator = z.object(schema as Record<string, z.ZodTypeAny>);\n return { jsonSchema, zodValidator };\n }\n\n // Input is JSON Schema → convert to Zod\n const jsonSchema = schema as InputSchema;\n const zodValidator = jsonSchemaToZod(jsonSchema);\n return { jsonSchema, zodValidator };\n}\n\n/**\n * Validate data with Zod schema and return formatted result\n */\nexport function validateWithZod(\n data: unknown,\n validator: z.ZodType\n): { success: true; data: unknown } | { success: false; error: string } {\n const result = validator.safeParse(data);\n\n if (!result.success) {\n // Format Zod errors into readable message\n const errors = result.error.errors\n .map((err) => ` - ${err.path.join('.') || 'root'}: ${err.message}`)\n .join('\\n');\n return {\n success: false,\n error: `Validation failed:\\n${errors}`,\n };\n }\n\n return {\n success: true,\n data: result.data,\n };\n}\n","import {\n IframeChildTransport,\n type IframeChildTransportOptions,\n TabServerTransport,\n type TabServerTransportOptions,\n} from '@mcp-b/transports';\nimport type { Transport } from '@mcp-b/webmcp-ts-sdk';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n Server as McpServer,\n} from '@mcp-b/webmcp-ts-sdk';\nimport type {\n InternalModelContext,\n MCPBridge,\n ModelContextInput,\n ToolCallEvent,\n ToolDescriptor,\n ToolResponse,\n ValidatedToolDescriptor,\n WebModelContextInitOptions,\n} from './types.js';\nimport { normalizeSchema, validateWithZod } from './validation.js';\n\ndeclare global {\n interface Window {\n __webModelContextOptions?: WebModelContextInitOptions;\n }\n}\n\n/**\n * Custom ToolCallEvent implementation\n */\nclass WebToolCallEvent extends Event implements ToolCallEvent {\n public name: string;\n public arguments: Record<string, unknown>;\n private _response: ToolResponse | null = null;\n private _responded = false;\n\n constructor(toolName: string, args: Record<string, unknown>) {\n super('toolcall', { cancelable: true });\n this.name = toolName;\n this.arguments = args;\n }\n\n respondWith(response: ToolResponse): void {\n if (this._responded) {\n throw new Error('Response already provided for this tool call');\n }\n this._response = response;\n this._responded = true;\n }\n\n getResponse(): ToolResponse | null {\n return this._response;\n }\n\n hasResponse(): boolean {\n return this._responded;\n }\n}\n\n/**\n * Time window (in ms) to detect rapid duplicate registrations\n * Registrations within this window are likely due to React Strict Mode\n */\nconst RAPID_DUPLICATE_WINDOW_MS = 50;\n\n/**\n * ModelContext implementation that bridges to MCP SDK\n * Implements the W3C Web Model Context API proposal with two-bucket tool management\n *\n * Two-Bucket System:\n * - Bucket A (provideContextTools): Tools registered via provideContext() - base/app-level tools\n * - Bucket B (dynamicTools): Tools registered via registerTool() - component-scoped tools\n *\n * Benefits:\n * - provideContext() only clears Bucket A, leaving Bucket B intact\n * - Components can manage their own tool lifecycle independently\n * - Final tool list = Bucket A + Bucket B (merged, with collision detection)\n */\nclass WebModelContext implements InternalModelContext {\n private bridge: MCPBridge;\n private eventTarget: EventTarget;\n private provideContextTools: Map<string, ValidatedToolDescriptor>;\n private dynamicTools: Map<string, ValidatedToolDescriptor>;\n private registrationTimestamps: Map<string, number>;\n private unregisterFunctions: Map<string, () => void>;\n\n constructor(bridge: MCPBridge) {\n this.bridge = bridge;\n this.eventTarget = new EventTarget();\n this.provideContextTools = new Map();\n this.dynamicTools = new Map();\n this.registrationTimestamps = new Map();\n this.unregisterFunctions = new Map();\n }\n\n /**\n * Add event listener (compatible with ModelContext interface)\n */\n addEventListener(\n type: 'toolcall',\n listener: (event: ToolCallEvent) => void | Promise<void>,\n options?: boolean | AddEventListenerOptions\n ): void {\n this.eventTarget.addEventListener(type, listener as EventListener, options);\n }\n\n /**\n * Remove event listener\n */\n removeEventListener(\n type: 'toolcall',\n listener: (event: ToolCallEvent) => void | Promise<void>,\n options?: boolean | EventListenerOptions\n ): void {\n this.eventTarget.removeEventListener(type, listener as EventListener, options);\n }\n\n /**\n * Dispatch event\n */\n dispatchEvent(event: Event): boolean {\n return this.eventTarget.dispatchEvent(event);\n }\n\n /**\n * Provide context (tools) to AI models\n * Clears and replaces Bucket A (provideContext tools), leaving Bucket B (dynamic tools) intact\n */\n provideContext(context: ModelContextInput): void {\n console.log(`[Web Model Context] Registering ${context.tools.length} tools via provideContext`);\n\n this.provideContextTools.clear();\n\n for (const tool of context.tools) {\n if (this.dynamicTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Tool name collision: \"${tool.name}\" is already registered via registerTool(). ` +\n 'Please use a different name or unregister the dynamic tool first.'\n );\n }\n\n const { jsonSchema: inputJson, zodValidator: inputZod } = normalizeSchema(tool.inputSchema);\n\n const normalizedOutput = tool.outputSchema ? normalizeSchema(tool.outputSchema) : null;\n\n const validatedTool: ValidatedToolDescriptor = {\n name: tool.name,\n description: tool.description,\n inputSchema: inputJson,\n ...(normalizedOutput && { outputSchema: normalizedOutput.jsonSchema }),\n ...(tool.annotations && { annotations: tool.annotations }),\n execute: tool.execute,\n inputValidator: inputZod,\n ...(normalizedOutput && { outputValidator: normalizedOutput.zodValidator }),\n };\n\n this.provideContextTools.set(tool.name, validatedTool);\n }\n\n this.updateBridgeTools();\n\n this.notifyToolsListChanged();\n }\n\n /**\n * Register a single tool dynamically (Bucket B)\n * Returns an object with an unregister function to remove the tool\n * Tools registered via this method persist across provideContext() calls\n */\n registerTool(tool: ToolDescriptor<any, any>): { unregister: () => void } {\n console.log(`[Web Model Context] Registering tool dynamically: ${tool.name}`);\n\n const now = Date.now();\n const lastRegistration = this.registrationTimestamps.get(tool.name);\n\n if (lastRegistration && now - lastRegistration < RAPID_DUPLICATE_WINDOW_MS) {\n console.warn(\n `[Web Model Context] Tool \"${tool.name}\" registered multiple times within ${RAPID_DUPLICATE_WINDOW_MS}ms. ` +\n 'This is likely due to React Strict Mode double-mounting. Ignoring duplicate registration.'\n );\n\n const existingUnregister = this.unregisterFunctions.get(tool.name);\n if (existingUnregister) {\n return { unregister: existingUnregister };\n }\n }\n\n if (this.provideContextTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Tool name collision: \"${tool.name}\" is already registered via provideContext(). ` +\n 'Please use a different name or update your provideContext() call.'\n );\n }\n\n if (this.dynamicTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Tool name collision: \"${tool.name}\" is already registered via registerTool(). ` +\n 'Please unregister it first or use a different name.'\n );\n }\n\n const { jsonSchema: inputJson, zodValidator: inputZod } = normalizeSchema(tool.inputSchema);\n\n const normalizedOutput = tool.outputSchema ? normalizeSchema(tool.outputSchema) : null;\n\n const validatedTool: ValidatedToolDescriptor = {\n name: tool.name,\n description: tool.description,\n inputSchema: inputJson,\n ...(normalizedOutput && { outputSchema: normalizedOutput.jsonSchema }),\n ...(tool.annotations && { annotations: tool.annotations }),\n execute: tool.execute,\n inputValidator: inputZod,\n ...(normalizedOutput && { outputValidator: normalizedOutput.zodValidator }),\n };\n\n this.dynamicTools.set(tool.name, validatedTool);\n\n this.registrationTimestamps.set(tool.name, now);\n\n this.updateBridgeTools();\n\n this.notifyToolsListChanged();\n\n const unregisterFn = () => {\n console.log(`[Web Model Context] Unregistering tool: ${tool.name}`);\n\n if (this.provideContextTools.has(tool.name)) {\n throw new Error(\n `[Web Model Context] Cannot unregister tool \"${tool.name}\": ` +\n 'This tool was registered via provideContext(). Use provideContext() to update the base tool set.'\n );\n }\n\n if (!this.dynamicTools.has(tool.name)) {\n console.warn(\n `[Web Model Context] Tool \"${tool.name}\" is not registered, ignoring unregister call`\n );\n return;\n }\n\n this.dynamicTools.delete(tool.name);\n\n this.registrationTimestamps.delete(tool.name);\n this.unregisterFunctions.delete(tool.name);\n\n this.updateBridgeTools();\n\n this.notifyToolsListChanged();\n };\n\n this.unregisterFunctions.set(tool.name, unregisterFn);\n\n return { unregister: unregisterFn };\n }\n\n /**\n * Update the bridge tools map with merged tools from both buckets\n * Final tool list = Bucket A (provideContext) + Bucket B (dynamic)\n */\n private updateBridgeTools(): void {\n this.bridge.tools.clear();\n\n for (const [name, tool] of this.provideContextTools) {\n this.bridge.tools.set(name, tool);\n }\n\n for (const [name, tool] of this.dynamicTools) {\n this.bridge.tools.set(name, tool);\n }\n\n console.log(\n `[Web Model Context] Updated bridge with ${this.provideContextTools.size} base tools + ${this.dynamicTools.size} dynamic tools = ${this.bridge.tools.size} total`\n );\n }\n\n /**\n * Notify all servers that the tools list has changed\n */\n private notifyToolsListChanged(): void {\n if (this.bridge.tabServer.notification) {\n this.bridge.tabServer.notification({\n method: 'notifications/tools/list_changed',\n params: {},\n });\n }\n\n if (this.bridge.iframeServer?.notification) {\n this.bridge.iframeServer.notification({\n method: 'notifications/tools/list_changed',\n params: {},\n });\n }\n }\n\n /**\n * Execute a tool with hybrid approach:\n * 1. Validate input arguments\n * 2. Dispatch toolcall event first\n * 3. If not prevented, call tool's execute function\n * 4. Validate output (permissive mode - warn only)\n */\n async executeTool(toolName: string, args: Record<string, unknown>): Promise<ToolResponse> {\n const tool = this.bridge.tools.get(toolName);\n if (!tool) {\n throw new Error(`Tool not found: ${toolName}`);\n }\n\n console.log(`[Web Model Context] Validating input for tool: ${toolName}`);\n const validation = validateWithZod(args, tool.inputValidator);\n if (!validation.success) {\n console.error(\n `[Web Model Context] Input validation failed for ${toolName}:`,\n validation.error\n );\n return {\n content: [\n {\n type: 'text',\n text: `Input validation error for tool \"${toolName}\":\\n${validation.error}`,\n },\n ],\n isError: true,\n };\n }\n\n const validatedArgs = validation.data as Record<string, unknown>;\n\n const event = new WebToolCallEvent(toolName, validatedArgs);\n\n this.dispatchEvent(event);\n\n if (event.defaultPrevented && event.hasResponse()) {\n const response = event.getResponse();\n if (response) {\n console.log(`[Web Model Context] Tool ${toolName} handled by event listener`);\n return response;\n }\n }\n\n console.log(`[Web Model Context] Executing tool: ${toolName}`);\n try {\n const response = await tool.execute(validatedArgs);\n\n if (tool.outputValidator && response.structuredContent) {\n const outputValidation = validateWithZod(response.structuredContent, tool.outputValidator);\n if (!outputValidation.success) {\n console.warn(\n `[Web Model Context] Output validation failed for ${toolName}:`,\n outputValidation.error\n );\n }\n }\n\n return response;\n } catch (error) {\n console.error(`[Web Model Context] Error executing tool ${toolName}:`, error);\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * Get list of registered tools in MCP format\n * Includes full MCP spec: annotations, outputSchema, etc.\n */\n listTools() {\n return Array.from(this.bridge.tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n ...(tool.outputSchema && { outputSchema: tool.outputSchema }),\n ...(tool.annotations && { annotations: tool.annotations }),\n }));\n }\n}\n\n/**\n * Initialize the MCP bridge with dual-server support\n * Creates both TabServer (same-window) and IframeChildServer (parent-child) by default\n */\nfunction initializeMCPBridge(options?: WebModelContextInitOptions): MCPBridge {\n console.log('[Web Model Context] Initializing MCP bridge');\n\n const hostname = window.location.hostname || 'localhost';\n const transportOptions = options?.transport;\n\n const setupServerHandlers = (server: McpServer, bridge: MCPBridge) => {\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n console.log('[MCP Bridge] Handling list_tools request');\n return {\n tools: bridge.modelContext.listTools(),\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n console.log(`[MCP Bridge] Handling call_tool request: ${request.params.name}`);\n\n const toolName = request.params.name;\n const args = (request.params.arguments || {}) as Record<string, unknown>;\n\n try {\n const response = await bridge.modelContext.executeTool(toolName, args);\n // Return in MCP SDK format\n return {\n content: response.content,\n isError: response.isError,\n };\n } catch (error) {\n console.error(`[MCP Bridge] Error calling tool ${toolName}:`, error);\n throw error;\n }\n });\n };\n\n const customTransport: Transport | undefined = transportOptions?.create?.();\n\n if (customTransport) {\n console.log('[Web Model Context] Using custom transport');\n\n const server = new McpServer(\n {\n name: hostname,\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {\n listChanged: true,\n },\n },\n }\n );\n\n const bridge: MCPBridge = {\n tabServer: server,\n tools: new Map(),\n modelContext: undefined as unknown as InternalModelContext,\n isInitialized: true,\n };\n\n const modelContext = new WebModelContext(bridge);\n bridge.modelContext = modelContext;\n\n setupServerHandlers(server, bridge);\n server.connect(customTransport);\n\n console.log('[Web Model Context] MCP server connected with custom transport');\n return bridge;\n }\n\n console.log('[Web Model Context] Using dual-server mode');\n\n const tabServerEnabled = transportOptions?.tabServer !== false;\n const tabServer = new McpServer(\n {\n name: `${hostname}-tab`,\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {\n listChanged: true,\n },\n },\n }\n );\n\n // Create bridge object (modelContext is assigned after instantiation)\n const bridge: MCPBridge = {\n tabServer,\n tools: new Map(),\n modelContext: undefined as unknown as InternalModelContext,\n isInitialized: true,\n };\n\n // Create modelContext and attach to bridge\n const modelContext = new WebModelContext(bridge);\n bridge.modelContext = modelContext;\n\n // Set up handlers for tab server\n setupServerHandlers(tabServer, bridge);\n\n // Connect tab server transport\n if (tabServerEnabled) {\n const tabServerOptions: Partial<TabServerTransportOptions> =\n typeof transportOptions?.tabServer === 'object' ? transportOptions.tabServer : {};\n const { allowedOrigins, ...restTabServerOptions } = tabServerOptions;\n\n const tabTransport = new TabServerTransport({\n allowedOrigins: allowedOrigins ?? ['*'],\n ...(restTabServerOptions as Omit<TabServerTransportOptions, 'allowedOrigins'>),\n });\n\n tabServer.connect(tabTransport);\n console.log('[Web Model Context] Tab server connected');\n }\n\n const isInIframe = typeof window !== 'undefined' && window.parent !== window;\n const iframeServerConfig = transportOptions?.iframeServer;\n const iframeServerEnabled =\n iframeServerConfig !== false && (iframeServerConfig !== undefined || isInIframe);\n\n if (iframeServerEnabled) {\n console.log('[Web Model Context] Enabling iframe server');\n\n const iframeServer = new McpServer(\n {\n name: `${hostname}-iframe`,\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {\n listChanged: true,\n },\n },\n }\n );\n\n setupServerHandlers(iframeServer, bridge);\n\n const iframeServerOptions: Partial<IframeChildTransportOptions> =\n typeof iframeServerConfig === 'object' ? iframeServerConfig : {};\n const { allowedOrigins, ...restIframeServerOptions } = iframeServerOptions;\n\n const iframeTransport = new IframeChildTransport({\n allowedOrigins: allowedOrigins ?? ['*'],\n ...(restIframeServerOptions as Omit<IframeChildTransportOptions, 'allowedOrigins'>),\n });\n\n iframeServer.connect(iframeTransport);\n bridge.iframeServer = iframeServer;\n\n console.log('[Web Model Context] Iframe server connected');\n }\n\n return bridge;\n}\n\n/**\n * Initialize the Web Model Context API (window.navigator.modelContext)\n */\nexport function initializeWebModelContext(options?: WebModelContextInitOptions): void {\n if (typeof window === 'undefined') {\n console.warn('[Web Model Context] Not in browser environment, skipping initialization');\n return;\n }\n\n const effectiveOptions = options ?? window.__webModelContextOptions;\n\n if (window.navigator.modelContext) {\n console.warn(\n '[Web Model Context] window.navigator.modelContext already exists, skipping initialization'\n );\n return;\n }\n\n try {\n const bridge = initializeMCPBridge(effectiveOptions);\n\n Object.defineProperty(window.navigator, 'modelContext', {\n value: bridge.modelContext,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(window, '__mcpBridge', {\n value: bridge,\n writable: false,\n configurable: true,\n });\n\n console.log('✅ [Web Model Context] window.navigator.modelContext initialized successfully');\n } catch (error) {\n console.error('[Web Model Context] Failed to initialize:', error);\n throw error;\n }\n}\n\n/**\n * Cleanup function (for testing/development)\n */\nexport function cleanupWebModelContext(): void {\n if (typeof window === 'undefined') return;\n\n if (window.__mcpBridge) {\n try {\n window.__mcpBridge.tabServer.close();\n\n if (window.__mcpBridge.iframeServer) {\n window.__mcpBridge.iframeServer.close();\n }\n } catch (error) {\n console.warn('[Web Model Context] Error closing MCP servers:', error);\n }\n }\n\n delete (window.navigator as unknown as { modelContext?: unknown }).modelContext;\n delete (window as unknown as { __mcpBridge?: unknown }).__mcpBridge;\n\n console.log('[Web Model Context] Cleaned up');\n}\n","// index.ts - Entry point for Web Model Context API polyfill\n\nimport { initializeWebModelContext } from './global.js';\nimport type { TransportConfiguration, WebModelContextInitOptions } from './types.js';\n\ntype TabServerConfig = NonNullable<TransportConfiguration['tabServer']>;\n\nfunction mergeTransportOptions(\n base: TransportConfiguration,\n override: TransportConfiguration\n): TransportConfiguration {\n if (!base) {\n return override;\n }\n if (!override) {\n return base;\n }\n\n return {\n ...base,\n ...override,\n tabServer: {\n ...(base.tabServer ?? {}),\n ...(override.tabServer ?? {}),\n },\n };\n}\n\nfunction mergeInitOptions(\n base?: WebModelContextInitOptions,\n override?: WebModelContextInitOptions\n): WebModelContextInitOptions | undefined {\n if (!base) {\n return override;\n }\n if (!override) {\n return base;\n }\n\n return {\n ...base,\n ...override,\n transport: mergeTransportOptions(base.transport ?? {}, override.transport ?? {}),\n };\n}\n\nfunction parseScriptTagOptions(\n script: HTMLScriptElement | null\n): WebModelContextInitOptions | undefined {\n if (!script || !script.dataset) {\n return undefined;\n }\n\n const { dataset } = script;\n\n if (dataset.webmcpOptions) {\n try {\n return JSON.parse(dataset.webmcpOptions) as WebModelContextInitOptions;\n } catch (error) {\n console.error('[Web Model Context] Invalid JSON in data-webmcp-options:', error);\n return undefined;\n }\n }\n\n const options: WebModelContextInitOptions = {};\n let hasOptions = false;\n\n if (dataset.webmcpAutoInitialize !== undefined) {\n options.autoInitialize = dataset.webmcpAutoInitialize !== 'false';\n hasOptions = true;\n }\n\n const tabServerOptions: TabServerConfig = {};\n let hasTabServerOptions = false;\n\n if (dataset.webmcpAllowedOrigins) {\n const origins = dataset.webmcpAllowedOrigins\n .split(',')\n .map((origin) => origin.trim())\n .filter((origin) => origin.length > 0);\n\n if (origins.length > 0) {\n tabServerOptions.allowedOrigins = origins;\n hasOptions = true;\n hasTabServerOptions = true;\n }\n }\n\n if (dataset.webmcpChannelId) {\n tabServerOptions.channelId = dataset.webmcpChannelId;\n hasOptions = true;\n hasTabServerOptions = true;\n }\n\n if (hasTabServerOptions) {\n options.transport = {\n ...(options.transport ?? {}),\n tabServer: {\n ...(options.transport?.tabServer ?? {}),\n ...tabServerOptions,\n },\n };\n }\n\n return hasOptions ? options : undefined;\n}\n\n// Auto-initialize immediately when script loads in browser environments\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const globalOptions = window.__webModelContextOptions;\n const scriptElement = document.currentScript as HTMLScriptElement | null;\n const scriptOptions = parseScriptTagOptions(scriptElement);\n const mergedOptions =\n mergeInitOptions(globalOptions, scriptOptions) ?? globalOptions ?? scriptOptions;\n\n if (mergedOptions) {\n window.__webModelContextOptions = mergedOptions;\n }\n\n const shouldAutoInitialize = mergedOptions?.autoInitialize !== false;\n\n try {\n if (shouldAutoInitialize) {\n initializeWebModelContext(mergedOptions);\n }\n } catch (error) {\n console.error('[Web Model Context] Auto-initialization failed:', error);\n }\n}\n\n// For manual initialization (when using as ES module)\nexport { cleanupWebModelContext, initializeWebModelContext } from './global.js';\nexport type * from './types.js';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/global",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "W3C Web Model Context API polyfill - implements window.navigator.modelContext bridging to Model Context Protocol",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
],
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@composio/json-schema-to-zod": "^0.1.17",
|
|
50
|
-
"zod": "
|
|
51
|
-
"@mcp-b/transports": "1.0
|
|
50
|
+
"zod": "3.25.76",
|
|
51
|
+
"@mcp-b/transports": "1.1.0",
|
|
52
52
|
"@mcp-b/webmcp-ts-sdk": "1.0.1"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@types/node": "
|
|
55
|
+
"@types/node": "22.17.2",
|
|
56
56
|
"tsdown": "^0.15.10",
|
|
57
57
|
"typescript": "^5.8.3"
|
|
58
58
|
},
|