@mcp-b/global 1.1.0 → 1.1.1

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
@@ -214,6 +214,152 @@ initializeWebModelContext({
214
214
  });
215
215
  ```
216
216
 
217
+ ## 🔄 Native Chromium API Support
218
+
219
+ This package **automatically detects and integrates** with Chromium's native Web Model Context API when available. No configuration needed - it just works!
220
+
221
+ ### Automatic Detection & Integration
222
+
223
+ When you call `initializeWebModelContext()` (or when auto-initialization runs):
224
+
225
+ 1. **Native API detected** (both `navigator.modelContext` and `navigator.modelContextTesting` present):
226
+ - Uses native Chromium implementation
227
+ - Creates MCP bridge and syncs tools automatically
228
+ - Registers callback to listen for native tool changes
229
+ - MCP clients stay synchronized with native tool registry
230
+
231
+ 2. **No native API detected**:
232
+ - Installs full polyfill implementation
233
+ - Provides identical API surface
234
+
235
+ **Zero configuration required** - the package automatically adapts to your environment!
236
+
237
+ ### Native API Features
238
+
239
+ When the native Chromium API is available, you get:
240
+
241
+ - ✅ **Automatic tool synchronization** - Tools registered in native API are synced to MCP bridge via `registerToolsChangedCallback()`
242
+ - ✅ **Iframe tool collection** - Native API automatically collects tools from embedded iframes (no manual transport setup needed)
243
+ - ✅ **MCP compatibility** - Your MCP clients (extensions, apps) continue to work seamlessly
244
+ - ✅ **Tool change notifications** - MCP servers receive `tools/list_changed` notifications automatically
245
+ - ✅ **Consistent API** - Same code works with both native and polyfill implementations
246
+
247
+ ### How Tool Synchronization Works
248
+
249
+ The polyfill automatically registers a callback with the native API:
250
+
251
+ ```typescript
252
+ // Happens automatically when native API is detected
253
+ navigator.modelContextTesting.registerToolsChangedCallback(() => {
254
+ // Syncs native tools → MCP bridge
255
+ // MCP clients receive tools/list_changed notification
256
+ });
257
+ ```
258
+
259
+ This callback fires when:
260
+ - `navigator.modelContext.registerTool()` is called
261
+ - `navigator.modelContext.unregisterTool()` is called
262
+ - `navigator.modelContext.provideContext()` is called
263
+ - `navigator.modelContext.clearContext()` is called
264
+ - Tools are added from embedded iframes (native feature)
265
+
266
+ ### Enabling Native API in Chromium
267
+
268
+ ```bash
269
+ # Method 1: Launch with flag
270
+ chromium --enable-experimental-web-platform-features
271
+
272
+ # Method 2: Enable in chrome://flags
273
+ # Search for: "Experimental Web Platform Features"
274
+ # Set to: Enabled
275
+ # Restart browser
276
+ ```
277
+
278
+ ### Example: Using Native API
279
+
280
+ ```typescript
281
+ import '@mcp-b/global';
282
+
283
+ // If native API is present, this delegates to navigator.modelContext:
284
+ window.navigator.modelContext.registerTool({
285
+ name: 'myTool',
286
+ description: 'My tool',
287
+ inputSchema: { type: 'object', properties: {} },
288
+ async execute() {
289
+ return { content: [{ type: 'text', text: 'Hello!' }] };
290
+ }
291
+ });
292
+
293
+ // Behind the scenes:
294
+ // 1. Tool registered in native Chromium registry
295
+ // 2. Callback fires (registerToolsChangedCallback)
296
+ // 3. Tool synced to MCP bridge
297
+ // 4. MCP clients notified (tools/list_changed)
298
+ ```
299
+
300
+ ### Iframe Tool Collection (Native Only)
301
+
302
+ When the native API is active, tools from embedded iframes are **automatically collected**:
303
+
304
+ ```html
305
+ <!-- parent.html -->
306
+ <script type="module">
307
+ import '@mcp-b/global';
308
+
309
+ // Native API will collect tools from this page AND all iframes
310
+ navigator.modelContext.registerTool({
311
+ name: 'parent-tool',
312
+ description: 'Tool from parent page',
313
+ inputSchema: { type: 'object', properties: {} },
314
+ async execute() {
315
+ return { content: [{ type: 'text', text: 'Parent tool' }] };
316
+ }
317
+ });
318
+ </script>
319
+
320
+ <iframe src="child.html"></iframe>
321
+ ```
322
+
323
+ ```html
324
+ <!-- child.html -->
325
+ <script type="module">
326
+ import '@mcp-b/global';
327
+
328
+ // This tool is automatically visible in parent's registry (native feature)
329
+ navigator.modelContext.registerTool({
330
+ name: 'child-tool',
331
+ description: 'Tool from iframe',
332
+ inputSchema: { type: 'object', properties: {} },
333
+ async execute() {
334
+ return { content: [{ type: 'text', text: 'Child tool' }] };
335
+ }
336
+ });
337
+ </script>
338
+ ```
339
+
340
+ With native API, `navigator.modelContextTesting.listTools()` in the parent will show **both** tools! The MCP bridge stays in sync automatically.
341
+
342
+ ### Detection in Console
343
+
344
+ When you initialize the package, check the console logs:
345
+
346
+ ```
347
+ ✅ [Web Model Context] Native Chromium API detected
348
+ Using native implementation with MCP bridge synchronization
349
+ Native API will automatically collect tools from embedded iframes
350
+ ✅ [Web Model Context] MCP bridge synced with native API
351
+ MCP clients will receive automatic tool updates from native registry
352
+ ```
353
+
354
+ Or if polyfill is used:
355
+
356
+ ```
357
+ [Web Model Context] Native API not detected, installing polyfill
358
+ ✅ [Web Model Context] window.navigator.modelContext initialized successfully
359
+ [Model Context Testing] Installing polyfill
360
+ ✅ [Model Context Testing] Polyfill installed at window.navigator.modelContextTesting
361
+ ```
362
+
217
363
  ## 📖 API Reference
218
364
 
219
365
  ### Two-Bucket Tool Management System
@@ -688,9 +834,238 @@ if (window.__mcpBridge) {
688
834
  }
689
835
  ```
690
836
 
