@mcp-b/webmcp-polyfill 0.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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +284 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 mcp-b contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @mcp-b/webmcp-polyfill
|
|
2
|
+
|
|
3
|
+
Strict WebMCP core runtime polyfill for `navigator.modelContext`.
|
|
4
|
+
|
|
5
|
+
This package installs only the core API:
|
|
6
|
+
|
|
7
|
+
- `provideContext(options?)`
|
|
8
|
+
- `registerTool(tool)`
|
|
9
|
+
- `unregisterTool(name)`
|
|
10
|
+
- `clearContext()`
|
|
11
|
+
|
|
12
|
+
It does not install MCP bridge extension methods like `callTool`, resources, or prompts.
|
|
13
|
+
For the full MCPB runtime (core + bridge extensions), use `@mcp-b/global`.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @mcp-b/webmcp-polyfill
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { initializeWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';
|
|
25
|
+
|
|
26
|
+
initializeWebMCPPolyfill();
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Options
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
initializeWebMCPPolyfill({
|
|
33
|
+
forceOverride: false,
|
|
34
|
+
installTestingShim: true,
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `forceOverride`: replace an existing `navigator.modelContext` if present.
|
|
39
|
+
- `installTestingShim`: install `navigator.modelContextTesting` parity helpers.
|
|
40
|
+
|
|
41
|
+
## Interop with `@mcp-b/global`
|
|
42
|
+
|
|
43
|
+
- Default behavior is non-destructive: if `navigator.modelContext` already exists, this package does nothing unless `forceOverride: true` is passed.
|
|
44
|
+
- When a page already has this core polyfill and later loads `@mcp-b/global`, global runs in attach-only mode (keeps the existing object identity and adds bridge/runtime features).
|
|
45
|
+
- Repeated injection of `@mcp-b/global` is idempotent (first initialization wins).
|
|
46
|
+
|
|
47
|
+
## Testing Shim
|
|
48
|
+
|
|
49
|
+
When `installTestingShim` is enabled (default), this package also installs a minimal
|
|
50
|
+
`navigator.modelContextTesting` surface for parity-style tests:
|
|
51
|
+
|
|
52
|
+
- `listTools()`
|
|
53
|
+
- `executeTool(toolName, inputArgsJson, options?)`
|
|
54
|
+
- `registerToolsChangedCallback(callback)`
|
|
55
|
+
- `getCrossDocumentScriptToolResult()`
|
|
56
|
+
|
|
57
|
+
## Cleanup
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { cleanupWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';
|
|
61
|
+
|
|
62
|
+
cleanupWebMCPPolyfill();
|
|
63
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { InputSchema, ModelContext, ModelContextClient, ModelContextCore, ModelContextOptions, ToolAnnotations, ToolDescriptor, ToolResponse } from "@mcp-b/webmcp-types";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
interface WebMCPPolyfillInitOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Force installation even when navigator.modelContext already exists.
|
|
7
|
+
* Existing descriptors are restored by cleanupWebMCPPolyfill().
|
|
8
|
+
*/
|
|
9
|
+
forceOverride?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Installs navigator.modelContextTesting when this polyfill provides modelContext.
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
installTestingShim?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Deprecated no-op kept for compatibility with previous wrapper options.
|
|
17
|
+
*/
|
|
18
|
+
disableIframeTransportByDefault?: boolean;
|
|
19
|
+
}
|
|
20
|
+
declare function initializeWebMCPPolyfill(options?: WebMCPPolyfillInitOptions): void;
|
|
21
|
+
declare function cleanupWebMCPPolyfill(): void;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { type InputSchema, type ModelContext, type ModelContextClient, type ModelContextCore, type ModelContextOptions, type ToolAnnotations, type ToolDescriptor, type ToolResponse, WebMCPPolyfillInitOptions, cleanupWebMCPPolyfill, initializeWebMCPPolyfill, initializeWebMCPPolyfill as initializeWebModelContextPolyfill };
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;UAmCiB,yBAAA;;;AAAjB;AAkcA;EA4CgB,aAAA,CAAA,EAAA,OAAA;;;;;;;;;;;iBA5CA,wBAAA,WAAmC;iBA4CnC,qBAAA,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
const FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE = "Failed to parse input arguments";
|
|
3
|
+
const TOOL_INVOCATION_FAILED_MESSAGE = "Tool was executed but the invocation failed. For example, the script function threw an error";
|
|
4
|
+
const TOOL_CANCELLED_MESSAGE = "Tool was cancelled";
|
|
5
|
+
const DEFAULT_INPUT_SCHEMA = {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {}
|
|
8
|
+
};
|
|
9
|
+
const POLYFILL_MARKER_PROPERTY = "__isWebMCPPolyfill";
|
|
10
|
+
const installState = {
|
|
11
|
+
installed: false,
|
|
12
|
+
previousModelContextDescriptor: void 0,
|
|
13
|
+
previousModelContextTestingDescriptor: void 0
|
|
14
|
+
};
|
|
15
|
+
var StrictWebMCPContext = class {
|
|
16
|
+
tools = /* @__PURE__ */ new Map();
|
|
17
|
+
toolsChangedCallback = null;
|
|
18
|
+
provideContext(options = {}) {
|
|
19
|
+
const nextTools = /* @__PURE__ */ new Map();
|
|
20
|
+
for (const tool of options.tools ?? []) {
|
|
21
|
+
const normalized = normalizeToolDescriptor(tool, nextTools);
|
|
22
|
+
nextTools.set(normalized.name, normalized);
|
|
23
|
+
}
|
|
24
|
+
this.tools = nextTools;
|
|
25
|
+
this.notifyToolsChanged();
|
|
26
|
+
}
|
|
27
|
+
clearContext() {
|
|
28
|
+
this.tools.clear();
|
|
29
|
+
this.notifyToolsChanged();
|
|
30
|
+
}
|
|
31
|
+
registerTool(tool) {
|
|
32
|
+
const normalized = normalizeToolDescriptor(tool, this.tools);
|
|
33
|
+
this.tools.set(normalized.name, normalized);
|
|
34
|
+
this.notifyToolsChanged();
|
|
35
|
+
}
|
|
36
|
+
unregisterTool(name) {
|
|
37
|
+
if (this.tools.delete(name)) this.notifyToolsChanged();
|
|
38
|
+
}
|
|
39
|
+
getTestingShim() {
|
|
40
|
+
return {
|
|
41
|
+
listTools: () => {
|
|
42
|
+
return [...this.tools.values()].map((tool) => {
|
|
43
|
+
const output = {
|
|
44
|
+
name: tool.name,
|
|
45
|
+
description: tool.description
|
|
46
|
+
};
|
|
47
|
+
try {
|
|
48
|
+
output.inputSchema = JSON.stringify(tool.inputSchema ?? DEFAULT_INPUT_SCHEMA);
|
|
49
|
+
} catch {}
|
|
50
|
+
return output;
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
executeTool: (toolName, inputArgsJson, options) => this.executeToolForTesting(toolName, inputArgsJson, options),
|
|
54
|
+
registerToolsChangedCallback: (callback) => {
|
|
55
|
+
if (typeof callback !== "function") throw new TypeError("Failed to execute 'registerToolsChangedCallback' on 'ModelContextTesting': parameter 1 is not of type 'Function'.");
|
|
56
|
+
this.toolsChangedCallback = callback;
|
|
57
|
+
},
|
|
58
|
+
getCrossDocumentScriptToolResult: async () => "[]"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async executeToolForTesting(toolName, inputArgsJson, options) {
|
|
62
|
+
if (options?.signal?.aborted) throw createUnknownError(TOOL_CANCELLED_MESSAGE);
|
|
63
|
+
const tool = this.tools.get(toolName);
|
|
64
|
+
if (!tool) throw createUnknownError(`Tool not found: ${toolName}`);
|
|
65
|
+
const args = parseInputArgsJson(inputArgsJson);
|
|
66
|
+
const validationError = validateArgsWithSchema(args, tool.inputSchema ?? DEFAULT_INPUT_SCHEMA);
|
|
67
|
+
if (validationError) throw createUnknownError(validationError);
|
|
68
|
+
let contextActive = true;
|
|
69
|
+
const client = { requestUserInteraction: async (callback) => {
|
|
70
|
+
if (!contextActive) throw new Error(`ModelContextClient for tool "${toolName}" is no longer active after execute() resolved`);
|
|
71
|
+
if (typeof callback !== "function") throw new TypeError("requestUserInteraction(callback) requires a function callback");
|
|
72
|
+
return callback();
|
|
73
|
+
} };
|
|
74
|
+
try {
|
|
75
|
+
const execution = tool.execute(args, client);
|
|
76
|
+
return toSerializedTestingResult(await withAbortSignal(Promise.resolve(execution), options?.signal));
|
|
77
|
+
} catch {
|
|
78
|
+
throw createUnknownError(TOOL_INVOCATION_FAILED_MESSAGE);
|
|
79
|
+
} finally {
|
|
80
|
+
contextActive = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
notifyToolsChanged() {
|
|
84
|
+
if (!this.toolsChangedCallback) return;
|
|
85
|
+
queueMicrotask(() => {
|
|
86
|
+
try {
|
|
87
|
+
this.toolsChangedCallback?.();
|
|
88
|
+
} catch {}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
function createUnknownError(message) {
|
|
93
|
+
try {
|
|
94
|
+
return new DOMException(message, "UnknownError");
|
|
95
|
+
} catch {
|
|
96
|
+
const error = new Error(message);
|
|
97
|
+
error.name = "UnknownError";
|
|
98
|
+
return error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function parseInputArgsJson(inputArgsJson) {
|
|
102
|
+
let parsed;
|
|
103
|
+
try {
|
|
104
|
+
parsed = JSON.parse(inputArgsJson);
|
|
105
|
+
} catch {
|
|
106
|
+
throw createUnknownError(FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE);
|
|
107
|
+
}
|
|
108
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw createUnknownError(FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE);
|
|
109
|
+
return parsed;
|
|
110
|
+
}
|
|
111
|
+
function isPlainObject(value) {
|
|
112
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
113
|
+
}
|
|
114
|
+
function validateInputSchema(schema) {
|
|
115
|
+
if (!isPlainObject(schema)) throw new Error("inputSchema must be a JSON Schema object");
|
|
116
|
+
validateJsonSchemaNode(schema, "$");
|
|
117
|
+
}
|
|
118
|
+
function validateJsonSchemaNode(node, path) {
|
|
119
|
+
const typeValue = node.type;
|
|
120
|
+
if (typeValue !== void 0 && typeof typeValue !== "string" && !(Array.isArray(typeValue) && typeValue.every((entry) => typeof entry === "string" && entry.length > 0))) throw new Error(`Invalid JSON Schema at ${path}: "type" must be a string or string[]`);
|
|
121
|
+
const requiredValue = node.required;
|
|
122
|
+
if (requiredValue !== void 0 && !(Array.isArray(requiredValue) && requiredValue.every((entry) => typeof entry === "string"))) throw new Error(`Invalid JSON Schema at ${path}: "required" must be an array of strings`);
|
|
123
|
+
const propertiesValue = node.properties;
|
|
124
|
+
if (propertiesValue !== void 0) {
|
|
125
|
+
if (!isPlainObject(propertiesValue)) throw new Error(`Invalid JSON Schema at ${path}: "properties" must be an object`);
|
|
126
|
+
for (const [key, value] of Object.entries(propertiesValue)) {
|
|
127
|
+
if (!isPlainObject(value)) throw new Error(`Invalid JSON Schema at ${path}.properties.${key}: expected object schema`);
|
|
128
|
+
validateJsonSchemaNode(value, `${path}.properties.${key}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const itemsValue = node.items;
|
|
132
|
+
if (itemsValue !== void 0) if (Array.isArray(itemsValue)) for (const [index, value] of itemsValue.entries()) {
|
|
133
|
+
if (!isPlainObject(value)) throw new Error(`Invalid JSON Schema at ${path}.items[${index}]: expected object schema`);
|
|
134
|
+
validateJsonSchemaNode(value, `${path}.items[${index}]`);
|
|
135
|
+
}
|
|
136
|
+
else if (isPlainObject(itemsValue)) validateJsonSchemaNode(itemsValue, `${path}.items`);
|
|
137
|
+
else throw new Error(`Invalid JSON Schema at ${path}: "items" must be an object or object[]`);
|
|
138
|
+
for (const keyword of [
|
|
139
|
+
"allOf",
|
|
140
|
+
"anyOf",
|
|
141
|
+
"oneOf"
|
|
142
|
+
]) {
|
|
143
|
+
const value = node[keyword];
|
|
144
|
+
if (value === void 0) continue;
|
|
145
|
+
if (!Array.isArray(value)) throw new Error(`Invalid JSON Schema at ${path}: "${keyword}" must be an array`);
|
|
146
|
+
for (const [index, entry] of value.entries()) {
|
|
147
|
+
if (!isPlainObject(entry)) throw new Error(`Invalid JSON Schema at ${path}.${keyword}[${index}]: expected object schema`);
|
|
148
|
+
validateJsonSchemaNode(entry, `${path}.${keyword}[${index}]`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const notValue = node.not;
|
|
152
|
+
if (notValue !== void 0) {
|
|
153
|
+
if (!isPlainObject(notValue)) throw new Error(`Invalid JSON Schema at ${path}: "not" must be an object schema`);
|
|
154
|
+
validateJsonSchemaNode(notValue, `${path}.not`);
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
JSON.stringify(node);
|
|
158
|
+
} catch {
|
|
159
|
+
throw new Error(`Invalid JSON Schema at ${path}: schema must be JSON-serializable`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function normalizeToolDescriptor(tool, existing) {
|
|
163
|
+
if (!tool || typeof tool !== "object") throw new TypeError("registerTool(tool) requires a tool object");
|
|
164
|
+
if (typeof tool.name !== "string" || tool.name.length === 0) throw new TypeError("Tool \"name\" must be a non-empty string");
|
|
165
|
+
if (typeof tool.description !== "string" || tool.description.length === 0) throw new TypeError("Tool \"description\" must be a non-empty string");
|
|
166
|
+
if (typeof tool.execute !== "function") throw new TypeError("Tool \"execute\" must be a function");
|
|
167
|
+
if (existing.has(tool.name)) throw new Error(`Tool already registered: ${tool.name}`);
|
|
168
|
+
const normalizedInputSchema = tool.inputSchema ?? DEFAULT_INPUT_SCHEMA;
|
|
169
|
+
validateInputSchema(normalizedInputSchema);
|
|
170
|
+
return {
|
|
171
|
+
...tool,
|
|
172
|
+
inputSchema: normalizedInputSchema
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function isMatchingPrimitiveType(value, type) {
|
|
176
|
+
switch (type) {
|
|
177
|
+
case "string": return typeof value === "string";
|
|
178
|
+
case "number": return typeof value === "number" && Number.isFinite(value);
|
|
179
|
+
case "integer": return typeof value === "number" && Number.isInteger(value);
|
|
180
|
+
case "boolean": return typeof value === "boolean";
|
|
181
|
+
case "object": return isPlainObject(value);
|
|
182
|
+
case "array": return Array.isArray(value);
|
|
183
|
+
case "null": return value === null;
|
|
184
|
+
default: return true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function validateArgsWithSchema(args, schema) {
|
|
188
|
+
if (schema.type === "object" && !isPlainObject(args)) return "Input validation error: expected object arguments";
|
|
189
|
+
const properties = isPlainObject(schema.properties) ? schema.properties : void 0;
|
|
190
|
+
const required = Array.isArray(schema.required) ? schema.required.filter((name) => typeof name === "string") : [];
|
|
191
|
+
for (const requiredName of required) if (!(requiredName in args)) return `Input validation error: missing required field "${requiredName}"`;
|
|
192
|
+
if (!properties) return null;
|
|
193
|
+
for (const [key, value] of Object.entries(args)) {
|
|
194
|
+
const propertySchema = properties[key];
|
|
195
|
+
if (!propertySchema || !isPlainObject(propertySchema)) continue;
|
|
196
|
+
const declaredType = propertySchema.type;
|
|
197
|
+
if (typeof declaredType === "string") {
|
|
198
|
+
if (!isMatchingPrimitiveType(value, declaredType)) return `Input validation error: field "${key}" must be of type "${declaredType}"`;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
function getFirstTextBlock(result) {
|
|
204
|
+
for (const block of result.content ?? []) if (block.type === "text" && "text" in block && typeof block.text === "string") return block.text;
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
function toSerializedTestingResult(result) {
|
|
208
|
+
if (result.isError) throw createUnknownError(getFirstTextBlock(result)?.replace(/^Error:\s*/i, "").trim() || TOOL_INVOCATION_FAILED_MESSAGE);
|
|
209
|
+
const metadata = result.metadata;
|
|
210
|
+
if (metadata && typeof metadata === "object" && metadata.willNavigate) return null;
|
|
211
|
+
try {
|
|
212
|
+
return JSON.stringify(result);
|
|
213
|
+
} catch {
|
|
214
|
+
throw createUnknownError(TOOL_INVOCATION_FAILED_MESSAGE);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function withAbortSignal(operation, signal) {
|
|
218
|
+
if (!signal) return operation;
|
|
219
|
+
if (signal.aborted) return Promise.reject(createUnknownError(TOOL_CANCELLED_MESSAGE));
|
|
220
|
+
return new Promise((resolve, reject) => {
|
|
221
|
+
const onAbort = () => {
|
|
222
|
+
cleanup();
|
|
223
|
+
reject(createUnknownError(TOOL_CANCELLED_MESSAGE));
|
|
224
|
+
};
|
|
225
|
+
const cleanup = () => {
|
|
226
|
+
signal.removeEventListener("abort", onAbort);
|
|
227
|
+
};
|
|
228
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
229
|
+
operation.then((value) => {
|
|
230
|
+
cleanup();
|
|
231
|
+
resolve(value);
|
|
232
|
+
}, (error) => {
|
|
233
|
+
cleanup();
|
|
234
|
+
reject(error);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function getNavigator() {
|
|
239
|
+
if (typeof navigator !== "undefined") return navigator;
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
function defineNavigatorProperty(target, key, value) {
|
|
243
|
+
Object.defineProperty(target, key, {
|
|
244
|
+
configurable: true,
|
|
245
|
+
enumerable: true,
|
|
246
|
+
writable: false,
|
|
247
|
+
value
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function initializeWebMCPPolyfill(options) {
|
|
251
|
+
const nav = getNavigator();
|
|
252
|
+
if (!nav) return;
|
|
253
|
+
const forceOverride = options?.forceOverride ?? false;
|
|
254
|
+
if (Boolean(nav.modelContext) && !forceOverride) return;
|
|
255
|
+
if (installState.installed) cleanupWebMCPPolyfill();
|
|
256
|
+
const context = new StrictWebMCPContext();
|
|
257
|
+
const modelContext = context;
|
|
258
|
+
modelContext[POLYFILL_MARKER_PROPERTY] = true;
|
|
259
|
+
installState.previousModelContextDescriptor = Object.getOwnPropertyDescriptor(nav, "modelContext");
|
|
260
|
+
installState.previousModelContextTestingDescriptor = Object.getOwnPropertyDescriptor(nav, "modelContextTesting");
|
|
261
|
+
defineNavigatorProperty(nav, "modelContext", modelContext);
|
|
262
|
+
if (options?.installTestingShim ?? true) defineNavigatorProperty(nav, "modelContextTesting", context.getTestingShim());
|
|
263
|
+
installState.installed = true;
|
|
264
|
+
}
|
|
265
|
+
function cleanupWebMCPPolyfill() {
|
|
266
|
+
const nav = getNavigator();
|
|
267
|
+
if (!nav || !installState.installed) return;
|
|
268
|
+
const restore = (key, previousDescriptor) => {
|
|
269
|
+
if (previousDescriptor) {
|
|
270
|
+
Object.defineProperty(nav, key, previousDescriptor);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
delete nav[key];
|
|
274
|
+
};
|
|
275
|
+
restore("modelContext", installState.previousModelContextDescriptor);
|
|
276
|
+
restore("modelContextTesting", installState.previousModelContextTestingDescriptor);
|
|
277
|
+
installState.installed = false;
|
|
278
|
+
installState.previousModelContextDescriptor = void 0;
|
|
279
|
+
installState.previousModelContextTestingDescriptor = void 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
//#endregion
|
|
283
|
+
export { cleanupWebMCPPolyfill, initializeWebMCPPolyfill, initializeWebMCPPolyfill as initializeWebModelContextPolyfill };
|
|
284
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["DEFAULT_INPUT_SCHEMA: InputSchema","installState: InstallState","output: { name: string; description: string; inputSchema?: string }","client: ModelContextClient","parsed: unknown"],"sources":["../src/index.ts"],"sourcesContent":["import type {\n InputSchema,\n ModelContext,\n ModelContextClient,\n ModelContextOptions,\n ModelContextTesting,\n ModelContextTestingExecuteToolOptions,\n ToolDescriptor,\n ToolResponse,\n} from '@mcp-b/webmcp-types';\n\nconst FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE = 'Failed to parse input arguments';\nconst TOOL_INVOCATION_FAILED_MESSAGE =\n 'Tool was executed but the invocation failed. For example, the script function threw an error';\nconst TOOL_CANCELLED_MESSAGE = 'Tool was cancelled';\nconst DEFAULT_INPUT_SCHEMA: InputSchema = { type: 'object', properties: {} };\n\nconst POLYFILL_MARKER_PROPERTY = '__isWebMCPPolyfill' as const;\n\ninterface PolyfillModelContext extends ModelContext {\n [POLYFILL_MARKER_PROPERTY]: true;\n}\n\ninterface InstallState {\n installed: boolean;\n previousModelContextDescriptor: PropertyDescriptor | undefined;\n previousModelContextTestingDescriptor: PropertyDescriptor | undefined;\n}\n\nconst installState: InstallState = {\n installed: false,\n previousModelContextDescriptor: undefined,\n previousModelContextTestingDescriptor: undefined,\n};\n\nexport interface WebMCPPolyfillInitOptions {\n /**\n * Force installation even when navigator.modelContext already exists.\n * Existing descriptors are restored by cleanupWebMCPPolyfill().\n */\n forceOverride?: boolean;\n\n /**\n * Installs navigator.modelContextTesting when this polyfill provides modelContext.\n * @default true\n */\n installTestingShim?: boolean;\n\n /**\n * Deprecated no-op kept for compatibility with previous wrapper options.\n */\n disableIframeTransportByDefault?: boolean;\n}\n\nclass StrictWebMCPContext {\n private tools = new Map<string, ToolDescriptor>();\n private toolsChangedCallback: (() => void) | null = null;\n\n provideContext(options: ModelContextOptions = {}): void {\n const nextTools = new Map<string, ToolDescriptor>();\n\n for (const tool of options.tools ?? []) {\n const normalized = normalizeToolDescriptor(tool, nextTools);\n nextTools.set(normalized.name, normalized);\n }\n\n this.tools = nextTools;\n this.notifyToolsChanged();\n }\n\n clearContext(): void {\n this.tools.clear();\n this.notifyToolsChanged();\n }\n\n registerTool(tool: ToolDescriptor): void {\n const normalized = normalizeToolDescriptor(tool, this.tools);\n this.tools.set(normalized.name, normalized);\n this.notifyToolsChanged();\n }\n\n unregisterTool(name: string): void {\n const removed = this.tools.delete(name);\n if (removed) {\n this.notifyToolsChanged();\n }\n }\n\n getTestingShim(): ModelContextTesting {\n return {\n listTools: () => {\n return [...this.tools.values()].map((tool) => {\n const output: { name: string; description: string; inputSchema?: string } = {\n name: tool.name,\n description: tool.description,\n };\n\n try {\n output.inputSchema = JSON.stringify(tool.inputSchema ?? DEFAULT_INPUT_SCHEMA);\n } catch {\n // Keep inputSchema omitted when serialization fails.\n }\n\n return output;\n });\n },\n executeTool: (\n toolName: string,\n inputArgsJson: string,\n options?: ModelContextTestingExecuteToolOptions\n ) => this.executeToolForTesting(toolName, inputArgsJson, options),\n registerToolsChangedCallback: (callback: () => void) => {\n if (typeof callback !== 'function') {\n throw new TypeError(\n \"Failed to execute 'registerToolsChangedCallback' on 'ModelContextTesting': parameter 1 is not of type 'Function'.\"\n );\n }\n this.toolsChangedCallback = callback;\n },\n getCrossDocumentScriptToolResult: async () => '[]',\n };\n }\n\n private async executeToolForTesting(\n toolName: string,\n inputArgsJson: string,\n options?: ModelContextTestingExecuteToolOptions\n ): Promise<string | null> {\n if (options?.signal?.aborted) {\n throw createUnknownError(TOOL_CANCELLED_MESSAGE);\n }\n\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw createUnknownError(`Tool not found: ${toolName}`);\n }\n\n const args = parseInputArgsJson(inputArgsJson);\n const validationError = validateArgsWithSchema(args, tool.inputSchema ?? DEFAULT_INPUT_SCHEMA);\n if (validationError) {\n throw createUnknownError(validationError);\n }\n\n let contextActive = true;\n const client: ModelContextClient = {\n requestUserInteraction: async (callback: () => Promise<unknown>): Promise<unknown> => {\n if (!contextActive) {\n throw new Error(\n `ModelContextClient for tool \"${toolName}\" is no longer active after execute() resolved`\n );\n }\n\n if (typeof callback !== 'function') {\n throw new TypeError('requestUserInteraction(callback) requires a function callback');\n }\n\n return callback();\n },\n };\n\n try {\n const execution = tool.execute(args, client);\n const result = await withAbortSignal(Promise.resolve(execution), options?.signal);\n return toSerializedTestingResult(result);\n } catch {\n throw createUnknownError(TOOL_INVOCATION_FAILED_MESSAGE);\n } finally {\n contextActive = false;\n }\n }\n\n private notifyToolsChanged(): void {\n if (!this.toolsChangedCallback) {\n return;\n }\n\n queueMicrotask(() => {\n try {\n this.toolsChangedCallback?.();\n } catch {\n // Callback errors are ignored to match browser event callback behavior.\n }\n });\n }\n}\n\nfunction createUnknownError(message: string): Error {\n try {\n return new DOMException(message, 'UnknownError');\n } catch {\n const error = new Error(message);\n error.name = 'UnknownError';\n return error;\n }\n}\n\nfunction parseInputArgsJson(inputArgsJson: string): Record<string, unknown> {\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(inputArgsJson);\n } catch {\n throw createUnknownError(FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE);\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw createUnknownError(FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE);\n }\n\n return parsed as Record<string, unknown>;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction validateInputSchema(schema: unknown): asserts schema is InputSchema {\n if (!isPlainObject(schema)) {\n throw new Error('inputSchema must be a JSON Schema object');\n }\n\n validateJsonSchemaNode(schema, '$');\n}\n\nfunction validateJsonSchemaNode(node: Record<string, unknown>, path: string): void {\n const typeValue = node.type;\n if (\n typeValue !== undefined &&\n typeof typeValue !== 'string' &&\n !(\n Array.isArray(typeValue) &&\n typeValue.every((entry) => typeof entry === 'string' && entry.length > 0)\n )\n ) {\n throw new Error(`Invalid JSON Schema at ${path}: \"type\" must be a string or string[]`);\n }\n\n const requiredValue = node.required;\n if (\n requiredValue !== undefined &&\n !(Array.isArray(requiredValue) && requiredValue.every((entry) => typeof entry === 'string'))\n ) {\n throw new Error(`Invalid JSON Schema at ${path}: \"required\" must be an array of strings`);\n }\n\n const propertiesValue = node.properties;\n if (propertiesValue !== undefined) {\n if (!isPlainObject(propertiesValue)) {\n throw new Error(`Invalid JSON Schema at ${path}: \"properties\" must be an object`);\n }\n\n for (const [key, value] of Object.entries(propertiesValue)) {\n if (!isPlainObject(value)) {\n throw new Error(`Invalid JSON Schema at ${path}.properties.${key}: expected object schema`);\n }\n validateJsonSchemaNode(value, `${path}.properties.${key}`);\n }\n }\n\n const itemsValue = node.items;\n if (itemsValue !== undefined) {\n if (Array.isArray(itemsValue)) {\n for (const [index, value] of itemsValue.entries()) {\n if (!isPlainObject(value)) {\n throw new Error(`Invalid JSON Schema at ${path}.items[${index}]: expected object schema`);\n }\n validateJsonSchemaNode(value, `${path}.items[${index}]`);\n }\n } else if (isPlainObject(itemsValue)) {\n validateJsonSchemaNode(itemsValue, `${path}.items`);\n } else {\n throw new Error(`Invalid JSON Schema at ${path}: \"items\" must be an object or object[]`);\n }\n }\n\n for (const keyword of ['allOf', 'anyOf', 'oneOf'] as const) {\n const value = node[keyword];\n if (value === undefined) {\n continue;\n }\n\n if (!Array.isArray(value)) {\n throw new Error(`Invalid JSON Schema at ${path}: \"${keyword}\" must be an array`);\n }\n\n for (const [index, entry] of value.entries()) {\n if (!isPlainObject(entry)) {\n throw new Error(\n `Invalid JSON Schema at ${path}.${keyword}[${index}]: expected object schema`\n );\n }\n validateJsonSchemaNode(entry, `${path}.${keyword}[${index}]`);\n }\n }\n\n const notValue = node.not;\n if (notValue !== undefined) {\n if (!isPlainObject(notValue)) {\n throw new Error(`Invalid JSON Schema at ${path}: \"not\" must be an object schema`);\n }\n validateJsonSchemaNode(notValue, `${path}.not`);\n }\n\n try {\n JSON.stringify(node);\n } catch {\n throw new Error(`Invalid JSON Schema at ${path}: schema must be JSON-serializable`);\n }\n}\n\nfunction normalizeToolDescriptor(\n tool: ToolDescriptor,\n existing: Map<string, ToolDescriptor>\n): ToolDescriptor {\n if (!tool || typeof tool !== 'object') {\n throw new TypeError('registerTool(tool) requires a tool object');\n }\n\n if (typeof tool.name !== 'string' || tool.name.length === 0) {\n throw new TypeError('Tool \"name\" must be a non-empty string');\n }\n\n if (typeof tool.description !== 'string' || tool.description.length === 0) {\n throw new TypeError('Tool \"description\" must be a non-empty string');\n }\n\n if (typeof tool.execute !== 'function') {\n throw new TypeError('Tool \"execute\" must be a function');\n }\n\n if (existing.has(tool.name)) {\n throw new Error(`Tool already registered: ${tool.name}`);\n }\n\n const normalizedInputSchema = (tool.inputSchema ?? DEFAULT_INPUT_SCHEMA) as unknown;\n validateInputSchema(normalizedInputSchema);\n\n return {\n ...tool,\n inputSchema: normalizedInputSchema,\n };\n}\n\nfunction isMatchingPrimitiveType(value: unknown, type: string): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && Number.isFinite(value);\n case 'integer':\n return typeof value === 'number' && Number.isInteger(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'object':\n return isPlainObject(value);\n case 'array':\n return Array.isArray(value);\n case 'null':\n return value === null;\n default:\n return true;\n }\n}\n\nfunction validateArgsWithSchema(args: Record<string, unknown>, schema: InputSchema): string | null {\n if (schema.type === 'object' && !isPlainObject(args)) {\n return 'Input validation error: expected object arguments';\n }\n\n const properties = isPlainObject(schema.properties) ? schema.properties : undefined;\n const required = Array.isArray(schema.required)\n ? schema.required.filter((name): name is string => typeof name === 'string')\n : [];\n\n for (const requiredName of required) {\n if (!(requiredName in args)) {\n return `Input validation error: missing required field \"${requiredName}\"`;\n }\n }\n\n if (!properties) {\n return null;\n }\n\n for (const [key, value] of Object.entries(args)) {\n const propertySchema = properties[key];\n if (!propertySchema || !isPlainObject(propertySchema)) {\n continue;\n }\n\n const declaredType = propertySchema.type;\n if (typeof declaredType === 'string') {\n if (!isMatchingPrimitiveType(value, declaredType)) {\n return `Input validation error: field \"${key}\" must be of type \"${declaredType}\"`;\n }\n }\n }\n\n return null;\n}\n\nfunction getFirstTextBlock(result: ToolResponse): string | null {\n for (const block of result.content ?? []) {\n if (block.type === 'text' && 'text' in block && typeof block.text === 'string') {\n return block.text;\n }\n }\n\n return null;\n}\n\nfunction toSerializedTestingResult(result: ToolResponse): string | null {\n if (result.isError) {\n const firstText = getFirstTextBlock(result);\n const message = firstText?.replace(/^Error:\\s*/i, '').trim() || TOOL_INVOCATION_FAILED_MESSAGE;\n throw createUnknownError(message);\n }\n\n const metadata = (result as ToolResponse & { metadata?: { willNavigate?: boolean } }).metadata;\n if (metadata && typeof metadata === 'object' && metadata.willNavigate) {\n return null;\n }\n\n try {\n return JSON.stringify(result);\n } catch {\n throw createUnknownError(TOOL_INVOCATION_FAILED_MESSAGE);\n }\n}\n\nfunction withAbortSignal<T>(operation: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) {\n return operation;\n }\n\n if (signal.aborted) {\n return Promise.reject(createUnknownError(TOOL_CANCELLED_MESSAGE));\n }\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n cleanup();\n reject(createUnknownError(TOOL_CANCELLED_MESSAGE));\n };\n\n const cleanup = () => {\n signal.removeEventListener('abort', onAbort);\n };\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n operation.then(\n (value) => {\n cleanup();\n resolve(value);\n },\n (error) => {\n cleanup();\n reject(error);\n }\n );\n });\n}\n\nfunction getNavigator(): Navigator | null {\n if (typeof navigator !== 'undefined') {\n return navigator;\n }\n\n return null;\n}\n\nfunction defineNavigatorProperty<K extends keyof Navigator>(\n target: Navigator,\n key: K,\n value: Navigator[K]\n): void {\n Object.defineProperty(target, key, {\n configurable: true,\n enumerable: true,\n writable: false,\n value,\n });\n}\n\nexport function initializeWebMCPPolyfill(options?: WebMCPPolyfillInitOptions): void {\n const nav = getNavigator();\n if (!nav) {\n return;\n }\n\n const forceOverride = options?.forceOverride ?? false;\n const hasModelContext = Boolean(nav.modelContext);\n\n if (hasModelContext && !forceOverride) {\n return;\n }\n\n if (installState.installed) {\n cleanupWebMCPPolyfill();\n }\n\n const context = new StrictWebMCPContext();\n const modelContext = context as unknown as PolyfillModelContext;\n modelContext[POLYFILL_MARKER_PROPERTY] = true;\n\n installState.previousModelContextDescriptor = Object.getOwnPropertyDescriptor(\n nav,\n 'modelContext'\n );\n installState.previousModelContextTestingDescriptor = Object.getOwnPropertyDescriptor(\n nav,\n 'modelContextTesting'\n );\n\n defineNavigatorProperty(nav, 'modelContext', modelContext as Navigator['modelContext']);\n\n const installTestingShim = options?.installTestingShim ?? true;\n if (installTestingShim) {\n defineNavigatorProperty(\n nav,\n 'modelContextTesting',\n context.getTestingShim() as Navigator['modelContextTesting']\n );\n }\n\n installState.installed = true;\n}\n\nexport function cleanupWebMCPPolyfill(): void {\n const nav = getNavigator();\n if (!nav || !installState.installed) {\n return;\n }\n\n const restore = <K extends keyof Navigator>(\n key: K,\n previousDescriptor: PropertyDescriptor | undefined\n ) => {\n if (previousDescriptor) {\n Object.defineProperty(nav, key, previousDescriptor);\n return;\n }\n\n delete (nav as unknown as Record<string, unknown>)[key as string];\n };\n\n restore('modelContext', installState.previousModelContextDescriptor);\n restore('modelContextTesting', installState.previousModelContextTestingDescriptor);\n\n installState.installed = false;\n installState.previousModelContextDescriptor = undefined;\n installState.previousModelContextTestingDescriptor = undefined;\n}\n\nexport { initializeWebMCPPolyfill as initializeWebModelContextPolyfill };\n\nexport type {\n InputSchema,\n ModelContext,\n ModelContextClient,\n ModelContextCore,\n ModelContextOptions,\n ToolAnnotations,\n ToolDescriptor,\n ToolResponse,\n} from '@mcp-b/webmcp-types';\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcp-b/webmcp-polyfill",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Strict WebMCP core runtime polyfill for navigator.modelContext",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"webmcp",
|
|
7
|
+
"model-context",
|
|
8
|
+
"navigator-modelcontext",
|
|
9
|
+
"polyfill",
|
|
10
|
+
"browser"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://docs.mcp-b.ai/packages/webmcp-polyfill",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/WebMCP-org/npm-packages/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/WebMCP-org/npm-packages.git",
|
|
19
|
+
"directory": "packages/webmcp-polyfill"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Alex Nahas",
|
|
23
|
+
"sideEffects": true,
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@mcp-b/webmcp-types": "0.1.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
43
|
+
"tsdown": "^0.15.10",
|
|
44
|
+
"typescript": "^5.8.3",
|
|
45
|
+
"vitest": "^4.0.18"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public",
|
|
52
|
+
"registry": "https://registry.npmjs.org/"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "pnpm --filter @mcp-b/webmcp-types build && tsdown",
|
|
56
|
+
"check": "biome check --write .",
|
|
57
|
+
"clean": "rm -rf dist .turbo",
|
|
58
|
+
"format": "biome format --write .",
|
|
59
|
+
"lint": "biome lint --write .",
|
|
60
|
+
"publish:dry": "pnpm publish --access public --dry-run",
|
|
61
|
+
"publish:npm": "pnpm publish --access public",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"typecheck": "pnpm --filter @mcp-b/webmcp-types build && tsc --noEmit && vitest run --typecheck --silent"
|
|
64
|
+
}
|
|
65
|
+
}
|