@mcp-b/webmcp-polyfill 2.3.2 → 3.0.0-beta.20260702171253
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 +36 -29
- package/dist/index.d.ts +2 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.iife.js +2 -2
- package/dist/index.js +139 -204
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +21 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +167 -0
- package/dist/schema.js.map +1 -0
- package/package.json +13 -7
package/dist/index.js
CHANGED
|
@@ -1,61 +1,47 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isPlainObject, normalizeInputSchema, toJsonValue, validateValueWithSchema } from "./schema.js";
|
|
2
2
|
|
|
3
3
|
//#region src/index.ts
|
|
4
4
|
const FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE = "Failed to parse input arguments";
|
|
5
5
|
const TOOL_INVOCATION_FAILED_MESSAGE = "Tool was executed but the invocation failed. For example, the script function threw an error";
|
|
6
6
|
const TOOL_CANCELLED_MESSAGE = "Tool was cancelled";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
properties: {}
|
|
10
|
-
};
|
|
11
|
-
const STANDARD_JSON_SCHEMA_TARGETS = ["draft-2020-12", "draft-07"];
|
|
7
|
+
/** WebMCP §4.2 tool name: ASCII alnum, underscore, hyphen, period; 1–128 code points. */
|
|
8
|
+
const VALID_TOOL_NAME_RE = /^[A-Za-z0-9_\-.]{1,128}$/u;
|
|
12
9
|
const POLYFILL_MARKER_PROPERTY = "__isWebMCPPolyfill";
|
|
13
10
|
const STANDARD_VALIDATOR_SYMBOL = Symbol("standardValidator");
|
|
11
|
+
function createAbortError() {
|
|
12
|
+
return new DOMException("signal is aborted without reason", "AbortError");
|
|
13
|
+
}
|
|
14
14
|
const installState = {
|
|
15
15
|
installed: false,
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
previousNavigatorModelContextDescriptor: void 0,
|
|
17
|
+
previousNavigatorModelContextTestingDescriptor: void 0,
|
|
18
|
+
previousDocumentModelContextDescriptor: void 0,
|
|
19
|
+
installedNavigatorModelContext: false,
|
|
20
|
+
installedNavigatorModelContextTesting: false,
|
|
21
|
+
installedDocumentModelContext: false
|
|
18
22
|
};
|
|
19
23
|
var StrictWebMCPContext = class extends EventTarget {
|
|
20
24
|
tools = /* @__PURE__ */ new Map();
|
|
21
25
|
testingShim = null;
|
|
22
26
|
_ontoolchange = null;
|
|
23
|
-
provideContextDeprecationWarned = false;
|
|
24
|
-
clearContextDeprecationWarned = false;
|
|
25
27
|
unregisterToolDeprecationWarned = false;
|
|
28
|
+
toolsChangedQueued = false;
|
|
26
29
|
get ontoolchange() {
|
|
27
30
|
return this._ontoolchange;
|
|
28
31
|
}
|
|
29
32
|
set ontoolchange(handler) {
|
|
30
33
|
this._ontoolchange = handler;
|
|
31
34
|
}
|
|
32
|
-
provideContext(options = {}) {
|
|
33
|
-
this.warnProvideContextDeprecationOnce();
|
|
34
|
-
const nextTools = /* @__PURE__ */ new Map();
|
|
35
|
-
for (const tool of options.tools ?? []) {
|
|
36
|
-
const normalized = normalizeToolDescriptor(tool, nextTools);
|
|
37
|
-
nextTools.set(normalized.name, normalized);
|
|
38
|
-
}
|
|
39
|
-
this.tools = nextTools;
|
|
40
|
-
this.notifyToolsChanged();
|
|
41
|
-
}
|
|
42
|
-
clearContext() {
|
|
43
|
-
this.warnClearContextDeprecationOnce();
|
|
44
|
-
this.tools.clear();
|
|
45
|
-
this.notifyToolsChanged();
|
|
46
|
-
}
|
|
47
35
|
registerTool(tool, options) {
|
|
48
36
|
const signal = options?.signal;
|
|
49
|
-
if (signal?.aborted)
|
|
50
|
-
console.warn(`[WebMCPPolyfill] registerTool("${tool?.name ?? "<unknown>"}") skipped: options.signal was already aborted.`);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
37
|
+
if (signal?.aborted) return Promise.reject(createAbortError());
|
|
53
38
|
const normalized = normalizeToolDescriptor(tool, this.tools);
|
|
54
39
|
this.tools.set(normalized.name, normalized);
|
|
55
40
|
this.notifyToolsChanged();
|
|
56
41
|
if (signal) signal.addEventListener("abort", () => {
|
|
57
42
|
if (this.tools.delete(normalized.name)) this.notifyToolsChanged();
|
|
58
43
|
}, { once: true });
|
|
44
|
+
return Promise.resolve();
|
|
59
45
|
}
|
|
60
46
|
unregisterTool(nameOrTool) {
|
|
61
47
|
this.warnUnregisterToolDeprecationOnce();
|
|
@@ -63,7 +49,10 @@ var StrictWebMCPContext = class extends EventTarget {
|
|
|
63
49
|
if (this.tools.delete(name)) this.notifyToolsChanged();
|
|
64
50
|
}
|
|
65
51
|
getTools() {
|
|
66
|
-
return this.
|
|
52
|
+
return Promise.resolve(this.getRegisteredToolInfos());
|
|
53
|
+
}
|
|
54
|
+
executeTool(tool, inputArgsJson, options) {
|
|
55
|
+
return this.executeToolByName(tool.name, inputArgsJson, options, false);
|
|
67
56
|
}
|
|
68
57
|
getTestingShim() {
|
|
69
58
|
if (!this.testingShim) this.testingShim = new PolyfillTestingShim(this);
|
|
@@ -85,8 +74,23 @@ var StrictWebMCPContext = class extends EventTarget {
|
|
|
85
74
|
};
|
|
86
75
|
});
|
|
87
76
|
}
|
|
77
|
+
/** @internal Used by getTools() */
|
|
78
|
+
getRegisteredToolInfos() {
|
|
79
|
+
return this.getToolInfos().map((toolInfo) => {
|
|
80
|
+
const tool = this.tools.get(toolInfo.name);
|
|
81
|
+
return {
|
|
82
|
+
...toolInfo,
|
|
83
|
+
title: tool?.title ?? "",
|
|
84
|
+
origin: globalThis.location?.origin ?? "",
|
|
85
|
+
window: globalThis.window
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
}
|
|
88
89
|
/** @internal Used by PolyfillTestingShim */
|
|
89
90
|
async executeToolForTesting(toolName, inputArgsJson, options) {
|
|
91
|
+
return this.executeToolByName(toolName, inputArgsJson, options, true);
|
|
92
|
+
}
|
|
93
|
+
async executeToolByName(toolName, inputArgsJson, options, normalizeResult) {
|
|
90
94
|
if (options?.signal?.aborted) throw createUnknownError(TOOL_CANCELLED_MESSAGE);
|
|
91
95
|
const tool = this.tools.get(toolName);
|
|
92
96
|
if (!tool) throw createUnknownError(`Tool not found: ${toolName}`);
|
|
@@ -101,7 +105,13 @@ var StrictWebMCPContext = class extends EventTarget {
|
|
|
101
105
|
} };
|
|
102
106
|
try {
|
|
103
107
|
const execution = tool.execute(args, client);
|
|
104
|
-
|
|
108
|
+
const rawResult = await withAbortSignal(Promise.resolve(execution), options?.signal);
|
|
109
|
+
const normalizedResult = normalizeToolResponse(rawResult);
|
|
110
|
+
const outputValidationError = validateOutputForTool(normalizedResult, tool);
|
|
111
|
+
if (outputValidationError) throw new Error(outputValidationError);
|
|
112
|
+
if (normalizeResult) return toSerializedTestingResult(normalizedResult);
|
|
113
|
+
const serialized = JSON.stringify(rawResult);
|
|
114
|
+
return serialized === void 0 ? null : serialized;
|
|
105
115
|
} catch (error) {
|
|
106
116
|
throw createUnknownError(error instanceof Error ? `${TOOL_INVOCATION_FAILED_MESSAGE}: ${error.message}` : TOOL_INVOCATION_FAILED_MESSAGE);
|
|
107
117
|
} finally {
|
|
@@ -109,7 +119,10 @@ var StrictWebMCPContext = class extends EventTarget {
|
|
|
109
119
|
}
|
|
110
120
|
}
|
|
111
121
|
notifyToolsChanged() {
|
|
122
|
+
if (this.toolsChangedQueued) return;
|
|
123
|
+
this.toolsChangedQueued = true;
|
|
112
124
|
queueMicrotask(() => {
|
|
125
|
+
this.toolsChangedQueued = false;
|
|
113
126
|
const event = new Event("toolchange");
|
|
114
127
|
try {
|
|
115
128
|
this._ontoolchange?.call(this, event);
|
|
@@ -120,16 +133,6 @@ var StrictWebMCPContext = class extends EventTarget {
|
|
|
120
133
|
this.testingShim?.dispatchToolChange();
|
|
121
134
|
});
|
|
122
135
|
}
|
|
123
|
-
warnProvideContextDeprecationOnce() {
|
|
124
|
-
if (this.provideContextDeprecationWarned) return;
|
|
125
|
-
this.provideContextDeprecationWarned = true;
|
|
126
|
-
console.warn("[WebMCPPolyfill] navigator.modelContext.provideContext() is deprecated and will be removed in the next major version. Register tools individually with registerTool() instead.");
|
|
127
|
-
}
|
|
128
|
-
warnClearContextDeprecationOnce() {
|
|
129
|
-
if (this.clearContextDeprecationWarned) return;
|
|
130
|
-
this.clearContextDeprecationWarned = true;
|
|
131
|
-
console.warn("[WebMCPPolyfill] navigator.modelContext.clearContext() is deprecated and will be removed in the next major version. Unregister individual tools instead.");
|
|
132
|
-
}
|
|
133
136
|
warnUnregisterToolDeprecationOnce() {
|
|
134
137
|
if (this.unregisterToolDeprecationWarned) return;
|
|
135
138
|
this.unregisterToolDeprecationWarned = true;
|
|
@@ -194,6 +197,15 @@ function createUnknownError(message) {
|
|
|
194
197
|
return error;
|
|
195
198
|
}
|
|
196
199
|
}
|
|
200
|
+
function createInvalidStateError(message) {
|
|
201
|
+
try {
|
|
202
|
+
return new DOMException(message, "InvalidStateError");
|
|
203
|
+
} catch {
|
|
204
|
+
const error = new Error(message);
|
|
205
|
+
error.name = "InvalidStateError";
|
|
206
|
+
return error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
197
209
|
function parseInputArgsJson(inputArgsJson) {
|
|
198
210
|
let parsed;
|
|
199
211
|
try {
|
|
@@ -209,131 +221,11 @@ function getToolNameForUnregister(nameOrTool) {
|
|
|
209
221
|
if (isPlainObject(nameOrTool) && typeof nameOrTool.name === "string") return nameOrTool.name;
|
|
210
222
|
throw new TypeError("Failed to execute 'unregisterTool' on 'ModelContext': parameter 1 must be a string or an object with a string name.");
|
|
211
223
|
}
|
|
212
|
-
function isPlainObject(value) {
|
|
213
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
214
|
-
}
|
|
215
|
-
function getStandardProps(value) {
|
|
216
|
-
if (!isPlainObject(value)) return null;
|
|
217
|
-
const standard = value["~standard"];
|
|
218
|
-
if (!isPlainObject(standard)) return null;
|
|
219
|
-
return standard;
|
|
220
|
-
}
|
|
221
|
-
function isStandardInputValidatorSchema(value) {
|
|
222
|
-
const standard = getStandardProps(value);
|
|
223
|
-
return Boolean(standard && standard.version === 1 && typeof standard.validate === "function");
|
|
224
|
-
}
|
|
225
|
-
function isStandardInputJsonSchema(value) {
|
|
226
|
-
const standard = getStandardProps(value);
|
|
227
|
-
if (!standard || standard.version !== 1 || !isPlainObject(standard.jsonSchema)) return false;
|
|
228
|
-
return typeof standard.jsonSchema.input === "function";
|
|
229
|
-
}
|
|
230
|
-
function createStandardValidatorFromJsonSchema(schema) {
|
|
231
|
-
return { "~standard": {
|
|
232
|
-
version: 1,
|
|
233
|
-
vendor: "@mcp-b/webmcp-polyfill-json-schema",
|
|
234
|
-
validate(value) {
|
|
235
|
-
if (!isPlainObject(value)) return { issues: [{ message: "expected object arguments" }] };
|
|
236
|
-
const issue = validateArgsWithSchema(value, schema);
|
|
237
|
-
if (issue) return { issues: [issue] };
|
|
238
|
-
return { value };
|
|
239
|
-
}
|
|
240
|
-
} };
|
|
241
|
-
}
|
|
242
|
-
function convertStandardInputSchema(schema) {
|
|
243
|
-
for (const target of STANDARD_JSON_SCHEMA_TARGETS) try {
|
|
244
|
-
const converted = schema["~standard"].jsonSchema.input({ target });
|
|
245
|
-
validateInputSchema(converted);
|
|
246
|
-
return converted;
|
|
247
|
-
} catch (error) {
|
|
248
|
-
console.warn(`[WebMCPPolyfill] Standard JSON Schema conversion failed for target "${target}":`, error);
|
|
249
|
-
}
|
|
250
|
-
throw new Error("Failed to convert Standard JSON Schema inputSchema to a JSON Schema object");
|
|
251
|
-
}
|
|
252
|
-
function normalizeInputSchema(inputSchema) {
|
|
253
|
-
if (inputSchema === void 0) {
|
|
254
|
-
const normalized = DEFAULT_INPUT_SCHEMA;
|
|
255
|
-
return {
|
|
256
|
-
inputSchema: normalized,
|
|
257
|
-
standardValidator: createStandardValidatorFromJsonSchema(normalized)
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
if (isStandardInputJsonSchema(inputSchema)) {
|
|
261
|
-
const converted = convertStandardInputSchema(inputSchema);
|
|
262
|
-
return {
|
|
263
|
-
inputSchema: converted,
|
|
264
|
-
standardValidator: createStandardValidatorFromJsonSchema(converted)
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
if (isStandardInputValidatorSchema(inputSchema)) return {
|
|
268
|
-
inputSchema: DEFAULT_INPUT_SCHEMA,
|
|
269
|
-
standardValidator: inputSchema
|
|
270
|
-
};
|
|
271
|
-
validateInputSchema(inputSchema);
|
|
272
|
-
if (Object.keys(inputSchema).length === 0) return {
|
|
273
|
-
inputSchema: DEFAULT_INPUT_SCHEMA,
|
|
274
|
-
standardValidator: createStandardValidatorFromJsonSchema(DEFAULT_INPUT_SCHEMA)
|
|
275
|
-
};
|
|
276
|
-
const normalizedSchema = inputSchema.type === void 0 ? {
|
|
277
|
-
type: "object",
|
|
278
|
-
...inputSchema
|
|
279
|
-
} : inputSchema;
|
|
280
|
-
return {
|
|
281
|
-
inputSchema: normalizedSchema,
|
|
282
|
-
standardValidator: createStandardValidatorFromJsonSchema(normalizedSchema)
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
function validateInputSchema(schema) {
|
|
286
|
-
if (!isPlainObject(schema)) throw new Error("inputSchema must be a JSON Schema object");
|
|
287
|
-
validateJsonSchemaNode(schema, "$");
|
|
288
|
-
}
|
|
289
|
-
function validateJsonSchemaNode(node, path) {
|
|
290
|
-
const typeValue = node.type;
|
|
291
|
-
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[]`);
|
|
292
|
-
const requiredValue = node.required;
|
|
293
|
-
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`);
|
|
294
|
-
const propertiesValue = node.properties;
|
|
295
|
-
if (propertiesValue !== void 0) {
|
|
296
|
-
if (!isPlainObject(propertiesValue)) throw new Error(`Invalid JSON Schema at ${path}: "properties" must be an object`);
|
|
297
|
-
for (const [key, value] of Object.entries(propertiesValue)) {
|
|
298
|
-
if (!isPlainObject(value)) throw new Error(`Invalid JSON Schema at ${path}.properties.${key}: expected object schema`);
|
|
299
|
-
validateJsonSchemaNode(value, `${path}.properties.${key}`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
const itemsValue = node.items;
|
|
303
|
-
if (itemsValue !== void 0) if (Array.isArray(itemsValue)) for (const [index, value] of itemsValue.entries()) {
|
|
304
|
-
if (!isPlainObject(value)) throw new Error(`Invalid JSON Schema at ${path}.items[${index}]: expected object schema`);
|
|
305
|
-
validateJsonSchemaNode(value, `${path}.items[${index}]`);
|
|
306
|
-
}
|
|
307
|
-
else if (isPlainObject(itemsValue)) validateJsonSchemaNode(itemsValue, `${path}.items`);
|
|
308
|
-
else throw new Error(`Invalid JSON Schema at ${path}: "items" must be an object or object[]`);
|
|
309
|
-
for (const keyword of [
|
|
310
|
-
"allOf",
|
|
311
|
-
"anyOf",
|
|
312
|
-
"oneOf"
|
|
313
|
-
]) {
|
|
314
|
-
const value = node[keyword];
|
|
315
|
-
if (value === void 0) continue;
|
|
316
|
-
if (!Array.isArray(value)) throw new Error(`Invalid JSON Schema at ${path}: "${keyword}" must be an array`);
|
|
317
|
-
for (const [index, entry] of value.entries()) {
|
|
318
|
-
if (!isPlainObject(entry)) throw new Error(`Invalid JSON Schema at ${path}.${keyword}[${index}]: expected object schema`);
|
|
319
|
-
validateJsonSchemaNode(entry, `${path}.${keyword}[${index}]`);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
const notValue = node.not;
|
|
323
|
-
if (notValue !== void 0) {
|
|
324
|
-
if (!isPlainObject(notValue)) throw new Error(`Invalid JSON Schema at ${path}: "not" must be an object schema`);
|
|
325
|
-
validateJsonSchemaNode(notValue, `${path}.not`);
|
|
326
|
-
}
|
|
327
|
-
try {
|
|
328
|
-
JSON.stringify(node);
|
|
329
|
-
} catch {
|
|
330
|
-
throw new Error(`Invalid JSON Schema at ${path}: schema must be JSON-serializable`);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
224
|
function normalizeToolDescriptor(tool, existing) {
|
|
334
225
|
if (!tool || typeof tool !== "object") throw new TypeError("registerTool(tool) requires a tool object");
|
|
335
|
-
if (typeof tool.name !== "string" || tool.name.length === 0) throw
|
|
336
|
-
if (
|
|
226
|
+
if (typeof tool.name !== "string" || tool.name.length === 0) throw createInvalidStateError("Tool \"name\" must be a non-empty string");
|
|
227
|
+
if (!VALID_TOOL_NAME_RE.test(tool.name) || Array.from(tool.name).length > 128) throw createInvalidStateError("Tool \"name\" must be 1–128 characters and contain only ASCII alphanumeric, underscore, hyphen, or period");
|
|
228
|
+
if (typeof tool.description !== "string" || tool.description.length === 0) throw createInvalidStateError("Tool \"description\" must be a non-empty string");
|
|
337
229
|
if (typeof tool.execute !== "function") throw new TypeError("Tool \"execute\" must be a function");
|
|
338
230
|
if (existing.has(tool.name)) throw new Error(`Tool already registered: ${tool.name}`);
|
|
339
231
|
const normalizedInputSchema = normalizeInputSchema(tool.inputSchema);
|
|
@@ -352,13 +244,6 @@ function normalizeToolDescriptor(tool, existing) {
|
|
|
352
244
|
[STANDARD_VALIDATOR_SYMBOL]: normalizedInputSchema.standardValidator
|
|
353
245
|
};
|
|
354
246
|
}
|
|
355
|
-
function validateArgsWithSchema(args, schema) {
|
|
356
|
-
const result = new Validator(schema, "2020-12", true).validate(args);
|
|
357
|
-
if (result.valid) return null;
|
|
358
|
-
const error = result.errors[result.errors.length - 1];
|
|
359
|
-
if (!error) return { message: "Input validation failed" };
|
|
360
|
-
return { message: error.error };
|
|
361
|
-
}
|
|
362
247
|
function formatStandardIssuePath(path) {
|
|
363
248
|
if (!path || path.length === 0) return null;
|
|
364
249
|
const segments = path.map((segment) => {
|
|
@@ -387,22 +272,15 @@ async function validateArgsWithStandardSchema(args, schema) {
|
|
|
387
272
|
async function validateArgsForTool(args, tool) {
|
|
388
273
|
return validateArgsWithStandardSchema(args, tool[STANDARD_VALIDATOR_SYMBOL]);
|
|
389
274
|
}
|
|
275
|
+
function validateOutputForTool(result, tool) {
|
|
276
|
+
if (!tool.outputSchema || result.isError) return null;
|
|
277
|
+
if (result.structuredContent === void 0) return `Output validation error: Tool ${tool.name} has an output schema but no structured content was provided`;
|
|
278
|
+
const issue = validateValueWithSchema(result.structuredContent, tool.outputSchema);
|
|
279
|
+
return issue ? `Output validation error: ${issue.message}` : null;
|
|
280
|
+
}
|
|
390
281
|
function isCallToolResult(value) {
|
|
391
282
|
return isPlainObject(value) && Array.isArray(value.content);
|
|
392
283
|
}
|
|
393
|
-
function isJsonPrimitive(value) {
|
|
394
|
-
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
395
|
-
}
|
|
396
|
-
function isJsonValue(value) {
|
|
397
|
-
if (isJsonPrimitive(value)) return Number.isFinite(value) || typeof value !== "number";
|
|
398
|
-
if (Array.isArray(value)) return value.every((entry) => isJsonValue(entry));
|
|
399
|
-
if (!isPlainObject(value)) return false;
|
|
400
|
-
return Object.values(value).every((entry) => isJsonValue(entry));
|
|
401
|
-
}
|
|
402
|
-
function toStructuredContent(value) {
|
|
403
|
-
if (!isPlainObject(value) || !isJsonValue(value)) return;
|
|
404
|
-
return value;
|
|
405
|
-
}
|
|
406
284
|
function serializeTextContent(value) {
|
|
407
285
|
if (typeof value === "string") return value;
|
|
408
286
|
try {
|
|
@@ -413,13 +291,13 @@ function serializeTextContent(value) {
|
|
|
413
291
|
}
|
|
414
292
|
function normalizeToolResponse(value) {
|
|
415
293
|
if (isCallToolResult(value)) return value;
|
|
416
|
-
const structuredContent =
|
|
294
|
+
const structuredContent = toJsonValue(value);
|
|
417
295
|
return {
|
|
418
296
|
content: [{
|
|
419
297
|
type: "text",
|
|
420
298
|
text: serializeTextContent(value)
|
|
421
299
|
}],
|
|
422
|
-
...structuredContent ? { structuredContent } : {},
|
|
300
|
+
...structuredContent !== void 0 ? { structuredContent } : {},
|
|
423
301
|
isError: false
|
|
424
302
|
};
|
|
425
303
|
}
|
|
@@ -462,6 +340,10 @@ function getNavigator() {
|
|
|
462
340
|
if (typeof navigator !== "undefined") return navigator;
|
|
463
341
|
return null;
|
|
464
342
|
}
|
|
343
|
+
function getDocument() {
|
|
344
|
+
if (typeof document !== "undefined") return document;
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
465
347
|
function defineNavigatorProperty(target, key, value) {
|
|
466
348
|
Object.defineProperty(target, key, {
|
|
467
349
|
configurable: true,
|
|
@@ -470,37 +352,90 @@ function defineNavigatorProperty(target, key, value) {
|
|
|
470
352
|
value
|
|
471
353
|
});
|
|
472
354
|
}
|
|
355
|
+
function defineDocumentModelContextProperty(target, value) {
|
|
356
|
+
Object.defineProperty(target, "modelContext", {
|
|
357
|
+
configurable: true,
|
|
358
|
+
enumerable: true,
|
|
359
|
+
writable: false,
|
|
360
|
+
value
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
let navigatorModelContextDeprecationWarned = false;
|
|
364
|
+
function defineDeprecatedNavigatorModelContext(target, value) {
|
|
365
|
+
Object.defineProperty(target, "modelContext", {
|
|
366
|
+
configurable: true,
|
|
367
|
+
enumerable: true,
|
|
368
|
+
get() {
|
|
369
|
+
if (!navigatorModelContextDeprecationWarned) {
|
|
370
|
+
navigatorModelContextDeprecationWarned = true;
|
|
371
|
+
console.warn("[WebMCPPolyfill] navigator.modelContext is deprecated. The May 27, 2026 WebMCP draft moved the modelContext getter from Navigator to Document — use document.modelContext instead. See https://github.com/webmachinelearning/webmcp/pull/184.");
|
|
372
|
+
}
|
|
373
|
+
return value;
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
}
|
|
473
377
|
function initializeWebMCPPolyfill(options) {
|
|
474
378
|
const nav = getNavigator();
|
|
475
|
-
|
|
476
|
-
if (
|
|
379
|
+
const doc = getDocument();
|
|
380
|
+
if (!nav && !doc) return;
|
|
381
|
+
const documentModelContext = doc?.modelContext;
|
|
382
|
+
if (Boolean(documentModelContext)) return;
|
|
383
|
+
const navigatorModelContext = nav?.modelContext;
|
|
384
|
+
const hasNavigatorModelContext = Boolean(navigatorModelContext);
|
|
477
385
|
if (installState.installed) cleanupWebMCPPolyfill();
|
|
386
|
+
if (doc && navigatorModelContext) {
|
|
387
|
+
installState.previousDocumentModelContextDescriptor = Object.getOwnPropertyDescriptor(doc, "modelContext");
|
|
388
|
+
defineDocumentModelContextProperty(doc, navigatorModelContext);
|
|
389
|
+
installState.installedDocumentModelContext = true;
|
|
390
|
+
installState.installed = true;
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (hasNavigatorModelContext) return;
|
|
478
394
|
const context = new StrictWebMCPContext();
|
|
479
395
|
const modelContext = context;
|
|
480
396
|
modelContext[POLYFILL_MARKER_PROPERTY] = true;
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (
|
|
397
|
+
if (doc) {
|
|
398
|
+
installState.previousDocumentModelContextDescriptor = Object.getOwnPropertyDescriptor(doc, "modelContext");
|
|
399
|
+
defineDocumentModelContextProperty(doc, modelContext);
|
|
400
|
+
installState.installedDocumentModelContext = true;
|
|
401
|
+
}
|
|
402
|
+
if (nav) {
|
|
403
|
+
installState.previousNavigatorModelContextDescriptor = Object.getOwnPropertyDescriptor(nav, "modelContext");
|
|
404
|
+
installState.previousNavigatorModelContextTestingDescriptor = Object.getOwnPropertyDescriptor(nav, "modelContextTesting");
|
|
405
|
+
navigatorModelContextDeprecationWarned = false;
|
|
406
|
+
defineDeprecatedNavigatorModelContext(nav, modelContext);
|
|
407
|
+
installState.installedNavigatorModelContext = true;
|
|
408
|
+
const installTestingShim = options?.installTestingShim ?? "if-missing";
|
|
409
|
+
const hasModelContextTesting = Boolean(nav.modelContextTesting);
|
|
410
|
+
if (installTestingShim === "always" || (installTestingShim === true || installTestingShim === "if-missing") && !hasModelContextTesting) {
|
|
411
|
+
defineNavigatorProperty(nav, "modelContextTesting", context.getTestingShim());
|
|
412
|
+
installState.installedNavigatorModelContextTesting = true;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
487
415
|
installState.installed = true;
|
|
488
416
|
}
|
|
489
417
|
function cleanupWebMCPPolyfill() {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const restore = (key, previousDescriptor) => {
|
|
418
|
+
if (!installState.installed) return;
|
|
419
|
+
const restore = (target, key, previousDescriptor) => {
|
|
493
420
|
if (previousDescriptor) {
|
|
494
|
-
Object.defineProperty(
|
|
421
|
+
Object.defineProperty(target, key, previousDescriptor);
|
|
495
422
|
return;
|
|
496
423
|
}
|
|
497
|
-
delete
|
|
424
|
+
delete target[key];
|
|
498
425
|
};
|
|
499
|
-
|
|
500
|
-
|
|
426
|
+
const nav = getNavigator();
|
|
427
|
+
const doc = getDocument();
|
|
428
|
+
if (doc && installState.installedDocumentModelContext) restore(doc, "modelContext", installState.previousDocumentModelContextDescriptor);
|
|
429
|
+
if (nav && installState.installedNavigatorModelContext) restore(nav, "modelContext", installState.previousNavigatorModelContextDescriptor);
|
|
430
|
+
if (nav && installState.installedNavigatorModelContextTesting) restore(nav, "modelContextTesting", installState.previousNavigatorModelContextTestingDescriptor);
|
|
501
431
|
installState.installed = false;
|
|
502
|
-
installState.
|
|
503
|
-
installState.
|
|
432
|
+
installState.previousDocumentModelContextDescriptor = void 0;
|
|
433
|
+
installState.previousNavigatorModelContextDescriptor = void 0;
|
|
434
|
+
installState.previousNavigatorModelContextTestingDescriptor = void 0;
|
|
435
|
+
installState.installedDocumentModelContext = false;
|
|
436
|
+
installState.installedNavigatorModelContext = false;
|
|
437
|
+
installState.installedNavigatorModelContextTesting = false;
|
|
438
|
+
navigatorModelContextDeprecationWarned = false;
|
|
504
439
|
}
|
|
505
440
|
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
506
441
|
const options = window.__webMCPPolyfillOptions;
|
|
@@ -512,5 +447,5 @@ if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
|
512
447
|
}
|
|
513
448
|
|
|
514
449
|
//#endregion
|
|
515
|
-
export { cleanupWebMCPPolyfill, initializeWebMCPPolyfill, initializeWebMCPPolyfill as initializeWebModelContextPolyfill, isPlainObject,
|
|
450
|
+
export { cleanupWebMCPPolyfill, initializeWebMCPPolyfill, initializeWebMCPPolyfill as initializeWebModelContextPolyfill, isPlainObject, normalizeInputSchema, toJsonValue, validateValueWithSchema };
|
|
516
451
|
//# sourceMappingURL=index.js.map
|