837
+ ## 🧪 Testing API (`navigator.modelContextTesting`)
838
+
839
+ This package provides a **Model Context Testing API** at `window.navigator.modelContextTesting` for debugging and testing your tools during development.
840
+
841
+ ### Native Support in Chromium
842
+
843
+ **IMPORTANT**: The `modelContextTesting` API is available natively in Chromium-based browsers when the experimental feature flag is enabled. This polyfill will detect and use the native implementation when available.
844
+
845
+ #### How to Enable Native API in Chromium:
846
+
847
+ **Option 1: Chrome Flags**
848
+ 1. Navigate to `chrome://flags`
849
+ 2. Search for "Experimental Web Platform Features"
850
+ 3. Enable the flag
851
+ 4. Restart your browser
852
+
853
+ **Option 2: Command Line**
854
+ ```bash
855
+ # Launch Chrome/Edge with experimental features
856
+ chrome --enable-experimental-web-platform-features
857
+ ```
858
+
859
+ **Detection**: When the native API is detected, you'll see this console message:
860
+ ```
861
+ ✅ [Model Context Testing] Native implementation detected (Chromium experimental feature)
862
+ Using native window.navigator.modelContextTesting from browser
863
+ ```
864
+
865
+ ### Polyfill Fallback
866
+
867
+ If the native API is not available, this package automatically provides a polyfill implementation with the same interface:
868
+
869
+ ```
870
+ [Model Context Testing] Native implementation not found, installing polyfill
871
+ 💡 To use the native implementation in Chromium:
872
+ - Navigate to chrome://flags
873
+ - Enable "Experimental Web Platform Features"
874
+ - Or launch with: --enable-experimental-web-platform-features
875
+ ✅ [Model Context Testing] Polyfill installed at window.navigator.modelContextTesting
876
+ ```
877
+
878
+ ### API Reference
879
+
880
+ #### `getToolCalls(): Array<ToolCall>`
881
+
882
+ Get a history of all tool calls made during the session.
883
+
884
+ ```javascript
885
+ // Register and call some tools
886
+ window.navigator.modelContext.provideContext({
887
+ tools: [{
888
+ name: "greet",
889
+ description: "Greet a user",
890
+ inputSchema: {
891
+ type: "object",
892
+ properties: { name: { type: "string" } },
893
+ required: ["name"]
894
+ },
895
+ async execute({ name }) {
896
+ return { content: [{ type: "text", text: `Hello, ${name}!` }] };
897
+ }
898
+ }]
899
+ });
900
+
901
+ // Simulate a tool call
902
+ // (In practice, this would come from an AI agent)
903
+
904
+ // Later, inspect the tool call history
905
+ const calls = window.navigator.modelContextTesting.getToolCalls();
906
+ console.log(calls);
907
+ // [
908
+ // {
909
+ // toolName: "greet",
910
+ // arguments: { name: "Alice" },
911
+ // timestamp: 1699123456789
912
+ // }
913
+ // ]
914
+ ```
915
+
916
+ #### `clearToolCalls(): void`
917
+
918
+ Clear the tool call history.
919
+
920
+ ```javascript
921
+ window.navigator.modelContextTesting.clearToolCalls();
922
+ console.log(window.navigator.modelContextTesting.getToolCalls()); // []
923
+ ```
924
+
925
+ #### `setMockToolResponse(toolName: string, response: ToolResponse): void`
926
+
927
+ Set a mock response for a specific tool. When set, the tool's `execute()` function will be bypassed and the mock response will be returned instead.
928
+
929
+ ```javascript
930
+ // Mock the "greet" tool to always return a specific response
931
+ window.navigator.modelContextTesting.setMockToolResponse("greet", {
932
+ content: [{
933
+ type: "text",
934
+ text: "Mocked greeting!"
935
+ }]
936
+ });
937
+
938
+ // Now when the tool is called, it returns the mock response
939
+ // (The execute function is never called)
940
+ ```
941
+
942
+ #### `clearMockToolResponse(toolName: string): void`
943
+
944
+ Remove the mock response for a specific tool.
945
+
946
+ ```javascript
947
+ window.navigator.modelContextTesting.clearMockToolResponse("greet");
948
+ // Tool will now use its actual execute function
949
+ ```
950
+
951
+ #### `clearAllMockToolResponses(): void`
952
+
953
+ Remove all mock tool responses.
954
+
955
+ ```javascript
956
+ window.navigator.modelContextTesting.clearAllMockToolResponses();
957
+ ```
958
+
959
+ #### `getRegisteredTools(): Array<ToolDescriptor>`
960
+
961
+ Get the list of all currently registered tools (same as `modelContext.listTools()`).
962
+
963
+ ```javascript
964
+ const tools = window.navigator.modelContextTesting.getRegisteredTools();
965
+ console.log(tools.map(t => t.name)); // ["greet", "add-todo", ...]
966
+ ```
967
+
968
+ #### `reset(): void`
969
+
970
+ Reset the entire testing state (clears tool call history and all mock responses).
971
+
972
+ ```javascript
973
+ window.navigator.modelContextTesting.reset();
974
+ ```
975
+
976
+ ### Testing Workflow Example
977
+
978
+ Here's a complete example of using the testing API:
979
+
980
+ ```javascript
981
+ // 1. Register your tools
982
+ window.navigator.modelContext.provideContext({
983
+ tools: [
984
+ {
985
+ name: "add-todo",
986
+ description: "Add a todo item",
987
+ inputSchema: {
988
+ type: "object",
989
+ properties: { text: { type: "string" } },
990
+ required: ["text"]
991
+ },
992
+ async execute({ text }) {
993
+ // This would normally add to your app state
994
+ return { content: [{ type: "text", text: `Added: ${text}` }] };
995
+ }
996
+ }
997
+ ]
998
+ });
999
+
1000
+ // 2. Set up mocks for testing
1001
+ window.navigator.modelContextTesting.setMockToolResponse("add-todo", {
1002
+ content: [{ type: "text", text: "Mock: Todo added successfully" }]
1003
+ });
1004
+
1005
+ // 3. Simulate tool calls (or let AI agent call them)
1006
+ // The tool will return the mock response instead of executing
1007
+
1008
+ // 4. Inspect tool call history
1009
+ const calls = window.navigator.modelContextTesting.getToolCalls();
1010
+ console.log(`${calls.length} tool calls made`);
1011
+ calls.forEach(call => {
1012
+ console.log(`- ${call.toolName}`, call.arguments);
1013
+ });
1014
+
1015
+ // 5. Clean up after testing
1016
+ window.navigator.modelContextTesting.reset();
1017
+ ```
1018
+
1019
+ ### Integration Testing Example
1020
+
1021
+ Perfect for automated testing with frameworks like Jest, Vitest, or Playwright:
1022
+
1023
+ ```javascript
1024
+ // test/model-context.test.js
1025
+ import { test, expect } from 'vitest';
1026
+
1027
+ test('todo tool creates correct response', async () => {
1028
+ // Arrange
1029
+ const mockResponse = {
1030
+ content: [{ type: "text", text: "Test todo added" }]
1031
+ };
1032
+
1033
+ window.navigator.modelContextTesting.setMockToolResponse(
1034
+ "add-todo",
1035
+ mockResponse
1036
+ );
1037
+
1038
+ // Act
1039
+ // Trigger your AI agent or directly call the tool via MCP
1040
+ // ...
1041
+
1042
+ // Assert
1043
+ const calls = window.navigator.modelContextTesting.getToolCalls();
1044
+ expect(calls).toHaveLength(1);
1045
+ expect(calls[0].toolName).toBe("add-todo");
1046
+ expect(calls[0].arguments).toEqual({ text: "Test item" });
1047
+
1048
+ // Cleanup
1049
+ window.navigator.modelContextTesting.reset();
1050
+ });
1051
+ ```
1052
+
1053
+ ### Browser Compatibility
1054
+
1055
+ | Browser | Native Support | Polyfill |
1056
+ |---------|---------------|----------|
1057
+ | Chrome/Edge (with flag) | ✅ Yes | N/A |
1058
+ | Chrome/Edge (default) | ❌ No | ✅ Yes |
1059
+ | Firefox | ❌ No | ✅ Yes |
1060
+ | Safari | ❌ No | ✅ Yes |
1061
+ | Other browsers | ❌ No | ✅ Yes |
1062
+
1063
+ The polyfill automatically detects and defers to the native implementation when available, ensuring forward compatibility as browsers adopt this standard.
1064
+
691
1065
  ## 📦 What's Included
692
1066
 
693
1067
  - **Web Model Context API** - Standard `window.navigator.modelContext` interface
1068
+ - **Model Context Testing API** - `window.navigator.modelContextTesting` for debugging and testing (with native Chromium support detection)
694
1069
  - **Dynamic Tool Registration** - `registerTool()` with `unregister()` function
695
1070
  - **MCP Bridge** - Automatic bridging to Model Context Protocol
696
1071
  - **Tab Transport** - Communication layer for browser contexts
package/dist/index.d.ts CHANGED
@@ -129,7 +129,7 @@ interface ModelContextInput {
129
129
  * Array of tool descriptors
130
130
  * Supports both JSON Schema and Zod schema formats
131
131
  */
132
- tools: ToolDescriptor<any, any>[];
132
+ tools: ToolDescriptor[];
133
133
  }
134
134
  /**
135
135
  * Tool call event
@@ -167,6 +167,16 @@ interface ModelContext {
167
167
  registerTool<TInputSchema extends ZodSchemaObject = Record<string, never>, TOutputSchema extends ZodSchemaObject = Record<string, never>>(tool: ToolDescriptor<TInputSchema, TOutputSchema>): {
168
168
  unregister: () => void;
169
169
  };
170
+ /**
171
+ * Unregister a tool by name
172
+ * Available in Chromium's native implementation
173
+ */
174
+ unregisterTool(name: string): void;
175
+ /**
176
+ * Clear all registered tools (both buckets)
177
+ * Available in Chromium's native implementation
178
+ */
179
+ clearContext(): void;
170
180
  /**
171
181
  * Add event listener for tool calls
172
182
  */
@@ -210,8 +220,93 @@ interface MCPBridge {
210
220
  iframeServer?: Server;
211
221
  tools: Map<string, ValidatedToolDescriptor>;
212
222
  modelContext: InternalModelContext;
223
+ modelContextTesting?: ModelContextTesting;
213
224
  isInitialized: boolean;
214
225
  }
