@mcp-b/global 4.0.0 → 5.0.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 +114 -99
- package/dist/index.d.ts +16 -17
- package/dist/index.iife.js +5 -14
- package/dist/index.js +65 -126
- package/dist/index.js.map +1 -1
- package/package.json +12 -16
- package/dist/index.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IframeChildTransport, TabServerTransport } from "@mcp-b/transports";
|
|
2
2
|
import { initializeWebMCPPolyfill } from "@mcp-b/webmcp-polyfill";
|
|
3
|
-
import { BrowserMcpServer,
|
|
3
|
+
import { BrowserMcpServer, isBrowserMcpServer } from "@mcp-b/webmcp-ts-sdk";
|
|
4
4
|
|
|
5
5
|
//#region src/global.ts
|
|
6
6
|
let runtime = null;
|
|
@@ -8,155 +8,96 @@ function isBrowserEnvironment() {
|
|
|
8
8
|
return typeof window !== "undefined" && typeof window.navigator !== "undefined";
|
|
9
9
|
}
|
|
10
10
|
function readCurrentModelContext() {
|
|
11
|
-
if (Object.getOwnPropertyDescriptor(navigator, "modelContext")) return navigator.modelContext;
|
|
12
11
|
return document.modelContext ?? navigator.modelContext;
|
|
13
12
|
}
|
|
14
13
|
function replaceDocumentModelContext(value) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
});
|
|
22
|
-
} catch {
|
|
23
|
-
Object.defineProperty(Object.getPrototypeOf(document), "modelContext", {
|
|
24
|
-
configurable: true,
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get() {
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
14
|
+
Object.defineProperty(document, "modelContext", {
|
|
15
|
+
configurable: true,
|
|
16
|
+
enumerable: true,
|
|
17
|
+
writable: false,
|
|
18
|
+
value
|
|
19
|
+
});
|
|
31
20
|
if (document.modelContext !== value) console.error("[WebModelContext] Failed to replace document.modelContext.", "Descriptor:", Object.getOwnPropertyDescriptor(document, "modelContext"));
|
|
32
21
|
}
|
|
33
22
|
function replaceNavigatorModelContext(value) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
} catch {
|
|
42
|
-
Object.defineProperty(Object.getPrototypeOf(navigator), "modelContext", {
|
|
43
|
-
configurable: true,
|
|
44
|
-
enumerable: true,
|
|
45
|
-
get() {
|
|
46
|
-
return value;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
23
|
+
Object.defineProperty(navigator, "modelContext", {
|
|
24
|
+
configurable: true,
|
|
25
|
+
enumerable: true,
|
|
26
|
+
writable: false,
|
|
27
|
+
value
|
|
28
|
+
});
|
|
50
29
|
if (navigator.modelContext !== value) console.error("[WebModelContext] Failed to replace navigator.modelContext.", "Descriptor:", Object.getOwnPropertyDescriptor(navigator, "modelContext"));
|
|
51
30
|
}
|
|
31
|
+
function restoreProperty(target, key, descriptor) {
|
|
32
|
+
if (descriptor) Object.defineProperty(target, key, descriptor);
|
|
33
|
+
else Reflect.deleteProperty(target, key);
|
|
34
|
+
}
|
|
52
35
|
/**
|
|
53
36
|
* Replace both modelContext surfaces with the given value.
|
|
54
37
|
*
|
|
55
|
-
*
|
|
56
|
-
* navigator
|
|
57
|
-
* old navigator-first users, so the bridge exposes the BrowserMcpServer wrapper
|
|
38
|
+
* document.modelContext is canonical. @mcp-b/global still supports old
|
|
39
|
+
* navigator-first users, so the bridge exposes the BrowserMcpServer wrapper
|
|
58
40
|
* through both properties.
|
|
59
41
|
*/
|
|
60
|
-
function replaceModelContext(value) {
|
|
61
|
-
replaceDocumentModelContext(value);
|
|
62
|
-
replaceNavigatorModelContext(value);
|
|
63
|
-
}
|
|
64
|
-
function createTransport(config) {
|
|
65
|
-
if (window.parent !== window && config?.iframeServer !== false) {
|
|
66
|
-
const { allowedOrigins, ...rest } = typeof config?.iframeServer === "object" ? config.iframeServer : {};
|
|
67
|
-
return new IframeChildTransport({
|
|
68
|
-
allowedOrigins: allowedOrigins ?? ["*"],
|
|
69
|
-
...rest
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
if (config?.tabServer === false) throw new Error("tabServer transport is disabled and iframe transport was not selected");
|
|
73
|
-
const { allowedOrigins, ...rest } = typeof config?.tabServer === "object" ? config.tabServer : {};
|
|
74
|
-
return new TabServerTransport({
|
|
75
|
-
allowedOrigins: allowedOrigins ?? ["*"],
|
|
76
|
-
...rest
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
function parseTestingInputSchema(inputSchema) {
|
|
80
|
-
if (!inputSchema) return;
|
|
42
|
+
function replaceModelContext(value, previousDocumentDescriptor, previousNavigatorDescriptor) {
|
|
81
43
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return parsed;
|
|
44
|
+
replaceDocumentModelContext(value);
|
|
45
|
+
replaceNavigatorModelContext(value);
|
|
85
46
|
} catch (error) {
|
|
86
|
-
|
|
87
|
-
|
|
47
|
+
restoreProperty(document, "modelContext", previousDocumentDescriptor);
|
|
48
|
+
restoreProperty(navigator, "modelContext", previousNavigatorDescriptor);
|
|
49
|
+
throw error;
|
|
88
50
|
}
|
|
89
51
|
}
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
testingShim,
|
|
95
|
-
tools: testingShim.getRegisteredTools()
|
|
96
|
-
};
|
|
97
|
-
if (typeof testingShim.listTools !== "function") return;
|
|
98
|
-
return {
|
|
99
|
-
testingShim,
|
|
100
|
-
tools: testingShim.listTools().map((tool) => ({
|
|
101
|
-
name: tool.name,
|
|
102
|
-
description: tool.description ?? "",
|
|
103
|
-
inputSchema: parseTestingInputSchema(tool.inputSchema) ?? {
|
|
104
|
-
type: "object",
|
|
105
|
-
properties: {}
|
|
106
|
-
}
|
|
107
|
-
}))
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
function syncToolsFromTestingShim(server) {
|
|
111
|
-
const shimState = getTestingShimTools();
|
|
112
|
-
if (!shimState) return 0;
|
|
113
|
-
const { testingShim, tools } = shimState;
|
|
114
|
-
return server.backfillTools(tools, async (name, args) => {
|
|
115
|
-
const serialized = await testingShim.executeTool(name, JSON.stringify(args ?? {}));
|
|
116
|
-
if (serialized === null) return {
|
|
117
|
-
content: [{
|
|
118
|
-
type: "text",
|
|
119
|
-
text: "Tool execution interrupted by navigation"
|
|
120
|
-
}],
|
|
121
|
-
isError: true
|
|
122
|
-
};
|
|
123
|
-
let parsed;
|
|
124
|
-
try {
|
|
125
|
-
parsed = JSON.parse(serialized);
|
|
126
|
-
} catch (parseError) {
|
|
127
|
-
throw new Error(`Failed to parse serialized tool response for ${name}: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
128
|
-
}
|
|
129
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`Invalid serialized tool response for ${name}`);
|
|
130
|
-
return parsed;
|
|
131
|
-
});
|
|
52
|
+
function createTransport(config) {
|
|
53
|
+
if (window.parent !== window && config?.iframeServer !== false) return new IframeChildTransport(typeof config?.iframeServer === "object" ? config.iframeServer : { allowedOrigins: ["*"] });
|
|
54
|
+
if (config?.tabServer === false) throw new Error("tabServer transport is disabled and iframe transport was not selected");
|
|
55
|
+
return new TabServerTransport(typeof config?.tabServer === "object" ? config.tabServer : { allowedOrigins: ["*"] });
|
|
132
56
|
}
|
|
57
|
+
/** Installs the global bridge on `document.modelContext`. */
|
|
133
58
|
function initializeWebModelContext(options) {
|
|
134
|
-
if (!isBrowserEnvironment()) return;
|
|
59
|
+
if (!isBrowserEnvironment() || globalThis.isSecureContext === false) return;
|
|
135
60
|
if (runtime) return;
|
|
136
|
-
|
|
137
|
-
|
|
61
|
+
const existingContext = readCurrentModelContext();
|
|
62
|
+
if (existingContext && isBrowserMcpServer(existingContext)) return;
|
|
63
|
+
initializeWebMCPPolyfill({ installTestingShim: options?.installTestingShim ?? true });
|
|
138
64
|
const native = readCurrentModelContext();
|
|
139
65
|
if (!native) throw new Error("modelContext is not available");
|
|
66
|
+
const transport = createTransport(options?.transport);
|
|
140
67
|
const server = new BrowserMcpServer({
|
|
141
68
|
name: `${window.location.hostname || "localhost"}-webmcp`,
|
|
142
69
|
version: "1.0.0"
|
|
143
70
|
}, { native });
|
|
144
|
-
server.syncNativeTools();
|
|
145
|
-
syncToolsFromTestingShim(server);
|
|
146
71
|
const previousDocumentModelContextDescriptor = Object.getOwnPropertyDescriptor(document, "modelContext");
|
|
147
72
|
const previousNavigatorModelContextDescriptor = Object.getOwnPropertyDescriptor(navigator, "modelContext");
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
73
|
+
try {
|
|
74
|
+
replaceModelContext(server, previousDocumentModelContextDescriptor, previousNavigatorModelContextDescriptor);
|
|
75
|
+
runtime = {
|
|
76
|
+
native,
|
|
77
|
+
server,
|
|
78
|
+
transport,
|
|
79
|
+
previousDocumentModelContextDescriptor,
|
|
80
|
+
previousNavigatorModelContextDescriptor
|
|
81
|
+
};
|
|
82
|
+
} catch (error) {
|
|
83
|
+
server.close();
|
|
84
|
+
transport.close();
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
(async () => {
|
|
88
|
+
try {
|
|
89
|
+
await server.syncNativeTools();
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.warn("[WebModelContext] Native WebMCP tool synchronization failed:", error);
|
|
92
|
+
}
|
|
93
|
+
if (runtime?.server !== server) return;
|
|
94
|
+
try {
|
|
95
|
+
await server.connect(transport);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error("[WebModelContext] Failed to connect MCP transport:", error);
|
|
98
|
+
if (runtime?.server === server) cleanupWebModelContext();
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
160
101
|
}
|
|
161
102
|
function cleanupWebModelContext() {
|
|
162
103
|
if (!runtime) return;
|
|
@@ -164,10 +105,8 @@ function cleanupWebModelContext() {
|
|
|
164
105
|
runtime = null;
|
|
165
106
|
server.close();
|
|
166
107
|
transport.close();
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (previousNavigatorModelContextDescriptor) Object.defineProperty(navigator, "modelContext", previousNavigatorModelContextDescriptor);
|
|
170
|
-
else delete navigator.modelContext;
|
|
108
|
+
restoreProperty(document, "modelContext", previousDocumentModelContextDescriptor);
|
|
109
|
+
restoreProperty(navigator, "modelContext", previousNavigatorModelContextDescriptor);
|
|
171
110
|
}
|
|
172
111
|
|
|
173
112
|
//#endregion
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/global.ts","../src/index.ts"],"sourcesContent":["import {\n IframeChildTransport,\n type IframeChildTransportOptions,\n TabServerTransport,\n type TabServerTransportOptions,\n} from '@mcp-b/transports';\nimport { initializeWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';\nimport { BrowserMcpServer, SERVER_MARKER_PROPERTY, type Transport } from '@mcp-b/webmcp-ts-sdk';\nimport type {\n InputSchema,\n ModelContextCore,\n ModelContextTesting,\n ModelContextTestingPolyfillExtensions,\n ToolListItem,\n ToolResponse,\n} from '@mcp-b/webmcp-types';\nimport type { WebModelContextInitOptions } from './types.js';\n\ninterface RuntimeState {\n native: ModelContextCore;\n server: BrowserMcpServer;\n transport: Transport;\n previousDocumentModelContextDescriptor: PropertyDescriptor | undefined;\n previousNavigatorModelContextDescriptor: PropertyDescriptor | undefined;\n}\n\nlet runtime: RuntimeState | null = null;\n\nfunction isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof window.navigator !== 'undefined';\n}\n\nfunction readCurrentModelContext(): unknown {\n const navigatorDescriptor = Object.getOwnPropertyDescriptor(navigator, 'modelContext');\n if (navigatorDescriptor) {\n return navigator.modelContext;\n }\n\n return document.modelContext ?? navigator.modelContext;\n}\n\nfunction replaceDocumentModelContext(value: unknown): void {\n try {\n Object.defineProperty(document, 'modelContext', {\n configurable: true,\n enumerable: true,\n writable: false,\n value,\n });\n } catch {\n Object.defineProperty(Object.getPrototypeOf(document), 'modelContext', {\n configurable: true,\n enumerable: true,\n get() {\n return value;\n },\n });\n }\n\n if (document.modelContext !== value) {\n console.error(\n '[WebModelContext] Failed to replace document.modelContext.',\n 'Descriptor:',\n Object.getOwnPropertyDescriptor(document, 'modelContext')\n );\n }\n}\n\nfunction replaceNavigatorModelContext(value: unknown): void {\n try {\n Object.defineProperty(navigator, 'modelContext', {\n configurable: true,\n enumerable: true,\n writable: false,\n value,\n });\n } catch {\n // Native browser property is non-configurable on the instance.\n // Shadow it with a getter on the prototype instead.\n Object.defineProperty(Object.getPrototypeOf(navigator), 'modelContext', {\n configurable: true,\n enumerable: true,\n get() {\n return value;\n },\n });\n }\n\n // Verify the replacement actually worked — the prototype getter cannot\n // shadow a non-configurable own property on the navigator instance.\n if (navigator.modelContext !== value) {\n console.error(\n '[WebModelContext] Failed to replace navigator.modelContext.',\n 'Descriptor:',\n Object.getOwnPropertyDescriptor(navigator, 'modelContext')\n );\n }\n}\n\n/**\n * Replace both modelContext surfaces with the given value.\n *\n * The Chrome 152 baseline uses document.modelContext as canonical and keeps\n * navigator.modelContext as a deprecated alias. @mcp-b/global still supports\n * old navigator-first users, so the bridge exposes the BrowserMcpServer wrapper\n * through both properties.\n */\nfunction replaceModelContext(value: unknown): void {\n replaceDocumentModelContext(value);\n replaceNavigatorModelContext(value);\n}\n\nfunction createTransport(config: WebModelContextInitOptions['transport']): Transport {\n const inIframe = window.parent !== window;\n\n if (inIframe && config?.iframeServer !== false) {\n const iframeOptions =\n typeof config?.iframeServer === 'object'\n ? config.iframeServer\n : ({} as Partial<IframeChildTransportOptions>);\n\n const { allowedOrigins, ...rest } = iframeOptions;\n\n return new IframeChildTransport({\n allowedOrigins: allowedOrigins ?? ['*'],\n ...rest,\n });\n }\n\n if (config?.tabServer === false) {\n throw new Error('tabServer transport is disabled and iframe transport was not selected');\n }\n\n const tabOptions =\n typeof config?.tabServer === 'object'\n ? config.tabServer\n : ({} as Partial<TabServerTransportOptions>);\n\n const { allowedOrigins, ...rest } = tabOptions;\n\n return new TabServerTransport({\n allowedOrigins: allowedOrigins ?? ['*'],\n ...rest,\n });\n}\n\nfunction parseTestingInputSchema(inputSchema: string | undefined): InputSchema | undefined {\n if (!inputSchema) {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(inputSchema) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return undefined;\n }\n return parsed as InputSchema;\n } catch (error) {\n console.warn('[WebMCP] Failed to parse testing inputSchema JSON:', error);\n return undefined;\n }\n}\n\nfunction getTestingShimTools():\n | {\n testingShim: ModelContextTesting;\n tools: ToolListItem[];\n }\n | undefined {\n const testingShim = navigator.modelContextTesting as\n | (ModelContextTesting & Partial<ModelContextTestingPolyfillExtensions>)\n | undefined;\n if (!testingShim) {\n return undefined;\n }\n\n if (typeof testingShim.getRegisteredTools === 'function') {\n return {\n testingShim,\n tools: testingShim.getRegisteredTools() as ToolListItem[],\n };\n }\n\n if (typeof testingShim.listTools !== 'function') {\n return undefined;\n }\n\n const tools = testingShim.listTools().map(\n (tool): ToolListItem => ({\n name: tool.name,\n description: tool.description ?? '',\n inputSchema: parseTestingInputSchema(tool.inputSchema) ?? {\n type: 'object',\n properties: {},\n },\n })\n );\n\n return {\n testingShim,\n tools,\n };\n}\n\nfunction syncToolsFromTestingShim(server: BrowserMcpServer): number {\n const shimState = getTestingShimTools();\n if (!shimState) {\n return 0;\n }\n\n const { testingShim, tools } = shimState;\n return server.backfillTools(tools, async (name: string, args: Record<string, unknown>) => {\n const serialized = await testingShim.executeTool(name, JSON.stringify(args ?? {}));\n if (serialized === null) {\n return {\n content: [{ type: 'text', text: 'Tool execution interrupted by navigation' }],\n isError: true,\n } satisfies ToolResponse;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(serialized);\n } catch (parseError) {\n throw new Error(\n `Failed to parse serialized tool response for ${name}: ${parseError instanceof Error ? parseError.message : String(parseError)}`\n );\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`Invalid serialized tool response for ${name}`);\n }\n return parsed as ToolResponse;\n });\n}\n\nexport function initializeWebModelContext(options?: WebModelContextInitOptions): void {\n if (!isBrowserEnvironment()) {\n return;\n }\n\n if (runtime) {\n return;\n }\n\n // Cross-bundle guard: if modelContext is already a BrowserMcpServer\n // (set by another bundle in this window), skip initialization.\n const existingContext = readCurrentModelContext() as Record<string, unknown> | undefined;\n if (existingContext?.[SERVER_MARKER_PROPERTY]) {\n return;\n }\n\n // 1. Install polyfill (provides modelContext + modelContextTesting)\n initializeWebMCPPolyfill({\n installTestingShim: options?.installTestingShim ?? 'if-missing',\n });\n\n // 2. Save reference to the polyfill's (or native) context\n const native = readCurrentModelContext() as ModelContextCore | undefined;\n if (!native) {\n throw new Error('modelContext is not available');\n }\n\n // 3. Create server with native mirroring\n const hostname = window.location.hostname || 'localhost';\n const server = new BrowserMcpServer({ name: `${hostname}-webmcp`, version: '1.0.0' }, { native });\n server.syncNativeTools();\n syncToolsFromTestingShim(server);\n\n // 4. Replace navigator.modelContext with the server.\n // Try own-property on the navigator instance first (works for polyfill and most cases).\n // Fall back to a prototype getter if the native property is non-configurable.\n const previousDocumentModelContextDescriptor = Object.getOwnPropertyDescriptor(\n document,\n 'modelContext'\n );\n const previousNavigatorModelContextDescriptor = Object.getOwnPropertyDescriptor(\n navigator,\n 'modelContext'\n );\n replaceModelContext(server);\n\n // 5. Create transport and connect\n const transport = createTransport(options?.transport);\n runtime = {\n native,\n server,\n transport,\n previousDocumentModelContextDescriptor,\n previousNavigatorModelContextDescriptor,\n };\n\n void server.connect(transport).catch((error: unknown) => {\n console.error('[WebModelContext] Failed to connect MCP transport:', error);\n });\n}\n\nexport function cleanupWebModelContext(): void {\n if (!runtime) {\n return;\n }\n\n const {\n server,\n transport,\n previousDocumentModelContextDescriptor,\n previousNavigatorModelContextDescriptor,\n } = runtime;\n runtime = null;\n\n void server.close();\n void transport.close();\n\n // Restore the descriptors that existed before we wrapped with BrowserMcpServer.\n // We intentionally do NOT call cleanupWebMCPPolyfill() here — the polyfill\n // manages its own lifecycle (auto-init, testing shim) independently.\n if (previousDocumentModelContextDescriptor) {\n Object.defineProperty(document, 'modelContext', previousDocumentModelContextDescriptor);\n } else {\n delete (document as unknown as Record<string, unknown>).modelContext;\n }\n\n if (previousNavigatorModelContextDescriptor) {\n Object.defineProperty(navigator, 'modelContext', previousNavigatorModelContextDescriptor);\n } else {\n delete (navigator as unknown as Record<string, unknown>).modelContext;\n }\n}\n","import { cleanupWebModelContext, initializeWebModelContext } from './global.js';\n\nexport { cleanupWebModelContext, initializeWebModelContext };\n\nexport type {\n NativeModelContextBehavior,\n TransportConfiguration,\n WebModelContextInitOptions,\n} from './types.js';\n\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const options = window.__webModelContextOptions;\n const shouldAutoInitialize = options?.autoInitialize !== false;\n\n if (shouldAutoInitialize) {\n try {\n initializeWebModelContext(options);\n } catch (error) {\n console.error('[WebModelContext] Auto-initialization failed:', error);\n }\n }\n}\n"],"mappings":";;;;;AA0BA,IAAI,UAA+B;AAEnC,SAAS,uBAAgC;CACvC,OAAO,OAAO,WAAW,eAAe,OAAO,OAAO,cAAc;;AAGtE,SAAS,0BAAmC;CAE1C,IAD4B,OAAO,yBAAyB,WAAW,eAChD,EACrB,OAAO,UAAU;CAGnB,OAAO,SAAS,gBAAgB,UAAU;;AAG5C,SAAS,4BAA4B,OAAsB;CACzD,IAAI;EACF,OAAO,eAAe,UAAU,gBAAgB;GAC9C,cAAc;GACd,YAAY;GACZ,UAAU;GACV;GACD,CAAC;SACI;EACN,OAAO,eAAe,OAAO,eAAe,SAAS,EAAE,gBAAgB;GACrE,cAAc;GACd,YAAY;GACZ,MAAM;IACJ,OAAO;;GAEV,CAAC;;CAGJ,IAAI,SAAS,iBAAiB,OAC5B,QAAQ,MACN,8DACA,eACA,OAAO,yBAAyB,UAAU,eAAe,CAC1D;;AAIL,SAAS,6BAA6B,OAAsB;CAC1D,IAAI;EACF,OAAO,eAAe,WAAW,gBAAgB;GAC/C,cAAc;GACd,YAAY;GACZ,UAAU;GACV;GACD,CAAC;SACI;EAGN,OAAO,eAAe,OAAO,eAAe,UAAU,EAAE,gBAAgB;GACtE,cAAc;GACd,YAAY;GACZ,MAAM;IACJ,OAAO;;GAEV,CAAC;;CAKJ,IAAI,UAAU,iBAAiB,OAC7B,QAAQ,MACN,+DACA,eACA,OAAO,yBAAyB,WAAW,eAAe,CAC3D;;;;;;;;;;AAYL,SAAS,oBAAoB,OAAsB;CACjD,4BAA4B,MAAM;CAClC,6BAA6B,MAAM;;AAGrC,SAAS,gBAAgB,QAA4D;CAGnF,IAFiB,OAAO,WAAW,UAEnB,QAAQ,iBAAiB,OAAO;EAM9C,MAAM,EAAE,gBAAgB,GAAG,SAJzB,OAAO,QAAQ,iBAAiB,WAC5B,OAAO,eACN,EAAE;EAIT,OAAO,IAAI,qBAAqB;GAC9B,gBAAgB,kBAAkB,CAAC,IAAI;GACvC,GAAG;GACJ,CAAC;;CAGJ,IAAI,QAAQ,cAAc,OACxB,MAAM,IAAI,MAAM,wEAAwE;CAQ1F,MAAM,EAAE,gBAAgB,GAAG,SAJzB,OAAO,QAAQ,cAAc,WACzB,OAAO,YACN,EAAE;CAIT,OAAO,IAAI,mBAAmB;EAC5B,gBAAgB,kBAAkB,CAAC,IAAI;EACvC,GAAG;EACJ,CAAC;;AAGJ,SAAS,wBAAwB,aAA0D;CACzF,IAAI,CAAC,aACH;CAGF,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,YAAY;EACtC,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,EAChE;EAEF,OAAO;UACA,OAAO;EACd,QAAQ,KAAK,sDAAsD,MAAM;EACzE;;;AAIJ,SAAS,sBAKK;CACZ,MAAM,cAAc,UAAU;CAG9B,IAAI,CAAC,aACH;CAGF,IAAI,OAAO,YAAY,uBAAuB,YAC5C,OAAO;EACL;EACA,OAAO,YAAY,oBAAoB;EACxC;CAGH,IAAI,OAAO,YAAY,cAAc,YACnC;CAcF,OAAO;EACL;EACA,OAbY,YAAY,WAAW,CAAC,KACnC,UAAwB;GACvB,MAAM,KAAK;GACX,aAAa,KAAK,eAAe;GACjC,aAAa,wBAAwB,KAAK,YAAY,IAAI;IACxD,MAAM;IACN,YAAY,EAAE;IACf;GACF,EAKI;EACN;;AAGH,SAAS,yBAAyB,QAAkC;CAClE,MAAM,YAAY,qBAAqB;CACvC,IAAI,CAAC,WACH,OAAO;CAGT,MAAM,EAAE,aAAa,UAAU;CAC/B,OAAO,OAAO,cAAc,OAAO,OAAO,MAAc,SAAkC;EACxF,MAAM,aAAa,MAAM,YAAY,YAAY,MAAM,KAAK,UAAU,QAAQ,EAAE,CAAC,CAAC;EAClF,IAAI,eAAe,MACjB,OAAO;GACL,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM;IAA4C,CAAC;GAC7E,SAAS;GACV;EAGH,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,WAAW;WACxB,YAAY;GACnB,MAAM,IAAI,MACR,gDAAgD,KAAK,IAAI,sBAAsB,QAAQ,WAAW,UAAU,OAAO,WAAW,GAC/H;;EAEH,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,EAChE,MAAM,IAAI,MAAM,wCAAwC,OAAO;EAEjE,OAAO;GACP;;AAGJ,SAAgB,0BAA0B,SAA4C;CACpF,IAAI,CAAC,sBAAsB,EACzB;CAGF,IAAI,SACF;CAMF,IADwB,yBACL,GAAG,yBACpB;CAIF,yBAAyB,EACvB,oBAAoB,SAAS,sBAAsB,cACpD,CAAC;CAGF,MAAM,SAAS,yBAAyB;CACxC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,gCAAgC;CAKlD,MAAM,SAAS,IAAI,iBAAiB;EAAE,MAAM,GAD3B,OAAO,SAAS,YAAY,YACW;EAAU,SAAS;EAAS,EAAE,EAAE,QAAQ,CAAC;CACjG,OAAO,iBAAiB;CACxB,yBAAyB,OAAO;CAKhC,MAAM,yCAAyC,OAAO,yBACpD,UACA,eACD;CACD,MAAM,0CAA0C,OAAO,yBACrD,WACA,eACD;CACD,oBAAoB,OAAO;CAG3B,MAAM,YAAY,gBAAgB,SAAS,UAAU;CACrD,UAAU;EACR;EACA;EACA;EACA;EACA;EACD;CAED,AAAK,OAAO,QAAQ,UAAU,CAAC,OAAO,UAAmB;EACvD,QAAQ,MAAM,sDAAsD,MAAM;GAC1E;;AAGJ,SAAgB,yBAA+B;CAC7C,IAAI,CAAC,SACH;CAGF,MAAM,EACJ,QACA,WACA,wCACA,4CACE;CACJ,UAAU;CAEV,AAAK,OAAO,OAAO;CACnB,AAAK,UAAU,OAAO;CAKtB,IAAI,wCACF,OAAO,eAAe,UAAU,gBAAgB,uCAAuC;MAEvF,OAAQ,SAAgD;CAG1D,IAAI,yCACF,OAAO,eAAe,WAAW,gBAAgB,wCAAwC;MAEzF,OAAQ,UAAiD;;;;;AC1T7D,IAAI,OAAO,WAAW,eAAe,OAAO,aAAa,aAAa;CACpE,MAAM,UAAU,OAAO;CAGvB,IAF6B,SAAS,mBAAmB,OAGvD,IAAI;EACF,0BAA0B,QAAQ;UAC3B,OAAO;EACd,QAAQ,MAAM,iDAAiD,MAAM"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/global.ts","../src/index.ts"],"sourcesContent":["import { IframeChildTransport, TabServerTransport } from '@mcp-b/transports';\nimport { initializeWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';\nimport { BrowserMcpServer, isBrowserMcpServer } from '@mcp-b/webmcp-ts-sdk';\nimport type { ModelContext } from '@mcp-b/webmcp-types';\nimport type { Transport } from '@modelcontextprotocol/server';\nimport type { WebModelContextInitOptions } from './types.js';\n\ninterface RuntimeState {\n native: ModelContext;\n server: BrowserMcpServer;\n transport: Transport;\n previousDocumentModelContextDescriptor: PropertyDescriptor | undefined;\n previousNavigatorModelContextDescriptor: PropertyDescriptor | undefined;\n}\n\nlet runtime: RuntimeState | null = null;\n\nfunction isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof window.navigator !== 'undefined';\n}\n\nfunction readCurrentModelContext(): ModelContext | undefined {\n return document.modelContext ?? navigator.modelContext;\n}\n\nfunction replaceDocumentModelContext(value: unknown): void {\n Object.defineProperty(document, 'modelContext', {\n configurable: true,\n enumerable: true,\n writable: false,\n value,\n });\n\n if (document.modelContext !== value) {\n console.error(\n '[WebModelContext] Failed to replace document.modelContext.',\n 'Descriptor:',\n Object.getOwnPropertyDescriptor(document, 'modelContext')\n );\n }\n}\n\nfunction replaceNavigatorModelContext(value: unknown): void {\n Object.defineProperty(navigator, 'modelContext', {\n configurable: true,\n enumerable: true,\n writable: false,\n value,\n });\n\n if (navigator.modelContext !== value) {\n console.error(\n '[WebModelContext] Failed to replace navigator.modelContext.',\n 'Descriptor:',\n Object.getOwnPropertyDescriptor(navigator, 'modelContext')\n );\n }\n}\n\nfunction restoreProperty(\n target: Document | Navigator,\n key: 'modelContext',\n descriptor: PropertyDescriptor | undefined\n): void {\n if (descriptor) Object.defineProperty(target, key, descriptor);\n else Reflect.deleteProperty(target, key);\n}\n\n/**\n * Replace both modelContext surfaces with the given value.\n *\n * document.modelContext is canonical. @mcp-b/global still supports old\n * navigator-first users, so the bridge exposes the BrowserMcpServer wrapper\n * through both properties.\n */\nfunction replaceModelContext(\n value: unknown,\n previousDocumentDescriptor: PropertyDescriptor | undefined,\n previousNavigatorDescriptor: PropertyDescriptor | undefined\n): void {\n try {\n replaceDocumentModelContext(value);\n replaceNavigatorModelContext(value);\n } catch (error) {\n restoreProperty(document, 'modelContext', previousDocumentDescriptor);\n restoreProperty(navigator, 'modelContext', previousNavigatorDescriptor);\n throw error;\n }\n}\n\nfunction createTransport(config: WebModelContextInitOptions['transport']): Transport {\n const inIframe = window.parent !== window;\n\n if (inIframe && config?.iframeServer !== false) {\n return new IframeChildTransport(\n typeof config?.iframeServer === 'object' ? config.iframeServer : { allowedOrigins: ['*'] }\n );\n }\n\n if (config?.tabServer === false) {\n throw new Error('tabServer transport is disabled and iframe transport was not selected');\n }\n\n return new TabServerTransport(\n typeof config?.tabServer === 'object' ? config.tabServer : { allowedOrigins: ['*'] }\n );\n}\n\n/** Installs the global bridge on `document.modelContext`. */\nexport function initializeWebModelContext(options?: WebModelContextInitOptions): void {\n if (!isBrowserEnvironment() || globalThis.isSecureContext === false) {\n return;\n }\n\n if (runtime) {\n return;\n }\n\n // Cross-bundle guard: if modelContext is already a BrowserMcpServer\n // (set by another bundle in this window), skip initialization.\n const existingContext = readCurrentModelContext();\n if (existingContext && isBrowserMcpServer(existingContext)) {\n return;\n }\n\n // 1. Install polyfill (provides modelContext + modelContextTesting)\n initializeWebMCPPolyfill({\n installTestingShim: options?.installTestingShim ?? true,\n });\n\n // 2. Save reference to the polyfill's (or native) context\n const native = readCurrentModelContext();\n if (!native) {\n throw new Error('modelContext is not available');\n }\n\n // 3. Resolve transport before mutating either browser surface.\n const transport = createTransport(options?.transport);\n\n // 4. Create server with native mirroring\n const hostname = window.location.hostname || 'localhost';\n const server = new BrowserMcpServer({ name: `${hostname}-webmcp`, version: '1.0.0' }, { native });\n\n // 5. Replace both the canonical document surface and compatibility alias.\n const previousDocumentModelContextDescriptor = Object.getOwnPropertyDescriptor(\n document,\n 'modelContext'\n );\n const previousNavigatorModelContextDescriptor = Object.getOwnPropertyDescriptor(\n navigator,\n 'modelContext'\n );\n try {\n replaceModelContext(\n server,\n previousDocumentModelContextDescriptor,\n previousNavigatorModelContextDescriptor\n );\n runtime = {\n native,\n server,\n transport,\n previousDocumentModelContextDescriptor,\n previousNavigatorModelContextDescriptor,\n };\n } catch (error) {\n void server.close();\n void transport.close();\n throw error;\n }\n\n void (async () => {\n try {\n await server.syncNativeTools();\n } catch (error) {\n console.warn('[WebModelContext] Native WebMCP tool synchronization failed:', error);\n }\n\n if (runtime?.server !== server) {\n return;\n }\n\n try {\n await server.connect(transport);\n } catch (error) {\n console.error('[WebModelContext] Failed to connect MCP transport:', error);\n if (runtime?.server === server) {\n cleanupWebModelContext();\n }\n }\n })();\n}\n\nexport function cleanupWebModelContext(): void {\n if (!runtime) {\n return;\n }\n\n const {\n server,\n transport,\n previousDocumentModelContextDescriptor,\n previousNavigatorModelContextDescriptor,\n } = runtime;\n runtime = null;\n\n void server.close();\n void transport.close();\n\n // Restore the descriptors that existed before we wrapped with BrowserMcpServer.\n // We intentionally do NOT call cleanupWebMCPPolyfill() here — the polyfill\n // manages its own lifecycle (auto-init, testing shim) independently.\n restoreProperty(document, 'modelContext', previousDocumentModelContextDescriptor);\n restoreProperty(navigator, 'modelContext', previousNavigatorModelContextDescriptor);\n}\n","import { cleanupWebModelContext, initializeWebModelContext } from './global.js';\n\nexport { cleanupWebModelContext, initializeWebModelContext };\n\nexport type { TransportConfiguration, WebModelContextInitOptions } from './types.js';\n\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const options = window.__webModelContextOptions;\n const shouldAutoInitialize = options?.autoInitialize !== false;\n\n if (shouldAutoInitialize) {\n try {\n initializeWebModelContext(options);\n } catch (error) {\n console.error('[WebModelContext] Auto-initialization failed:', error);\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/global",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "W3C Web Model Context Protocol (WebMCP) API polyfill. Let AI agents like Claude, ChatGPT, and Gemini interact with your website via document.modelContext.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"sideEffects": true,
|
|
49
49
|
"main": "./dist/index.js",
|
|
50
50
|
"module": "./dist/index.js",
|
|
51
|
-
"browser": "./dist/index.
|
|
51
|
+
"browser": "./dist/index.js",
|
|
52
52
|
"types": "./dist/index.d.ts",
|
|
53
53
|
"exports": {
|
|
54
54
|
".": {
|
|
@@ -66,25 +66,26 @@
|
|
|
66
66
|
"registry": "https://registry.npmjs.org/"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@
|
|
70
|
-
"@mcp-b/transports": "
|
|
71
|
-
"@mcp-b/webmcp-ts-sdk": "
|
|
72
|
-
"@mcp-b/webmcp-types": "
|
|
69
|
+
"@modelcontextprotocol/server": "2.0.0",
|
|
70
|
+
"@mcp-b/transports": "5.0.0",
|
|
71
|
+
"@mcp-b/webmcp-ts-sdk": "5.0.0",
|
|
72
|
+
"@mcp-b/webmcp-types": "5.0.0",
|
|
73
|
+
"@mcp-b/webmcp-polyfill": "5.0.0"
|
|
73
74
|
},
|
|
74
75
|
"devDependencies": {
|
|
76
|
+
"@modelcontextprotocol/client": "2.0.0",
|
|
75
77
|
"@types/node": "22.17.2",
|
|
76
78
|
"@vitest/coverage-v8": "^4.1.7",
|
|
77
|
-
"fast-check": "^4.0.0",
|
|
78
79
|
"playwright": "^1.60.0",
|
|
79
80
|
"typescript": "^5.8.3",
|
|
80
81
|
"vite-plus": "^0.1.22",
|
|
81
82
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
|
82
83
|
},
|
|
83
84
|
"engines": {
|
|
84
|
-
"node": ">=
|
|
85
|
+
"node": ">=20"
|
|
85
86
|
},
|
|
86
87
|
"scripts": {
|
|
87
|
-
"build": "vp pack",
|
|
88
|
+
"build": "vp pack && pnpm run typecheck:consumer",
|
|
88
89
|
"check": "vp check --fix",
|
|
89
90
|
"clean": "rm -rf dist",
|
|
90
91
|
"format": "vp fmt --write",
|
|
@@ -92,17 +93,12 @@
|
|
|
92
93
|
"publish:dry": "pnpm publish --access public --dry-run",
|
|
93
94
|
"publish:npm": "pnpm publish --access public",
|
|
94
95
|
"test": "vp test run",
|
|
95
|
-
"test:
|
|
96
|
-
"test:browser:ui": "vp test --browser",
|
|
97
|
-
"test:conformance:global": "vp test run --config vitest.conformance.global.config.ts --browser.headless",
|
|
96
|
+
"test:conformance:global": "vp test run conformance/global-runtime.e2e.test.ts --browser.headless",
|
|
98
97
|
"test:conformance:matrix": "pnpm run test:conformance:polyfill && pnpm run test:conformance:global && pnpm run test:conformance:native",
|
|
99
98
|
"test:conformance:native": "vp test run --config vitest.conformance.native.config.ts --browser.headless",
|
|
100
99
|
"test:conformance:polyfill": "pnpm --filter @mcp-b/webmcp-polyfill run test:conformance",
|
|
101
|
-
"test:node": "vp test run --config vitest.node.config.ts",
|
|
102
100
|
"test:watch": "vp test",
|
|
103
101
|
"typecheck": "tsc --noEmit && vp test run --typecheck --silent",
|
|
104
|
-
"
|
|
105
|
-
"version:minor": "pnpm version minor --no-git-tag-version",
|
|
106
|
-
"version:patch": "pnpm version patch --no-git-tag-version"
|
|
102
|
+
"typecheck:consumer": "tsc --noEmit --strict --skipLibCheck --module preserve --moduleResolution bundler --lib ES2022,DOM type-tests/consumer.ts"
|
|
107
103
|
}
|
|
108
104
|
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/global.ts"],"mappings":";;;UAEiB,sBAAA;EACf,SAAA,GAAY,OAAA,CAAQ,yBAAA;EACpB,YAAA,GAAe,OAAA,CAAQ,2BAAA;AAAA;AAAA,KAGb,0BAAA;AAAA,UAEK,0BAAA;EACf,SAAA,GAAY,sBAAA;EACZ,cAAA;EAPe;;;;;;;EAef,0BAAA,GAA6B,0BAAA;EAfN;;;AAGzB;;;EAmBE,kBAAA;AAAA;AAAA,QAGM,MAAA;EAAA,UACI,MAAA;IACR,wBAAA,GAA2B,0BAAA;EAAA;AAAA;;;iBC4Mf,yBAAA,CAA0B,OAAA,GAAU,0BAAA;AAAA,iBA6DpC,sBAAA,CAAA"}
|