226
+ /**
227
+ * Tool info returned by listTools() in testing API
228
+ * Note: inputSchema is a JSON string, not an object (matches Chromium implementation)
229
+ */
230
+ interface ToolInfo {
231
+ name: string;
232
+ description: string;
233
+ inputSchema: string;
234
+ }
235
+ /**
236
+ * Testing API for Model Context
237
+ *
238
+ * **Native Support**: This API is available natively in Chromium-based browsers
239
+ * when the experimental "Model Context Testing" feature flag is enabled.
240
+ *
241
+ * **How to enable in Chromium**:
242
+ * - Navigate to `chrome://flags`
243
+ * - Search for "experimental web platform features" or "model context"
244
+ * - Enable the feature and restart the browser
245
+ * - Or launch with: `--enable-experimental-web-platform-features`
246
+ *
247
+ * **Polyfill**: If the native API is not available, this polyfill provides
248
+ * a compatible implementation for testing purposes.
249
+ */
250
+ interface ModelContextTesting {
251
+ /**
252
+ * Execute a tool directly with JSON string input (Chromium native API)
253
+ * @param toolName - Name of the tool to execute
254
+ * @param inputArgsJson - JSON string of input arguments
255
+ * @returns Promise resolving to the tool's result
256
+ */
257
+ executeTool(toolName: string, inputArgsJson: string): Promise<unknown>;
258
+ /**
259
+ * List all registered tools (Chromium native API)
260
+ * Returns tools with inputSchema as JSON string
261
+ */
262
+ listTools(): ToolInfo[];
263
+ /**
264
+ * Register a callback that fires when the tools list changes (Chromium native API)
265
+ * Callback will fire on: registerTool, unregisterTool, provideContext, clearContext
266
+ */
267
+ registerToolsChangedCallback(callback: () => void): void;
268
+ /**
269
+ * Get all tool calls that have been made (for testing/debugging)
270
+ * Polyfill-specific extension
271
+ */
272
+ getToolCalls(): Array<{
273
+ toolName: string;
274
+ arguments: Record<string, unknown>;
275
+ timestamp: number;
276
+ }>;
277
+ /**
278
+ * Clear the history of tool calls
279
+ * Polyfill-specific extension
280
+ */
281
+ clearToolCalls(): void;
282
+ /**
283
+ * Set a mock response for a specific tool (for testing)
284
+ * When set, the tool's execute function will be bypassed and the mock response returned
285
+ * Polyfill-specific extension
286
+ */
287
+ setMockToolResponse(toolName: string, response: ToolResponse): void;
288
+ /**
289
+ * Clear mock response for a specific tool
290
+ * Polyfill-specific extension
291
+ */
292
+ clearMockToolResponse(toolName: string): void;
293
+ /**
294
+ * Clear all mock tool responses
295
+ * Polyfill-specific extension
296
+ */
297
+ clearAllMockToolResponses(): void;
298
+ /**
299
+ * Get the current tools registered in the system
300
+ * (same as modelContext.listTools but explicitly for testing)
301
+ * Polyfill-specific extension
302
+ */
303
+ getRegisteredTools(): ReturnType<ModelContext['listTools']>;
304
+ /**
305
+ * Reset the entire testing state (clears tool calls and mock responses)
306
+ * Polyfill-specific extension
307
+ */
308
+ reset(): void;
309
+ }
215
310
  declare global {
216
311
  interface Navigator {
217
312
  /**
@@ -219,6 +314,18 @@ declare global {
219
314
  * Provides tools and context to AI agents
220
315
  */
221
316
  modelContext: ModelContext;
317
+ /**
318
+ * Model Context Testing API
319
+ *
320
+ * **IMPORTANT**: This API is only available in Chromium-based browsers
321
+ * with the experimental feature flag enabled:
322
+ * - `chrome://flags` → "Experimental Web Platform Features"
323
+ * - Or launch with: `--enable-experimental-web-platform-features`
324
+ *
325
+ * If not available natively, the @mcp-b/global polyfill provides
326
+ * a compatible implementation.
327
+ */
328
+ modelContextTesting?: ModelContextTesting;
222
329
  }
223
330
  interface Window {
224
331
  /**
@@ -236,13 +343,39 @@ declare global {
236
343
  }
237
344
  }
238
345
  /**
239
- * Initialize the Web Model Context API (window.navigator.modelContext)
346
+ * Initializes the Web Model Context API on window.navigator.
347
+ * Creates and exposes navigator.modelContext and navigator.modelContextTesting.
348
+ * Automatically detects and uses native Chromium implementation if available.
349
+ *
350
+ * @param {WebModelContextInitOptions} [options] - Configuration options
351
+ * @throws {Error} If initialization fails
352
+ * @example
353
+ * ```typescript
354
+ * import { initializeWebModelContext } from '@mcp-b/global';
355
+ *
356
+ * initializeWebModelContext({
357
+ * transport: {
358
+ * tabServer: {
359
+ * allowedOrigins: ['https://example.com']
360
+ * }
361
+ * }
362
+ * });
363
+ * ```
240
364
  */
241
365
  declare function initializeWebModelContext(options?: WebModelContextInitOptions): void;
242
366
  /**
243
- * Cleanup function (for testing/development)
367
+ * Cleans up the Web Model Context API.
368
+ * Closes all MCP servers and removes API from window.navigator.
369
+ * Useful for testing and hot module replacement.
370
+ *
371
+ * @example
372
+ * ```typescript
373
+ * import { cleanupWebModelContext } from '@mcp-b/global';
374
+ *
375
+ * cleanupWebModelContext();
376
+ * ```
244
377
  */
245
378
  declare function cleanupWebModelContext(): void;
246
379
  //#endregion
247
- export { type CallToolResult, InputSchema, InternalModelContext, MCPBridge, ModelContext, ModelContextInput, type ToolAnnotations, ToolCallEvent, ToolDescriptor, ToolResponse, TransportConfiguration, ValidatedToolDescriptor, WebModelContextInitOptions, ZodSchemaObject, cleanupWebModelContext, initializeWebModelContext };
380
+ export { type CallToolResult, InputSchema, InternalModelContext, MCPBridge, ModelContext, ModelContextInput, ModelContextTesting, type ToolAnnotations, ToolCallEvent, ToolDescriptor, ToolInfo, ToolResponse, TransportConfiguration, ValidatedToolDescriptor, WebModelContextInitOptions, ZodSchemaObject, cleanupWebModelContext, initializeWebModelContext };
248
381
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/global.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAeA;AAkBY,UAlBK,WAAA,CAkBU;EAgBf,IAAA,EAAA,MAAA;EAKK,UAAA,CAAA,EArCF,MAqCE,CAAA,MAAsB,EAAA;IAItB,IAAA,EAAA,MAAA;IAOK,WAAA,CAAA,EAAA,MAAA;IAAR,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAOW,CAAA,CAAA;EAAR,QAAA,CAAA,EAAA,MAAA,EAAA;EAAO,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAMxB;AAqBA;;;;AAE0C,KApE9B,eAAA,GAAkB,MAoEY,CAAA,MAAA,EApEG,CAAA,CAAE,UAoEL,CAAA;;;;;AA2CnC,KA/FK,YAAA,GAAe,cA+FpB;;AAQP;;AAIiB,UAtGA,sBAAA,CAsGA;EACD;;;EAC8B,MAAA,CAAA,EAAA,GAAA,GApG7B,SAoG6B;EAG1B;;;AAQpB;AAWA;EASa,SAAA,CAAA,EA5HC,OA4HD,CA5HS,yBA4HT,CAAA,GAAA,KAAA;EAKa;;;AAO1B;;EAcyB,YAAA,CAAA,EA/IR,OA+IQ,CA/IA,2BA+IA,CAAA,GAAA,KAAA;;;;;AAGc,UA5ItB,0BAAA,CA4IsB;EAA7B;;;EAWc,SAAA,CAAA,EAnJV,sBAmJU;EAQF;;;EAOC,cAAA,CAAA,EAAA,OAAA;;;;;;AAmBvB;;;;;AAA0D,UApKzC,cAoKyC,CAAA,qBAnKnC,eAmKmC,GAnKjB,MAmKiB,CAAA,MAAA,EAAA,KAAA,CAAA,EAAA,sBAlKlC,eAkKkC,GAlKhB,MAkKgB,CAAA,MAAA,EAAA,KAAA,CAAA,CAAA,CAAA;EAWzC;;;EAGI,IAAA,EAAA,MAAA;EAAZ;;;EAGR,WAAA,EAAA,MAAA;EAAA;;;;;;;ECnQmB,WAAA,EDmGL,WCnGK,GDmGS,YCnGT;EAAA;;;;AAohBpB;EAwCgB,YAAA,CAAA,EDldC,WCkdqB,GDldP,aCkdO;;;;gBD7ctB;;;;;;;kBASN,qBAAqB,wBACvB,0BACA,CAAA,CAAE,MAAM,CAAA,CAAE,UAAU,mBACrB,QAAQ;;;;;;;UAQE,uBAAA;;;eAGF;iBACE;gBACD;kBACE,4BAA4B,QAAQ;kBAGpC,CAAA,CAAE;oBACA,CAAA,CAAE;;;;;;UAOL,iBAAA;;;;;SAKR;;;;;UAMQ,aAAA,SAAsB;;;;;;;;aAS1B;;;;0BAKa;;;;;;UAOT,YAAA;;;;;;0BAMS;;;;;;oCAQD,kBAAkB,6CACjB,kBAAkB,6BAElC,eAAe,cAAc;;;;;;uDAUjB,yBAAyB,mCACvB;;;;0DAQF,yBAAyB,mCACvB;;;;uBAMD;;;;;eAMR;;;iBAGE;mBACE;kBACD;;;;;;;UAQD,oBAAA,SAA6B;;;;;sCAKR,0BAA0B,QAAQ;;;;;UAMvD,SAAA;aACJ;iBACI;SACR,YAAY;gBACL;;;;;;;;;kBAUE;;;;;;kBAOA;;;;;;;;+BC7Qa;;ADX/B;AAkBA;AAgBA;AAKA;AAIiB,iBC+eD,yBAAA,CD/eC,OAAA,CAAA,EC+emC,0BD/enC,CAAA,EAAA,IAAA;;;;AAcA,iBCygBD,sBAAA,CAAA,CDzgBC,EAAA,IAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/global.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAYA;AAkBY,UAlBK,WAAA,CAkBU;EAgBf,IAAA,EAAA,MAAA;EAKK,UAAA,CAAA,EArCF,MAqCE,CAAA,MAAsB,EAAA;IAItB,IAAA,EAAA,MAAA;IAOK,WAAA,CAAA,EAAA,MAAA;IAAR,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAOW,CAAA,CAAA;EAAR,QAAA,CAAA,EAAA,MAAA,EAAA;EAAO,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;AAMxB;AAqBA;;;;AAE0C,KApE9B,eAAA,GAAkB,MAoEY,CAAA,MAAA,EApEG,CAAA,CAAE,UAoEL,CAAA;;;;;AA2CnC,KA/FK,YAAA,GAAe,cA+FpB;;AAQP;;AAIiB,UAtGA,sBAAA,CAsGA;EACD;;;EAC8B,MAAA,CAAA,EAAA,GAAA,GApG7B,SAoG6B;EAG1B;;;AAQpB;AAWA;EASa,SAAA,CAAA,EA5HC,OA4HD,CA5HS,yBA4HT,CAAA,GAAA,KAAA;EAKa;;;AAO1B;;EAcyB,YAAA,CAAA,EA/IR,OA+IQ,CA/IA,2BA+IA,CAAA,GAAA,KAAA;;;;;AAGc,UA5ItB,0BAAA,CA4IsB;EAA7B;;;EAuBc,SAAA,CAAA,EA/JV,sBA+JU;EAQF;;;EAOC,cAAA,CAAA,EAAA,OAAA;;;;;;AAmBvB;;;;;AAA0D,UAhLzC,cAgLyC,CAAA,qBA/KnC,eA+KmC,GA/KjB,MA+KiB,CAAA,MAAA,EAAA,KAAA,CAAA,EAAA,sBA9KlC,eA8KkC,GA9KhB,MA8KgB,CAAA,MAAA,EAAA,KAAA,CAAA,CAAA,CAAA;EAWzC;;;EAGI,IAAA,EAAA,MAAA;EAAZ;;;EAEkC,WAAA,EAAA,MAAA;EAQ1B;AAqBjB;;;;;;EA6DmC,WAAA,EArQpB,WAqQoB,GArQN,YAqQM;EAAX;;AAOvB;;;EAQiB,YAAA,CAAA,EA7QD,WA6QC,GA7Qa,aA6Qb;EAaQ;;;EAOC,WAAA,CAAA,EA5RX,eA4RW;EAAA;;;;ACrYP;;SAKW,EAAA,CAAA,IAAA,ED6GrB,YC7GqB,SD6GA,MC7G0B,CAAA,MAAA,EAAA,KAAA,CAAA,GD8GjD,MC9GiD,CAAA,MAAA,EAAA,OAAA,CAAA,GD+GjD,CAAA,CAAE,KC/G+C,CD+GzC,CAAA,CAAE,SC/GuC,CD+G7B,YC/G6B,CAAA,CAAA,EAAA,GDgHlD,OChHkD,CDgH1C,YChH0C,CAAA;;;AA0sCzD;AAyHA;;;UD3sCiB,uBAAA;;;eAGF;iBACE;gBACD;kBACE,4BAA4B,QAAQ;kBAGpC,CAAA,CAAE;oBACA,CAAA,CAAE;;;;;;UAOL,iBAAA;;;;;SAKR;;;;;UAMQ,aAAA,SAAsB;;;;;;;;aAS1B;;;;0BAKa;;;;;;UAOT,YAAA;;;;;;0BAMS;;;;;;oCAQD,kBAAkB,6CACjB,kBAAkB,6BAElC,eAAe,cAAc;;;;;;;;;;;;;;;;uDAsBjB,yBAAyB,mCACvB;;;;0DAQF,yBAAyB,mCACvB;;;;uBAMD;;;;;eAMR;;;iBAGE;mBACE;kBACD;;;;;;;UAQD,oBAAA,SAA6B;;;;;sCAKR,0BAA0B,QAAQ;;;;;UAMvD,SAAA;aACJ;iBACI;SACR,YAAY;gBACL;wBACQ;;;;;;;UAQP,QAAA;;;;;;;;;;;;;;;;;;;;UAqBA,mBAAA;;;;;;;wDAOuC;;;;;eAMzC;;;;;;;;;;kBAYG;;eAEH;;;;;;;;;;;;;kDAemC;;;;;;;;;;;;;;;;wBAmB1B,WAAW;;;;;;;;;;;;;kBAejB;;;;;;;;;;;;0BAaQ;;;;;;kBAOR;;;;;;;;+BChYa;;ADjB/B;AAkBA;AAgBA;AAKA;;;;;;;AAwBA;AAqBA;;;;;;;;;;AA0CU,iBC6lCM,yBAAA,CD7lCN,OAAA,CAAA,EC6lC0C,0BD7lC1C,CAAA,EAAA,IAAA;;;;;;;;;AAWV;;;;AAMkB,iBCqsCF,sBAAA,CAAA,CDrsCE,EAAA,IAAA"}
@@ -5,4 +5,4 @@ ${t}`:t}else if(e.examples!==void 0&&Array.isArray(e.examples)){let t=e.examples
5
5
  ${t.map(e=>` ${JSON.stringify(e)}`).join(`
6
6
  `)}`;n=n?`${n}
7
7
  ${e}`:e}}return n&&(t=t.describe(n)),t},di=(e,t,n)=>{if(e.default!==void 0){if(e.default===null&&n?.path.some(e=>e===`anyOf`||e===`oneOf`)&&e.type&&e.type!==`null`&&!e.nullable)return t;t=t.default(e.default)}return t},fi=(e,t)=>(e.readOnly&&(t=t.readonly()),t),pi=(e,t)=>qr.a.nullable(e)?ii(e,t):qr.an.object(e)?ci(e,t):qr.an.array(e)?Jr(e,t):qr.an.anyOf(e)?Kr(e,t):qr.an.allOf(e)?Gr(e,t):qr.a.oneOf(e)?oi(e,t):qr.a.not(e)?ti(e,t):qr.an.enum(e)?Qr(e):qr.a.const(e)?Xr(e):qr.a.multipleType(e)?ei(e,t):qr.a.primitive(e,`string`)?li(e):qr.a.primitive(e,`number`)||qr.a.primitive(e,`integer`)?ai(e):qr.a.primitive(e,`boolean`)?Yr(e):qr.a.primitive(e,`null`)?ni(e):qr.a.conditional(e)?$r(e,t):Zr(e),mi=(e,t={seen:new Map,path:[]},n)=>{if(typeof e!=`object`)return e?nt():it();if(t.parserOverride){let n=t.parserOverride(e,t);if(n instanceof P)return n}let r=t.seen.get(e);if(r){if(r.r!==void 0)return r.r;if(t.depth===void 0||r.n>=t.depth)return nt();r.n+=1}else r={r:void 0,n:0},t.seen.set(e,r);let i=pi(e,t);return n||(t.withoutDescribes||(i=ui(e,i)),t.withoutDefaults||(i=di(e,i,t)),i=fi(e,i)),r.r=i,i},hi=(e,t={})=>mi(e,{path:[],seen:new Map,...t});function gi(e){if(typeof e!=`object`||!e||`type`in e&&typeof e.type==`string`)return!1;let t=Object.values(e);return t.length===0?!1:t.some(e=>e instanceof P)}function _i(e){try{return hi(e)}catch(e){return console.warn(`[Web Model Context] Failed to convert JSON Schema to Zod:`,e),Y({}).passthrough()}}function vi(e){let t={},n=[];for(let[r,i]of Object.entries(e)){let e=i.description||void 0,a=`string`,o,s;if(i instanceof pe)a=`string`;else if(i instanceof he)a=`number`;else if(i instanceof _e)a=`boolean`;else if(i instanceof Te){a=`array`;let e=i.element;s=e instanceof pe?{type:`string`}:e instanceof he?{type:`number`}:e instanceof _e?{type:`boolean`}:{type:`string`}}else if(i instanceof De)a=`object`;else if(i instanceof Ve){a=`string`;let e=i._def;e?.values&&(o=e.values)}let c={type:a};e&&(c.description=e),o&&(c.enum=o),s&&(c.items=s),t[r]=c,i.isOptional()||n.push(r)}return{type:`object`,properties:t,...n.length>0&&{required:n}}}function yi(e){if(gi(e))return{jsonSchema:vi(e),zodValidator:Y(e)};let t=e;return{jsonSchema:t,zodValidator:_i(t)}}function bi(e,t){let n=t.safeParse(e);return n.success?{success:!0,data:n.data}:{success:!1,error:`Validation failed:\n${n.error.errors.map(e=>` - ${e.path.join(`.`)||`root`}: ${e.message}`).join(`
8
- `)}`}}var xi=class extends Event{name;arguments;_response=null;_responded=!1;constructor(e,t){super(`toolcall`,{cancelable:!0}),this.name=e,this.arguments=t}respondWith(e){if(this._responded)throw Error(`Response already provided for this tool call`);this._response=e,this._responded=!0}getResponse(){return this._response}hasResponse(){return this._responded}},Si=class{bridge;eventTarget;provideContextTools;dynamicTools;registrationTimestamps;unregisterFunctions;constructor(e){this.bridge=e,this.eventTarget=new EventTarget,this.provideContextTools=new Map,this.dynamicTools=new Map,this.registrationTimestamps=new Map,this.unregisterFunctions=new Map}addEventListener(e,t,n){this.eventTarget.addEventListener(e,t,n)}removeEventListener(e,t,n){this.eventTarget.removeEventListener(e,t,n)}dispatchEvent(e){return this.eventTarget.dispatchEvent(e)}provideContext(e){console.log(`[Web Model Context] Registering ${e.tools.length} tools via provideContext`),this.provideContextTools.clear();for(let t of e.tools){if(this.dynamicTools.has(t.name))throw Error(`[Web Model Context] Tool name collision: "${t.name}" is already registered via registerTool(). Please use a different name or unregister the dynamic tool first.`);let{jsonSchema:e,zodValidator:n}=yi(t.inputSchema),r=t.outputSchema?yi(t.outputSchema):null,i={name:t.name,description:t.description,inputSchema:e,...r&&{outputSchema:r.jsonSchema},...t.annotations&&{annotations:t.annotations},execute:t.execute,inputValidator:n,...r&&{outputValidator:r.zodValidator}};this.provideContextTools.set(t.name,i)}this.updateBridgeTools(),this.notifyToolsListChanged()}registerTool(e){console.log(`[Web Model Context] Registering tool dynamically: ${e.name}`);let t=Date.now(),n=this.registrationTimestamps.get(e.name);if(n&&t-n<50){console.warn(`[Web Model Context] Tool "${e.name}" registered multiple times within 50ms. This is likely due to React Strict Mode double-mounting. Ignoring duplicate registration.`);let t=this.unregisterFunctions.get(e.name);if(t)return{unregister:t}}if(this.provideContextTools.has(e.name))throw Error(`[Web Model Context] Tool name collision: "${e.name}" is already registered via provideContext(). Please use a different name or update your provideContext() call.`);if(this.dynamicTools.has(e.name))throw Error(`[Web Model Context] Tool name collision: "${e.name}" is already registered via registerTool(). Please unregister it first or use a different name.`);let{jsonSchema:r,zodValidator:i}=yi(e.inputSchema),a=e.outputSchema?yi(e.outputSchema):null,o={name:e.name,description:e.description,inputSchema:r,...a&&{outputSchema:a.jsonSchema},...e.annotations&&{annotations:e.annotations},execute:e.execute,inputValidator:i,...a&&{outputValidator:a.zodValidator}};this.dynamicTools.set(e.name,o),this.registrationTimestamps.set(e.name,t),this.updateBridgeTools(),this.notifyToolsListChanged();let s=()=>{if(console.log(`[Web Model Context] Unregistering tool: ${e.name}`),this.provideContextTools.has(e.name))throw Error(`[Web Model Context] Cannot unregister tool "${e.name}": This tool was registered via provideContext(). Use provideContext() to update the base tool set.`);if(!this.dynamicTools.has(e.name)){console.warn(`[Web Model Context] Tool "${e.name}" is not registered, ignoring unregister call`);return}this.dynamicTools.delete(e.name),this.registrationTimestamps.delete(e.name),this.unregisterFunctions.delete(e.name),this.updateBridgeTools(),this.notifyToolsListChanged()};return this.unregisterFunctions.set(e.name,s),{unregister:s}}updateBridgeTools(){this.bridge.tools.clear();for(let[e,t]of this.provideContextTools)this.bridge.tools.set(e,t);for(let[e,t]of this.dynamicTools)this.bridge.tools.set(e,t);console.log(`[Web Model Context] Updated bridge with ${this.provideContextTools.size} base tools + ${this.dynamicTools.size} dynamic tools = ${this.bridge.tools.size} total`)}notifyToolsListChanged(){this.bridge.tabServer.notification&&this.bridge.tabServer.notification({method:`notifications/tools/list_changed`,params:{}}),this.bridge.iframeServer?.notification&&this.bridge.iframeServer.notification({method:`notifications/tools/list_changed`,params:{}})}async executeTool(e,t){let n=this.bridge.tools.get(e);if(!n)throw Error(`Tool not found: ${e}`);console.log(`[Web Model Context] Validating input for tool: ${e}`);let r=bi(t,n.inputValidator);if(!r.success)return console.error(`[Web Model Context] Input validation failed for ${e}:`,r.error),{content:[{type:`text`,text:`Input validation error for tool "${e}":\n${r.error}`}],isError:!0};let i=r.data,a=new xi(e,i);if(this.dispatchEvent(a),a.defaultPrevented&&a.hasResponse()){let t=a.getResponse();if(t)return console.log(`[Web Model Context] Tool ${e} handled by event listener`),t}console.log(`[Web Model Context] Executing tool: ${e}`);try{let t=await n.execute(i);if(n.outputValidator&&t.structuredContent){let r=bi(t.structuredContent,n.outputValidator);r.success||console.warn(`[Web Model Context] Output validation failed for ${e}:`,r.error)}return t}catch(t){return console.error(`[Web Model Context] Error executing tool ${e}:`,t),{content:[{type:`text`,text:`Error: ${t instanceof Error?t.message:String(t)}`}],isError:!0}}}listTools(){return Array.from(this.bridge.tools.values()).map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,...e.outputSchema&&{outputSchema:e.outputSchema},...e.annotations&&{annotations:e.annotations}}))}};function Ci(e){console.log(`[Web Model Context] Initializing MCP bridge`);let n=window.location.hostname||`localhost`,r=e?.transport,i=(e,t)=>{e.setRequestHandler(bn,async()=>(console.log(`[MCP Bridge] Handling list_tools request`),{tools:t.modelContext.listTools()})),e.setRequestHandler(Cn,async e=>{console.log(`[MCP Bridge] Handling call_tool request: ${e.params.name}`);let n=e.params.name,r=e.params.arguments||{};try{let e=await t.modelContext.executeTool(n,r);return{content:e.content,isError:e.isError}}catch(e){throw console.error(`[MCP Bridge] Error calling tool ${n}:`,e),e}})},a=r?.create?.();if(a){console.log(`[Web Model Context] Using custom transport`);let e=new Rr({name:n,version:`1.0.0`},{capabilities:{tools:{listChanged:!0}}}),t={tabServer:e,tools:new Map,modelContext:void 0,isInitialized:!0};return t.modelContext=new Si(t),i(e,t),e.connect(a),console.log(`[Web Model Context] MCP server connected with custom transport`),t}console.log(`[Web Model Context] Using dual-server mode`);let o=r?.tabServer!==!1,s=new Rr({name:`${n}-tab`,version:`1.0.0`},{capabilities:{tools:{listChanged:!0}}}),c={tabServer:s,tools:new Map,modelContext:void 0,isInitialized:!0};if(c.modelContext=new Si(c),i(s,c),o){let{allowedOrigins:e,...n}=typeof r?.tabServer==`object`?r.tabServer:{},i=new t.TabServerTransport({allowedOrigins:e??[`*`],...n});s.connect(i),console.log(`[Web Model Context] Tab server connected`)}let l=typeof window<`u`&&window.parent!==window,u=r?.iframeServer;if(u!==!1&&(u!==void 0||l)){console.log(`[Web Model Context] Enabling iframe server`);let e=new Rr({name:`${n}-iframe`,version:`1.0.0`},{capabilities:{tools:{listChanged:!0}}});i(e,c);let{allowedOrigins:r,...a}=typeof u==`object`?u:{},o=new t.IframeChildTransport({allowedOrigins:r??[`*`],...a});e.connect(o),c.iframeServer=e,console.log(`[Web Model Context] Iframe server connected`)}return c}function wi(e){if(typeof window>`u`){console.warn(`[Web Model Context] Not in browser environment, skipping initialization`);return}let t=e??window.__webModelContextOptions;if(window.navigator.modelContext){console.warn(`[Web Model Context] window.navigator.modelContext already exists, skipping initialization`);return}try{let e=Ci(t);Object.defineProperty(window.navigator,`modelContext`,{value:e.modelContext,writable:!1,configurable:!1}),Object.defineProperty(window,`__mcpBridge`,{value:e,writable:!1,configurable:!0}),console.log(`✅ [Web Model Context] window.navigator.modelContext initialized successfully`)}catch(e){throw console.error(`[Web Model Context] Failed to initialize:`,e),e}}function Ti(){if(!(typeof window>`u`)){if(window.__mcpBridge)try{window.__mcpBridge.tabServer.close(),window.__mcpBridge.iframeServer&&window.__mcpBridge.iframeServer.close()}catch(e){console.warn(`[Web Model Context] Error closing MCP servers:`,e)}delete window.navigator.modelContext,delete window.__mcpBridge,console.log(`[Web Model Context] Cleaned up`)}}function Ei(e,t){return e?t?{...e,...t,tabServer:{...e.tabServer??{},...t.tabServer??{}}}:e:t}function Di(e,t){return e?t?{...e,...t,transport:Ei(e.transport??{},t.transport??{})}:e:t}function Oi(e){if(!e||!e.dataset)return;let{dataset:t}=e;if(t.webmcpOptions)try{return JSON.parse(t.webmcpOptions)}catch(e){console.error(`[Web Model Context] Invalid JSON in data-webmcp-options:`,e);return}let n={},r=!1;t.webmcpAutoInitialize!==void 0&&(n.autoInitialize=t.webmcpAutoInitialize!==`false`,r=!0);let i={},a=!1;if(t.webmcpAllowedOrigins){let e=t.webmcpAllowedOrigins.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);e.length>0&&(i.allowedOrigins=e,r=!0,a=!0)}return t.webmcpChannelId&&(i.channelId=t.webmcpChannelId,r=!0,a=!0),a&&(n.transport={...n.transport??{},tabServer:{...n.transport?.tabServer??{},...i}}),r?n:void 0}if(typeof window<`u`&&typeof document<`u`){let e=window.__webModelContextOptions,t=document.currentScript,n=Oi(t),r=Di(e,n)??e??n;r&&(window.__webModelContextOptions=r);let i=r?.autoInitialize!==!1;try{i&&wi(r)}catch(e){console.error(`[Web Model Context] Auto-initialization failed:`,e)}}return e.cleanupWebModelContext=Ti,e.initializeWebModelContext=wi,e})({},__mcp_b_transports);
8
+ `)}`}}function xi(){if(typeof window>`u`||typeof navigator>`u`)return{hasNativeContext:!1,hasNativeTesting:!1};let e=navigator.modelContext,t=navigator.modelContextTesting;return!e||!t||(t.constructor?.name||``).includes(`WebModelContext`)?{hasNativeContext:!1,hasNativeTesting:!1}:{hasNativeContext:!0,hasNativeTesting:!0}}var Si=class{nativeContext;nativeTesting;bridge;syncInProgress=!1;constructor(e,t,n){this.bridge=e,this.nativeContext=t,this.nativeTesting=n,this.nativeTesting.registerToolsChangedCallback(()=>{console.log(`[Native Adapter] Tool change detected from native API`),this.syncToolsFromNative()}),this.syncToolsFromNative()}syncToolsFromNative(){if(!this.syncInProgress){this.syncInProgress=!0;try{let e=this.nativeTesting.listTools();console.log(`[Native Adapter] Syncing ${e.length} tools from native API`),this.bridge.tools.clear();for(let t of e)try{let e=JSON.parse(t.inputSchema),n={name:t.name,description:t.description,inputSchema:e,execute:async e=>{let n=await this.nativeTesting.executeTool(t.name,JSON.stringify(e));return this.convertToToolResponse(n)},inputValidator:_i(e)};this.bridge.tools.set(t.name,n)}catch(e){console.error(`[Native Adapter] Failed to sync tool "${t.name}":`,e)}this.notifyMCPServers()}finally{this.syncInProgress=!1}}}convertToToolResponse(e){return typeof e==`string`?{content:[{type:`text`,text:e}]}:e==null?{content:[{type:`text`,text:``}]}:typeof e==`object`?{content:[{type:`text`,text:JSON.stringify(e,null,2)}],structuredContent:e}:{content:[{type:`text`,text:String(e)}]}}notifyMCPServers(){this.bridge.tabServer?.notification&&this.bridge.tabServer.notification({method:`notifications/tools/list_changed`,params:{}}),this.bridge.iframeServer?.notification&&this.bridge.iframeServer.notification({method:`notifications/tools/list_changed`,params:{}})}provideContext(e){console.log(`[Native Adapter] Delegating provideContext to native API`),this.nativeContext.provideContext(e)}registerTool(e){return console.log(`[Native Adapter] Delegating registerTool("${e.name}") to native API`),this.nativeContext.registerTool(e)}unregisterTool(e){console.log(`[Native Adapter] Delegating unregisterTool("${e}") to native API`),this.nativeContext.unregisterTool(e)}clearContext(){console.log(`[Native Adapter] Delegating clearContext to native API`),this.nativeContext.clearContext()}async executeTool(e,t){console.log(`[Native Adapter] Executing tool "${e}" via native API`);try{let n=await this.nativeTesting.executeTool(e,JSON.stringify(t));return this.convertToToolResponse(n)}catch(t){return console.error(`[Native Adapter] Error executing tool "${e}":`,t),{content:[{type:`text`,text:`Error: ${t instanceof Error?t.message:String(t)}`}],isError:!0}}}listTools(){return Array.from(this.bridge.tools.values()).map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,...e.outputSchema&&{outputSchema:e.outputSchema},...e.annotations&&{annotations:e.annotations}}))}addEventListener(e,t,n){this.nativeContext.addEventListener(e,t,n)}removeEventListener(e,t,n){this.nativeContext.removeEventListener(e,t,n)}dispatchEvent(e){return this.nativeContext.dispatchEvent(e)}},Ci=class extends Event{name;arguments;_response=null;_responded=!1;constructor(e,t){super(`toolcall`,{cancelable:!0}),this.name=e,this.arguments=t}respondWith(e){if(this._responded)throw Error(`Response already provided for this tool call`);this._response=e,this._responded=!0}getResponse(){return this._response}hasResponse(){return this._responded}},wi=class{toolCallHistory=[];mockResponses=new Map;toolsChangedCallbacks=new Set;bridge;constructor(e){this.bridge=e}recordToolCall(e,t){this.toolCallHistory.push({toolName:e,arguments:t,timestamp:Date.now()})}hasMockResponse(e){return this.mockResponses.has(e)}getMockResponse(e){return this.mockResponses.get(e)}notifyToolsChanged(){for(let e of this.toolsChangedCallbacks)try{e()}catch(e){console.error(`[Model Context Testing] Error in tools changed callback:`,e)}}async executeTool(e,t){console.log(`[Model Context Testing] Executing tool: ${e}`);let n;try{n=JSON.parse(t)}catch(e){throw SyntaxError(`Invalid JSON input: ${e instanceof Error?e.message:String(e)}`)}if(!this.bridge.tools.get(e))throw Error(`Tool not found: ${e}`);let r=await this.bridge.modelContext.executeTool(e,n);if(!r.isError){if(r.structuredContent)return r.structuredContent;if(r.content&&r.content.length>0){let e=r.content[0];if(e&&e.type===`text`)return e.text}}}listTools(){return this.bridge.modelContext.listTools().map(e=>({name:e.name,description:e.description,inputSchema:JSON.stringify(e.inputSchema)}))}registerToolsChangedCallback(e){this.toolsChangedCallbacks.add(e),console.log(`[Model Context Testing] Tools changed callback registered`)}getToolCalls(){return[...this.toolCallHistory]}clearToolCalls(){this.toolCallHistory=[],console.log(`[Model Context Testing] Tool call history cleared`)}setMockToolResponse(e,t){this.mockResponses.set(e,t),console.log(`[Model Context Testing] Mock response set for tool: ${e}`)}clearMockToolResponse(e){this.mockResponses.delete(e),console.log(`[Model Context Testing] Mock response cleared for tool: ${e}`)}clearAllMockToolResponses(){this.mockResponses.clear(),console.log(`[Model Context Testing] All mock responses cleared`)}getRegisteredTools(){return this.bridge.modelContext.listTools()}reset(){this.clearToolCalls(),this.clearAllMockToolResponses(),console.log(`[Model Context Testing] Testing state reset`)}},Ti=class{bridge;eventTarget;provideContextTools;dynamicTools;registrationTimestamps;unregisterFunctions;testingAPI;constructor(e){this.bridge=e,this.eventTarget=new EventTarget,this.provideContextTools=new Map,this.dynamicTools=new Map,this.registrationTimestamps=new Map,this.unregisterFunctions=new Map}setTestingAPI(e){this.testingAPI=e}addEventListener(e,t,n){this.eventTarget.addEventListener(e,t,n)}removeEventListener(e,t,n){this.eventTarget.removeEventListener(e,t,n)}dispatchEvent(e){return this.eventTarget.dispatchEvent(e)}provideContext(e){console.log(`[Web Model Context] Registering ${e.tools.length} tools via provideContext`),this.provideContextTools.clear();for(let t of e.tools){if(this.dynamicTools.has(t.name))throw Error(`[Web Model Context] Tool name collision: "${t.name}" is already registered via registerTool(). Please use a different name or unregister the dynamic tool first.`);let{jsonSchema:e,zodValidator:n}=yi(t.inputSchema),r=t.outputSchema?yi(t.outputSchema):null,i={name:t.name,description:t.description,inputSchema:e,...r&&{outputSchema:r.jsonSchema},...t.annotations&&{annotations:t.annotations},execute:t.execute,inputValidator:n,...r&&{outputValidator:r.zodValidator}};this.provideContextTools.set(t.name,i)}this.updateBridgeTools(),this.notifyToolsListChanged()}registerTool(e){console.log(`[Web Model Context] Registering tool dynamically: ${e.name}`);let t=Date.now(),n=this.registrationTimestamps.get(e.name);if(n&&t-n<50){console.warn(`[Web Model Context] Tool "${e.name}" registered multiple times within 50ms. This is likely due to React Strict Mode double-mounting. Ignoring duplicate registration.`);let t=this.unregisterFunctions.get(e.name);if(t)return{unregister:t}}if(this.provideContextTools.has(e.name))throw Error(`[Web Model Context] Tool name collision: "${e.name}" is already registered via provideContext(). Please use a different name or update your provideContext() call.`);if(this.dynamicTools.has(e.name))throw Error(`[Web Model Context] Tool name collision: "${e.name}" is already registered via registerTool(). Please unregister it first or use a different name.`);let{jsonSchema:r,zodValidator:i}=yi(e.inputSchema),a=e.outputSchema?yi(e.outputSchema):null,o={name:e.name,description:e.description,inputSchema:r,...a&&{outputSchema:a.jsonSchema},...e.annotations&&{annotations:e.annotations},execute:e.execute,inputValidator:i,...a&&{outputValidator:a.zodValidator}};this.dynamicTools.set(e.name,o),this.registrationTimestamps.set(e.name,t),this.updateBridgeTools(),this.notifyToolsListChanged();let s=()=>{if(console.log(`[Web Model Context] Unregistering tool: ${e.name}`),this.provideContextTools.has(e.name))throw Error(`[Web Model Context] Cannot unregister tool "${e.name}": This tool was registered via provideContext(). Use provideContext() to update the base tool set.`);if(!this.dynamicTools.has(e.name)){console.warn(`[Web Model Context] Tool "${e.name}" is not registered, ignoring unregister call`);return}this.dynamicTools.delete(e.name),this.registrationTimestamps.delete(e.name),this.unregisterFunctions.delete(e.name),this.updateBridgeTools(),this.notifyToolsListChanged()};return this.unregisterFunctions.set(e.name,s),{unregister:s}}unregisterTool(e){console.log(`[Web Model Context] Unregistering tool: ${e}`);let t=this.provideContextTools.has(e),n=this.dynamicTools.has(e);if(!t&&!n){console.warn(`[Web Model Context] Tool "${e}" is not registered, ignoring unregister call`);return}t&&this.provideContextTools.delete(e),n&&(this.dynamicTools.delete(e),this.registrationTimestamps.delete(e),this.unregisterFunctions.delete(e)),this.updateBridgeTools(),this.notifyToolsListChanged()}clearContext(){console.log(`[Web Model Context] Clearing all tools`),this.provideContextTools.clear(),this.dynamicTools.clear(),this.registrationTimestamps.clear(),this.unregisterFunctions.clear(),this.updateBridgeTools(),this.notifyToolsListChanged()}updateBridgeTools(){this.bridge.tools.clear();for(let[e,t]of this.provideContextTools)this.bridge.tools.set(e,t);for(let[e,t]of this.dynamicTools)this.bridge.tools.set(e,t);console.log(`[Web Model Context] Updated bridge with ${this.provideContextTools.size} base tools + ${this.dynamicTools.size} dynamic tools = ${this.bridge.tools.size} total`)}notifyToolsListChanged(){this.bridge.tabServer.notification&&this.bridge.tabServer.notification({method:`notifications/tools/list_changed`,params:{}}),this.bridge.iframeServer?.notification&&this.bridge.iframeServer.notification({method:`notifications/tools/list_changed`,params:{}}),this.testingAPI&&`notifyToolsChanged`in this.testingAPI&&this.testingAPI.notifyToolsChanged()}async executeTool(e,t){let n=this.bridge.tools.get(e);if(!n)throw Error(`Tool not found: ${e}`);console.log(`[Web Model Context] Validating input for tool: ${e}`);let r=bi(t,n.inputValidator);if(!r.success)return console.error(`[Web Model Context] Input validation failed for ${e}:`,r.error),{content:[{type:`text`,text:`Input validation error for tool "${e}":\n${r.error}`}],isError:!0};let i=r.data;if(this.testingAPI&&this.testingAPI.recordToolCall(e,i),this.testingAPI?.hasMockResponse(e)){let t=this.testingAPI.getMockResponse(e);if(t)return console.log(`[Web Model Context] Returning mock response for tool: ${e}`),t}let a=new Ci(e,i);if(this.dispatchEvent(a),a.defaultPrevented&&a.hasResponse()){let t=a.getResponse();if(t)return console.log(`[Web Model Context] Tool ${e} handled by event listener`),t}console.log(`[Web Model Context] Executing tool: ${e}`);try{let t=await n.execute(i);if(n.outputValidator&&t.structuredContent){let r=bi(t.structuredContent,n.outputValidator);r.success||console.warn(`[Web Model Context] Output validation failed for ${e}:`,r.error)}return t}catch(t){return console.error(`[Web Model Context] Error executing tool ${e}:`,t),{content:[{type:`text`,text:`Error: ${t instanceof Error?t.message:String(t)}`}],isError:!0}}}listTools(){return Array.from(this.bridge.tools.values()).map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,...e.outputSchema&&{outputSchema:e.outputSchema},...e.annotations&&{annotations:e.annotations}}))}};function Ei(e){console.log(`[Web Model Context] Initializing MCP bridge`);let n=window.location.hostname||`localhost`,r=e?.transport,i=(e,t)=>{e.setRequestHandler(bn,async()=>(console.log(`[MCP Bridge] Handling list_tools request`),{tools:t.modelContext.listTools()})),e.setRequestHandler(Cn,async e=>{console.log(`[MCP Bridge] Handling call_tool request: ${e.params.name}`);let n=e.params.name,r=e.params.arguments||{};try{let e=await t.modelContext.executeTool(n,r);return{content:e.content,isError:e.isError}}catch(e){throw console.error(`[MCP Bridge] Error calling tool ${n}:`,e),e}})},a=r?.create?.();if(a){console.log(`[Web Model Context] Using custom transport`);let e=new Rr({name:n,version:`1.0.0`},{capabilities:{tools:{listChanged:!0}}}),t={tabServer:e,tools:new Map,modelContext:void 0,isInitialized:!0};return t.modelContext=new Ti(t),i(e,t),e.connect(a),console.log(`[Web Model Context] MCP server connected with custom transport`),t}console.log(`[Web Model Context] Using dual-server mode`);let o=r?.tabServer!==!1,s=new Rr({name:`${n}-tab`,version:`1.0.0`},{capabilities:{tools:{listChanged:!0}}}),c={tabServer:s,tools:new Map,modelContext:void 0,isInitialized:!0};if(c.modelContext=new Ti(c),i(s,c),o){let{allowedOrigins:e,...n}=typeof r?.tabServer==`object`?r.tabServer:{},i=new t.TabServerTransport({allowedOrigins:e??[`*`],...n});s.connect(i),console.log(`[Web Model Context] Tab server connected`)}let l=typeof window<`u`&&window.parent!==window,u=r?.iframeServer;if(u!==!1&&(u!==void 0||l)){console.log(`[Web Model Context] Enabling iframe server`);let e=new Rr({name:`${n}-iframe`,version:`1.0.0`},{capabilities:{tools:{listChanged:!0}}});i(e,c);let{allowedOrigins:r,...a}=typeof u==`object`?u:{},o=new t.IframeChildTransport({allowedOrigins:r??[`*`],...a});e.connect(o),c.iframeServer=e,console.log(`[Web Model Context] Iframe server connected`)}return c}function Di(e){if(typeof window>`u`){console.warn(`[Web Model Context] Not in browser environment, skipping initialization`);return}let t=e??window.__webModelContextOptions,n=xi();if(n.hasNativeContext&&n.hasNativeTesting){let e=window.navigator.modelContext,n=window.navigator.modelContextTesting;if(!e||!n){console.error(`[Web Model Context] Native API detection mismatch`);return}console.log(`✅ [Web Model Context] Native Chromium API detected`),console.log(` Using native implementation with MCP bridge synchronization`),console.log(` Native API will automatically collect tools from embedded iframes`);try{let r=Ei(t);r.modelContext=new Si(r,e,n),r.modelContextTesting=n,Object.defineProperty(window,`__mcpBridge`,{value:r,writable:!1,configurable:!0}),console.log(`✅ [Web Model Context] MCP bridge synced with native API`),console.log(` MCP clients will receive automatic tool updates from native registry`)}catch(e){throw console.error(`[Web Model Context] Failed to initialize native adapter:`,e),e}return}if(n.hasNativeContext&&!n.hasNativeTesting){console.warn(`[Web Model Context] Partial native API detected`),console.warn(` navigator.modelContext exists but navigator.modelContextTesting is missing`),console.warn(` Cannot sync with native API. Please enable experimental features:`),console.warn(` - Navigate to chrome://flags`),console.warn(` - Enable "Experimental Web Platform Features"`),console.warn(` - Or launch with: --enable-experimental-web-platform-features`),console.warn(` Skipping initialization to avoid conflicts`);return}if(window.navigator.modelContext){console.warn(`[Web Model Context] window.navigator.modelContext already exists, skipping initialization`);return}console.log(`[Web Model Context] Native API not detected, installing polyfill`);try{let e=Ei(t);Object.defineProperty(window.navigator,`modelContext`,{value:e.modelContext,writable:!1,configurable:!1}),Object.defineProperty(window,`__mcpBridge`,{value:e,writable:!1,configurable:!0}),console.log(`✅ [Web Model Context] window.navigator.modelContext initialized successfully`),console.log(`[Model Context Testing] Installing polyfill`),console.log(` 💡 To use the native implementation in Chromium:`),console.log(` - Navigate to chrome://flags`),console.log(` - Enable "Experimental Web Platform Features"`),console.log(` - Or launch with: --enable-experimental-web-platform-features`);let n=new wi(e);e.modelContextTesting=n,e.modelContext.setTestingAPI(n),Object.defineProperty(window.navigator,`modelContextTesting`,{value:n,writable:!1,configurable:!0}),console.log(`✅ [Model Context Testing] Polyfill installed at window.navigator.modelContextTesting`)}catch(e){throw console.error(`[Web Model Context] Failed to initialize:`,e),e}}function Oi(){if(!(typeof window>`u`)){if(window.__mcpBridge)try{window.__mcpBridge.tabServer.close(),window.__mcpBridge.iframeServer&&window.__mcpBridge.iframeServer.close()}catch(e){console.warn(`[Web Model Context] Error closing MCP servers:`,e)}delete window.navigator.modelContext,delete window.navigator.modelContextTesting,delete window.__mcpBridge,console.log(`[Web Model Context] Cleaned up`)}}function ki(e,t){return e?t?{...e,...t,tabServer:{...e.tabServer??{},...t.tabServer??{}}}:e:t}function Ai(e,t){return e?t?{...e,...t,transport:ki(e.transport??{},t.transport??{})}:e:t}function ji(e){if(!e||!e.dataset)return;let{dataset:t}=e;if(t.webmcpOptions)try{return JSON.parse(t.webmcpOptions)}catch(e){console.error(`[Web Model Context] Invalid JSON in data-webmcp-options:`,e);return}let n={},r=!1;t.webmcpAutoInitialize!==void 0&&(n.autoInitialize=t.webmcpAutoInitialize!==`false`,r=!0);let i={},a=!1;if(t.webmcpAllowedOrigins){let e=t.webmcpAllowedOrigins.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);e.length>0&&(i.allowedOrigins=e,r=!0,a=!0)}return t.webmcpChannelId&&(i.channelId=t.webmcpChannelId,r=!0,a=!0),a&&(n.transport={...n.transport??{},tabServer:{...n.transport?.tabServer??{},...i}}),r?n:void 0}if(typeof window<`u`&&typeof document<`u`){let e=window.__webModelContextOptions,t=document.currentScript,n=ji(t),r=Ai(e,n)??e??n;r&&(window.__webModelContextOptions=r);let i=r?.autoInitialize!==!1;try{i&&Di(r)}catch(e){console.error(`[Web Model Context] Auto-initialization failed:`,e)}}return e.cleanupWebModelContext=Oi,e.initializeWebModelContext=Di,e})({},__mcp_b_transports);