@mcp-b/webmcp-polyfill 0.0.0-beta-20260216200013
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 +69 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +354 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -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,69 @@
|
|
|
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
|
+
installTestingShim: 'if-missing',
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `installTestingShim`:
|
|
38
|
+
- `true` or `'if-missing'` (default): install parity helpers only when `navigator.modelContextTesting` is missing.
|
|
39
|
+
- `'always'`: replace any existing `navigator.modelContextTesting`.
|
|
40
|
+
- `false`: do not install `navigator.modelContextTesting`.
|
|
41
|
+
|
|
42
|
+
## Interop with `@mcp-b/global`
|
|
43
|
+
|
|
44
|
+
- Default behavior is non-destructive: if `navigator.modelContext` already exists, this package does nothing.
|
|
45
|
+
- 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).
|
|
46
|
+
- Repeated injection of `@mcp-b/global` is idempotent (first initialization wins).
|
|
47
|
+
|
|
48
|
+
## Migration Notes
|
|
49
|
+
|
|
50
|
+
- `forceOverride` has been removed from `initializeWebMCPPolyfill` options.
|
|
51
|
+
- Existing callers passing `forceOverride` should remove that field.
|
|
52
|
+
|
|
53
|
+
## Testing Shim
|
|
54
|
+
|
|
55
|
+
When `installTestingShim` is enabled, this package can install a minimal
|
|
56
|
+
`navigator.modelContextTesting` surface for parity-style tests:
|
|
57
|
+
|
|
58
|
+
- `listTools()`
|
|
59
|
+
- `executeTool(toolName, inputArgsJson, options?)`
|
|
60
|
+
- `registerToolsChangedCallback(callback)`
|
|
61
|
+
- `getCrossDocumentScriptToolResult()`
|
|
62
|
+
|
|
63
|
+
## Cleanup
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { cleanupWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';
|
|
67
|
+
|
|
68
|
+
cleanupWebMCPPolyfill();
|
|
69
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { InputSchema } from "@mcp-b/webmcp-types";
|
|
2
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
type StandardInputValidatorSchema = StandardSchemaV1<Record<string, unknown>, Record<string, unknown>>;
|
|
6
|
+
interface StandardJSONSchemaV1<Input = unknown, Output = Input> {
|
|
7
|
+
readonly '~standard': {
|
|
8
|
+
readonly version: 1;
|
|
9
|
+
readonly vendor: string;
|
|
10
|
+
readonly types?: {
|
|
11
|
+
readonly input: Input;
|
|
12
|
+
readonly output: Output;
|
|
13
|
+
} | undefined;
|
|
14
|
+
readonly jsonSchema: {
|
|
15
|
+
readonly input: (options: {
|
|
16
|
+
readonly target: 'draft-2020-12' | 'draft-07' | 'openapi-3.0' | ({} & string);
|
|
17
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
18
|
+
}) => Record<string, unknown>;
|
|
19
|
+
readonly output: (options: {
|
|
20
|
+
readonly target: 'draft-2020-12' | 'draft-07' | 'openapi-3.0' | ({} & string);
|
|
21
|
+
readonly libraryOptions?: Record<string, unknown> | undefined;
|
|
22
|
+
}) => Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
type StandardInputJsonSchema = StandardJSONSchemaV1<Record<string, unknown>, Record<string, unknown>>;
|
|
27
|
+
type ToolInputSchema = InputSchema | StandardInputValidatorSchema | StandardInputJsonSchema;
|
|
28
|
+
type ToolOutputSchema = InputSchema | StandardInputJsonSchema;
|
|
29
|
+
type StandardValidationResult = Awaited<ReturnType<StandardInputValidatorSchema['~standard']['validate']>>;
|
|
30
|
+
type StandardValidationIssue = NonNullable<StandardValidationResult['issues']>[number];
|
|
31
|
+
interface WebMCPPolyfillInitOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Controls installation of navigator.modelContextTesting when this polyfill provides modelContext.
|
|
34
|
+
* - true or 'if-missing' (default): install only when modelContextTesting is missing.
|
|
35
|
+
* - 'always': install even when modelContextTesting already exists.
|
|
36
|
+
* - false: do not install.
|
|
37
|
+
* @default 'if-missing'
|
|
38
|
+
*/
|
|
39
|
+
installTestingShim?: boolean | 'always' | 'if-missing';
|
|
40
|
+
/**
|
|
41
|
+
* Deprecated no-op kept for backward compatibility with previous wrappers.
|
|
42
|
+
*/
|
|
43
|
+
disableIframeTransportByDefault?: boolean;
|
|
44
|
+
}
|
|
45
|
+
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
46
|
+
declare function validateArgsWithSchema(args: Record<string, unknown>, schema: InputSchema): StandardValidationIssue | null;
|
|
47
|
+
declare function initializeWebMCPPolyfill(options?: WebMCPPolyfillInitOptions): void;
|
|
48
|
+
declare function cleanupWebMCPPolyfill(): void;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { StandardInputJsonSchema, StandardInputValidatorSchema, StandardJSONSchemaV1, ToolInputSchema, ToolOutputSchema, WebMCPPolyfillInitOptions, cleanupWebMCPPolyfill, initializeWebMCPPolyfill, initializeWebMCPPolyfill as initializeWebModelContextPolyfill, isPlainObject, validateArgsWithSchema };
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;KAwBY,4BAAA,GAA+B,iBACzC,yBACA;UAEe,+CAA+C;EAJpD,SAAA,WAAA,EAAA;IACV,SAAA,OAAA,EAAA,CAAA;IACA,SAAA,MAAA,EAAA,MAAA;IAFyC,SAAA,KAAA,CAAA,EAAA;MAAgB,SAAA,KAAA,EAQpB,KARoB;MAI1C,SAAA,MAAoB,EAI0B,MAJ1B;IAA2B,CAAA,GAAA,SAAA;IAIzB,SAAA,UAAA,EAAA;MAAwB,SAAA,KAAA,EAAA,CAAA,OAAA,EAAA;QAI7B,SAAA,MAAA,EAAA,eAAA,GAAA,UAAA,GAAA,aAAA,GAAA,CAAA,CAAA,CAAA,GAAA,MAAA,CAAA;QACtB,SAAA,cAAA,CAAA,EADsB,MACtB,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,SAAA;MAGsB,CAAA,EAAA,GAHtB,MAGsB,CAAA,MAAA,EAAA,OAAA,CAAA;MACtB,SAAA,MAAA,EAAA,CAAA,OAAA,EAAA;QAAM,SAAA,MAAA,EAAA,eAAA,GAAA,UAAA,GAAA,aAAA,GAAA,CAAA,CAAA,CAAA,GAAA,MAAA,CAAA;QAIN,SAAA,cAAuB,CAAA,EALD,MAKC,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,SAAA;MACjC,CAAA,EAAA,GALU,MAKV,CAAA,MAAA,EAAA,OAAA,CAAA;IACA,CAAA;EAFoC,CAAA;;AAI1B,KAJA,uBAAA,GAA0B,oBAIX,CAHzB,MAGyB,CAAA,MAAA,EAAA,OAAA,CAAA,EAFzB,MAEyB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;AAAG,KAAlB,eAAA,GAAkB,WAAA,GAAc,4BAAd,GAA6C,uBAA7C;AAAc,KAChC,gBAAA,GAAmB,WADa,GACC,uBADD;KAGvC,wBAAA,GAA2B,OAH2C,CAIzE,UAJyE,CAI9D,4BAJ8D,CAAA,WAAA,CAAA,CAAA,UAAA,CAAA,CAAA,CAAA;KAMtE,uBAAA,GAA0B,WANmE,CAMvD,wBANuD,CAAA,QAAA,CAAA,CAAA,CAAA,MAAA,CAAA;AACtF,UAkCK,yBAAA,CAlCc;EAE1B;;;;;AAAkC;AAgCvC;EA8KgB,kBAAa,CAAA,EAAA,OAA2B,GAAA,QAAM,GAAA,YAAA;EAuO9C;;;EAGb,+BAAA,CAAA,EAAA,OAAA;;AA+Ja,iBAzYA,aAAA,CAyYwB,KAAW,EAAA,OAAA,CAAA,EAAA,KAAA,IAzYK,MAyYoB,CAAA,MAAA,EAAA,OAAA,CAAA;AAiD5D,iBAnNA,sBAAA,CAmNqB,IAAA,EAlN7B,MAkN6B,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,MAAA,EAjN3B,WAiN2B,CAAA,EAhNlC,uBAgNkC,GAAA,IAAA;iBAjDrB,wBAAA,WAAmC;iBAiDnC,qBAAA,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { Validator } from "@cfworker/json-schema";
|
|
2
|
+
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
const FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE = "Failed to parse input arguments";
|
|
5
|
+
const TOOL_INVOCATION_FAILED_MESSAGE = "Tool was executed but the invocation failed. For example, the script function threw an error";
|
|
6
|
+
const TOOL_CANCELLED_MESSAGE = "Tool was cancelled";
|
|
7
|
+
const DEFAULT_INPUT_SCHEMA = {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {}
|
|
10
|
+
};
|
|
11
|
+
const STANDARD_JSON_SCHEMA_TARGETS = ["draft-2020-12", "draft-07"];
|
|
12
|
+
const POLYFILL_MARKER_PROPERTY = "__isWebMCPPolyfill";
|
|
13
|
+
const STANDARD_VALIDATOR_SYMBOL = Symbol("standardValidator");
|
|
14
|
+
const installState = {
|
|
15
|
+
installed: false,
|
|
16
|
+
previousModelContextDescriptor: void 0,
|
|
17
|
+
previousModelContextTestingDescriptor: void 0
|
|
18
|
+
};
|
|
19
|
+
var StrictWebMCPContext = class {
|
|
20
|
+
tools = /* @__PURE__ */ new Map();
|
|
21
|
+
toolsChangedCallback = null;
|
|
22
|
+
provideContext(options = {}) {
|
|
23
|
+
const nextTools = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const tool of options.tools ?? []) {
|
|
25
|
+
const normalized = normalizeToolDescriptor(tool, nextTools);
|
|
26
|
+
nextTools.set(normalized.name, normalized);
|
|
27
|
+
}
|
|
28
|
+
this.tools = nextTools;
|
|
29
|
+
this.notifyToolsChanged();
|
|
30
|
+
}
|
|
31
|
+
clearContext() {
|
|
32
|
+
this.tools.clear();
|
|
33
|
+
this.notifyToolsChanged();
|
|
34
|
+
}
|
|
35
|
+
registerTool(tool) {
|
|
36
|
+
const normalized = normalizeToolDescriptor(tool, this.tools);
|
|
37
|
+
this.tools.set(normalized.name, normalized);
|
|
38
|
+
this.notifyToolsChanged();
|
|
39
|
+
}
|
|
40
|
+
unregisterTool(name) {
|
|
41
|
+
if (this.tools.delete(name)) this.notifyToolsChanged();
|
|
42
|
+
}
|
|
43
|
+
getTestingShim() {
|
|
44
|
+
return {
|
|
45
|
+
listTools: () => {
|
|
46
|
+
return [...this.tools.values()].map((tool) => {
|
|
47
|
+
const output = {
|
|
48
|
+
name: tool.name,
|
|
49
|
+
description: tool.description
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
output.inputSchema = JSON.stringify(tool.inputSchema);
|
|
53
|
+
} catch {}
|
|
54
|
+
return output;
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
executeTool: (toolName, inputArgsJson, options) => this.executeToolForTesting(toolName, inputArgsJson, options),
|
|
58
|
+
registerToolsChangedCallback: (callback) => {
|
|
59
|
+
if (typeof callback !== "function") throw new TypeError("Failed to execute 'registerToolsChangedCallback' on 'ModelContextTesting': parameter 1 is not of type 'Function'.");
|
|
60
|
+
this.toolsChangedCallback = callback;
|
|
61
|
+
},
|
|
62
|
+
getCrossDocumentScriptToolResult: async () => "[]"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async executeToolForTesting(toolName, inputArgsJson, options) {
|
|
66
|
+
if (options?.signal?.aborted) throw createUnknownError(TOOL_CANCELLED_MESSAGE);
|
|
67
|
+
const tool = this.tools.get(toolName);
|
|
68
|
+
if (!tool) throw createUnknownError(`Tool not found: ${toolName}`);
|
|
69
|
+
const args = parseInputArgsJson(inputArgsJson);
|
|
70
|
+
const validationError = await validateArgsForTool(args, tool);
|
|
71
|
+
if (validationError) throw createUnknownError(validationError);
|
|
72
|
+
let contextActive = true;
|
|
73
|
+
const client = { requestUserInteraction: async (callback) => {
|
|
74
|
+
if (!contextActive) throw new Error(`ModelContextClient for tool "${toolName}" is no longer active after execute() resolved`);
|
|
75
|
+
if (typeof callback !== "function") throw new TypeError("requestUserInteraction(callback) requires a function callback");
|
|
76
|
+
return callback();
|
|
77
|
+
} };
|
|
78
|
+
try {
|
|
79
|
+
const execution = tool.execute(args, client);
|
|
80
|
+
return toSerializedTestingResult(await withAbortSignal(Promise.resolve(execution), options?.signal));
|
|
81
|
+
} catch {
|
|
82
|
+
throw createUnknownError(TOOL_INVOCATION_FAILED_MESSAGE);
|
|
83
|
+
} finally {
|
|
84
|
+
contextActive = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
notifyToolsChanged() {
|
|
88
|
+
if (!this.toolsChangedCallback) return;
|
|
89
|
+
queueMicrotask(() => {
|
|
90
|
+
try {
|
|
91
|
+
this.toolsChangedCallback?.();
|
|
92
|
+
} catch {}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
function createUnknownError(message) {
|
|
97
|
+
try {
|
|
98
|
+
return new DOMException(message, "UnknownError");
|
|
99
|
+
} catch {
|
|
100
|
+
const error = new Error(message);
|
|
101
|
+
error.name = "UnknownError";
|
|
102
|
+
return error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function parseInputArgsJson(inputArgsJson) {
|
|
106
|
+
let parsed;
|
|
107
|
+
try {
|
|
108
|
+
parsed = JSON.parse(inputArgsJson);
|
|
109
|
+
} catch {
|
|
110
|
+
throw createUnknownError(FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE);
|
|
111
|
+
}
|
|
112
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw createUnknownError(FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE);
|
|
113
|
+
return parsed;
|
|
114
|
+
}
|
|
115
|
+
function isPlainObject(value) {
|
|
116
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
117
|
+
}
|
|
118
|
+
function getStandardProps(value) {
|
|
119
|
+
if (!isPlainObject(value)) return null;
|
|
120
|
+
const standard = value["~standard"];
|
|
121
|
+
if (!isPlainObject(standard)) return null;
|
|
122
|
+
return standard;
|
|
123
|
+
}
|
|
124
|
+
function isStandardInputValidatorSchema(value) {
|
|
125
|
+
const standard = getStandardProps(value);
|
|
126
|
+
return Boolean(standard && standard.version === 1 && typeof standard.validate === "function");
|
|
127
|
+
}
|
|
128
|
+
function isStandardInputJsonSchema(value) {
|
|
129
|
+
const standard = getStandardProps(value);
|
|
130
|
+
if (!standard || standard.version !== 1 || !isPlainObject(standard.jsonSchema)) return false;
|
|
131
|
+
return typeof standard.jsonSchema.input === "function";
|
|
132
|
+
}
|
|
133
|
+
function createStandardValidatorFromJsonSchema(schema) {
|
|
134
|
+
return { "~standard": {
|
|
135
|
+
version: 1,
|
|
136
|
+
vendor: "@mcp-b/webmcp-polyfill-json-schema",
|
|
137
|
+
validate(value) {
|
|
138
|
+
if (!isPlainObject(value)) return { issues: [{ message: "expected object arguments" }] };
|
|
139
|
+
const issue = validateArgsWithSchema(value, schema);
|
|
140
|
+
if (issue) return { issues: [issue] };
|
|
141
|
+
return { value };
|
|
142
|
+
}
|
|
143
|
+
} };
|
|
144
|
+
}
|
|
145
|
+
function convertStandardInputSchema(schema) {
|
|
146
|
+
for (const target of STANDARD_JSON_SCHEMA_TARGETS) try {
|
|
147
|
+
const converted = schema["~standard"].jsonSchema.input({ target });
|
|
148
|
+
validateInputSchema(converted);
|
|
149
|
+
return converted;
|
|
150
|
+
} catch {}
|
|
151
|
+
throw new Error("Failed to convert Standard JSON Schema inputSchema to a JSON Schema object");
|
|
152
|
+
}
|
|
153
|
+
function normalizeInputSchema(inputSchema) {
|
|
154
|
+
if (inputSchema === void 0) {
|
|
155
|
+
const normalized = DEFAULT_INPUT_SCHEMA;
|
|
156
|
+
return {
|
|
157
|
+
inputSchema: normalized,
|
|
158
|
+
standardValidator: createStandardValidatorFromJsonSchema(normalized)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (isStandardInputJsonSchema(inputSchema)) {
|
|
162
|
+
const converted = convertStandardInputSchema(inputSchema);
|
|
163
|
+
return {
|
|
164
|
+
inputSchema: converted,
|
|
165
|
+
standardValidator: createStandardValidatorFromJsonSchema(converted)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
if (isStandardInputValidatorSchema(inputSchema)) return {
|
|
169
|
+
inputSchema: DEFAULT_INPUT_SCHEMA,
|
|
170
|
+
standardValidator: inputSchema
|
|
171
|
+
};
|
|
172
|
+
validateInputSchema(inputSchema);
|
|
173
|
+
return {
|
|
174
|
+
inputSchema,
|
|
175
|
+
standardValidator: createStandardValidatorFromJsonSchema(inputSchema)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function validateInputSchema(schema) {
|
|
179
|
+
if (!isPlainObject(schema)) throw new Error("inputSchema must be a JSON Schema object");
|
|
180
|
+
validateJsonSchemaNode(schema, "$");
|
|
181
|
+
}
|
|
182
|
+
function validateJsonSchemaNode(node, path) {
|
|
183
|
+
const typeValue = node.type;
|
|
184
|
+
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[]`);
|
|
185
|
+
const requiredValue = node.required;
|
|
186
|
+
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`);
|
|
187
|
+
const propertiesValue = node.properties;
|
|
188
|
+
if (propertiesValue !== void 0) {
|
|
189
|
+
if (!isPlainObject(propertiesValue)) throw new Error(`Invalid JSON Schema at ${path}: "properties" must be an object`);
|
|
190
|
+
for (const [key, value] of Object.entries(propertiesValue)) {
|
|
191
|
+
if (!isPlainObject(value)) throw new Error(`Invalid JSON Schema at ${path}.properties.${key}: expected object schema`);
|
|
192
|
+
validateJsonSchemaNode(value, `${path}.properties.${key}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const itemsValue = node.items;
|
|
196
|
+
if (itemsValue !== void 0) if (Array.isArray(itemsValue)) for (const [index, value] of itemsValue.entries()) {
|
|
197
|
+
if (!isPlainObject(value)) throw new Error(`Invalid JSON Schema at ${path}.items[${index}]: expected object schema`);
|
|
198
|
+
validateJsonSchemaNode(value, `${path}.items[${index}]`);
|
|
199
|
+
}
|
|
200
|
+
else if (isPlainObject(itemsValue)) validateJsonSchemaNode(itemsValue, `${path}.items`);
|
|
201
|
+
else throw new Error(`Invalid JSON Schema at ${path}: "items" must be an object or object[]`);
|
|
202
|
+
for (const keyword of [
|
|
203
|
+
"allOf",
|
|
204
|
+
"anyOf",
|
|
205
|
+
"oneOf"
|
|
206
|
+
]) {
|
|
207
|
+
const value = node[keyword];
|
|
208
|
+
if (value === void 0) continue;
|
|
209
|
+
if (!Array.isArray(value)) throw new Error(`Invalid JSON Schema at ${path}: "${keyword}" must be an array`);
|
|
210
|
+
for (const [index, entry] of value.entries()) {
|
|
211
|
+
if (!isPlainObject(entry)) throw new Error(`Invalid JSON Schema at ${path}.${keyword}[${index}]: expected object schema`);
|
|
212
|
+
validateJsonSchemaNode(entry, `${path}.${keyword}[${index}]`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const notValue = node.not;
|
|
216
|
+
if (notValue !== void 0) {
|
|
217
|
+
if (!isPlainObject(notValue)) throw new Error(`Invalid JSON Schema at ${path}: "not" must be an object schema`);
|
|
218
|
+
validateJsonSchemaNode(notValue, `${path}.not`);
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
JSON.stringify(node);
|
|
222
|
+
} catch {
|
|
223
|
+
throw new Error(`Invalid JSON Schema at ${path}: schema must be JSON-serializable`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function normalizeToolDescriptor(tool, existing) {
|
|
227
|
+
if (!tool || typeof tool !== "object") throw new TypeError("registerTool(tool) requires a tool object");
|
|
228
|
+
if (typeof tool.name !== "string" || tool.name.length === 0) throw new TypeError("Tool \"name\" must be a non-empty string");
|
|
229
|
+
if (typeof tool.description !== "string" || tool.description.length === 0) throw new TypeError("Tool \"description\" must be a non-empty string");
|
|
230
|
+
if (typeof tool.execute !== "function") throw new TypeError("Tool \"execute\" must be a function");
|
|
231
|
+
if (existing.has(tool.name)) throw new Error(`Tool already registered: ${tool.name}`);
|
|
232
|
+
const normalizedInputSchema = normalizeInputSchema(tool.inputSchema);
|
|
233
|
+
return {
|
|
234
|
+
...tool,
|
|
235
|
+
inputSchema: normalizedInputSchema.inputSchema,
|
|
236
|
+
[STANDARD_VALIDATOR_SYMBOL]: normalizedInputSchema.standardValidator
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function validateArgsWithSchema(args, schema) {
|
|
240
|
+
const result = new Validator(schema, "2020-12", true).validate(args);
|
|
241
|
+
if (result.valid) return null;
|
|
242
|
+
const error = result.errors[result.errors.length - 1];
|
|
243
|
+
if (!error) return { message: "Input validation failed" };
|
|
244
|
+
return { message: error.error };
|
|
245
|
+
}
|
|
246
|
+
function formatStandardIssuePath(path) {
|
|
247
|
+
if (!path || path.length === 0) return null;
|
|
248
|
+
const segments = path.map((segment) => {
|
|
249
|
+
if (isPlainObject(segment) && "key" in segment) return segment.key;
|
|
250
|
+
return segment;
|
|
251
|
+
}).map((segment) => String(segment)).filter((segment) => segment.length > 0);
|
|
252
|
+
if (segments.length === 0) return null;
|
|
253
|
+
return segments.join(".");
|
|
254
|
+
}
|
|
255
|
+
async function validateArgsWithStandardSchema(args, schema) {
|
|
256
|
+
let result;
|
|
257
|
+
try {
|
|
258
|
+
result = await Promise.resolve(schema["~standard"].validate(args));
|
|
259
|
+
} catch {
|
|
260
|
+
return "Input validation error: schema validation failed";
|
|
261
|
+
}
|
|
262
|
+
if (!result.issues || result.issues.length === 0) return null;
|
|
263
|
+
const firstIssue = result.issues[0];
|
|
264
|
+
if (!firstIssue) return "Input validation error";
|
|
265
|
+
const path = formatStandardIssuePath(firstIssue?.path);
|
|
266
|
+
if (path) return `Input validation error: ${firstIssue.message} at ${path}`;
|
|
267
|
+
return `Input validation error: ${firstIssue.message}`;
|
|
268
|
+
}
|
|
269
|
+
async function validateArgsForTool(args, tool) {
|
|
270
|
+
return validateArgsWithStandardSchema(args, tool[STANDARD_VALIDATOR_SYMBOL]);
|
|
271
|
+
}
|
|
272
|
+
function getFirstTextBlock(result) {
|
|
273
|
+
for (const block of result.content ?? []) if (block.type === "text" && "text" in block && typeof block.text === "string") return block.text;
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
function toSerializedTestingResult(result) {
|
|
277
|
+
if (result.isError) throw createUnknownError(getFirstTextBlock(result)?.replace(/^Error:\s*/i, "").trim() || TOOL_INVOCATION_FAILED_MESSAGE);
|
|
278
|
+
const metadata = result.metadata;
|
|
279
|
+
if (metadata && typeof metadata === "object" && metadata.willNavigate) return null;
|
|
280
|
+
try {
|
|
281
|
+
return JSON.stringify(result);
|
|
282
|
+
} catch {
|
|
283
|
+
throw createUnknownError(TOOL_INVOCATION_FAILED_MESSAGE);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function withAbortSignal(operation, signal) {
|
|
287
|
+
if (!signal) return operation;
|
|
288
|
+
if (signal.aborted) return Promise.reject(createUnknownError(TOOL_CANCELLED_MESSAGE));
|
|
289
|
+
return new Promise((resolve, reject) => {
|
|
290
|
+
const onAbort = () => {
|
|
291
|
+
cleanup();
|
|
292
|
+
reject(createUnknownError(TOOL_CANCELLED_MESSAGE));
|
|
293
|
+
};
|
|
294
|
+
const cleanup = () => {
|
|
295
|
+
signal.removeEventListener("abort", onAbort);
|
|
296
|
+
};
|
|
297
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
298
|
+
operation.then((value) => {
|
|
299
|
+
cleanup();
|
|
300
|
+
resolve(value);
|
|
301
|
+
}, (error) => {
|
|
302
|
+
cleanup();
|
|
303
|
+
reject(error);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
function getNavigator() {
|
|
308
|
+
if (typeof navigator !== "undefined") return navigator;
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
function defineNavigatorProperty(target, key, value) {
|
|
312
|
+
Object.defineProperty(target, key, {
|
|
313
|
+
configurable: true,
|
|
314
|
+
enumerable: true,
|
|
315
|
+
writable: false,
|
|
316
|
+
value
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
function initializeWebMCPPolyfill(options) {
|
|
320
|
+
const nav = getNavigator();
|
|
321
|
+
if (!nav) return;
|
|
322
|
+
if (Boolean(nav.modelContext)) return;
|
|
323
|
+
if (installState.installed) cleanupWebMCPPolyfill();
|
|
324
|
+
const context = new StrictWebMCPContext();
|
|
325
|
+
const modelContext = context;
|
|
326
|
+
modelContext[POLYFILL_MARKER_PROPERTY] = true;
|
|
327
|
+
installState.previousModelContextDescriptor = Object.getOwnPropertyDescriptor(nav, "modelContext");
|
|
328
|
+
installState.previousModelContextTestingDescriptor = Object.getOwnPropertyDescriptor(nav, "modelContextTesting");
|
|
329
|
+
defineNavigatorProperty(nav, "modelContext", modelContext);
|
|
330
|
+
const installTestingShim = options?.installTestingShim ?? "if-missing";
|
|
331
|
+
const hasModelContextTesting = Boolean(nav.modelContextTesting);
|
|
332
|
+
if (installTestingShim === "always" || (installTestingShim === true || installTestingShim === "if-missing") && !hasModelContextTesting) defineNavigatorProperty(nav, "modelContextTesting", context.getTestingShim());
|
|
333
|
+
installState.installed = true;
|
|
334
|
+
}
|
|
335
|
+
function cleanupWebMCPPolyfill() {
|
|
336
|
+
const nav = getNavigator();
|
|
337
|
+
if (!nav || !installState.installed) return;
|
|
338
|
+
const restore = (key, previousDescriptor) => {
|
|
339
|
+
if (previousDescriptor) {
|
|
340
|
+
Object.defineProperty(nav, key, previousDescriptor);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
delete nav[key];
|
|
344
|
+
};
|
|
345
|
+
restore("modelContext", installState.previousModelContextDescriptor);
|
|
346
|
+
restore("modelContextTesting", installState.previousModelContextTestingDescriptor);
|
|
347
|
+
installState.installed = false;
|
|
348
|
+
installState.previousModelContextDescriptor = void 0;
|
|
349
|
+
installState.previousModelContextTestingDescriptor = void 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
//#endregion
|
|
353
|
+
export { cleanupWebMCPPolyfill, initializeWebMCPPolyfill, initializeWebMCPPolyfill as initializeWebModelContextPolyfill, isPlainObject, validateArgsWithSchema };
|
|
354
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["DEFAULT_INPUT_SCHEMA: InputSchema","installState: InstallState","output: ModelContextTestingToolInfo","client: ModelContextClient","parsed: unknown","result: StandardValidationResult"],"sources":["../src/index.ts"],"sourcesContent":["import { type Schema, Validator } from '@cfworker/json-schema';\nimport type {\n InputSchema,\n ModelContext,\n ModelContextClient,\n ModelContextOptions,\n ModelContextTesting,\n ModelContextTestingExecuteToolOptions,\n ModelContextTestingToolInfo,\n ToolDescriptor,\n ToolResponse,\n} from '@mcp-b/webmcp-types';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\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: {} };\nconst STANDARD_JSON_SCHEMA_TARGETS = ['draft-2020-12', 'draft-07'] as const;\n\nconst POLYFILL_MARKER_PROPERTY = '__isWebMCPPolyfill' as const;\nconst STANDARD_VALIDATOR_SYMBOL = Symbol('standardValidator');\n\nexport type StandardInputValidatorSchema = StandardSchemaV1<\n Record<string, unknown>,\n Record<string, unknown>\n>;\nexport interface StandardJSONSchemaV1<Input = unknown, Output = Input> {\n readonly '~standard': {\n readonly version: 1;\n readonly vendor: string;\n readonly types?: { readonly input: Input; readonly output: Output } | undefined;\n readonly jsonSchema: {\n readonly input: (options: {\n readonly target: 'draft-2020-12' | 'draft-07' | 'openapi-3.0' | ({} & string);\n readonly libraryOptions?: Record<string, unknown> | undefined;\n }) => Record<string, unknown>;\n readonly output: (options: {\n readonly target: 'draft-2020-12' | 'draft-07' | 'openapi-3.0' | ({} & string);\n readonly libraryOptions?: Record<string, unknown> | undefined;\n }) => Record<string, unknown>;\n };\n };\n}\nexport type StandardInputJsonSchema = StandardJSONSchemaV1<\n Record<string, unknown>,\n Record<string, unknown>\n>;\nexport type ToolInputSchema = InputSchema | StandardInputValidatorSchema | StandardInputJsonSchema;\nexport type ToolOutputSchema = InputSchema | StandardInputJsonSchema;\n\ntype StandardValidationResult = Awaited<\n ReturnType<StandardInputValidatorSchema['~standard']['validate']>\n>;\ntype StandardValidationIssue = NonNullable<StandardValidationResult['issues']>[number];\n\ninterface PolyfillModelContext extends ModelContext {\n [POLYFILL_MARKER_PROPERTY]: true;\n}\n\ninterface PolyfillToolDescriptor\n extends ToolDescriptor<Record<string, unknown>, ToolResponse, string> {\n inputSchema: InputSchema;\n [STANDARD_VALIDATOR_SYMBOL]: StandardInputValidatorSchema;\n}\n\ninterface NormalizedInputSchema {\n inputSchema: InputSchema;\n standardValidator: StandardInputValidatorSchema;\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 * Controls installation of navigator.modelContextTesting when this polyfill provides modelContext.\n * - true or 'if-missing' (default): install only when modelContextTesting is missing.\n * - 'always': install even when modelContextTesting already exists.\n * - false: do not install.\n * @default 'if-missing'\n */\n installTestingShim?: boolean | 'always' | 'if-missing';\n\n /**\n * Deprecated no-op kept for backward compatibility with previous wrappers.\n */\n disableIframeTransportByDefault?: boolean;\n}\n\nclass StrictWebMCPContext {\n private tools = new Map<string, PolyfillToolDescriptor>();\n private toolsChangedCallback: (() => void) | null = null;\n\n provideContext(options: ModelContextOptions = {}): void {\n const nextTools = new Map<string, PolyfillToolDescriptor>();\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: ModelContextTestingToolInfo = {\n name: tool.name,\n description: tool.description,\n };\n\n try {\n output.inputSchema = JSON.stringify(tool.inputSchema);\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 = await validateArgsForTool(args, tool);\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\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction getStandardProps(value: unknown): Record<string, unknown> | null {\n if (!isPlainObject(value)) {\n return null;\n }\n\n const standard = value['~standard'];\n if (!isPlainObject(standard)) {\n return null;\n }\n\n return standard;\n}\n\nfunction isStandardInputValidatorSchema(value: unknown): value is StandardInputValidatorSchema {\n const standard = getStandardProps(value);\n return Boolean(standard && standard.version === 1 && typeof standard.validate === 'function');\n}\n\nfunction isStandardInputJsonSchema(value: unknown): value is StandardInputJsonSchema {\n const standard = getStandardProps(value);\n if (!standard || standard.version !== 1 || !isPlainObject(standard.jsonSchema)) {\n return false;\n }\n\n return typeof standard.jsonSchema.input === 'function';\n}\n\nfunction createStandardValidatorFromJsonSchema(schema: InputSchema): StandardInputValidatorSchema {\n return {\n '~standard': {\n version: 1,\n vendor: '@mcp-b/webmcp-polyfill-json-schema',\n validate(value: unknown): StandardValidationResult {\n if (!isPlainObject(value)) {\n return {\n issues: [{ message: 'expected object arguments' }],\n };\n }\n\n const issue = validateArgsWithSchema(value, schema);\n if (issue) {\n return {\n issues: [issue],\n };\n }\n\n return {\n value,\n };\n },\n },\n };\n}\n\nfunction convertStandardInputSchema(schema: StandardInputJsonSchema): InputSchema {\n for (const target of STANDARD_JSON_SCHEMA_TARGETS) {\n try {\n const converted = schema['~standard'].jsonSchema.input({ target });\n validateInputSchema(converted);\n return converted;\n } catch {\n // Try the next target.\n }\n }\n\n throw new Error('Failed to convert Standard JSON Schema inputSchema to a JSON Schema object');\n}\n\nfunction normalizeInputSchema(inputSchema: ToolInputSchema | undefined): NormalizedInputSchema {\n if (inputSchema === undefined) {\n const normalized = DEFAULT_INPUT_SCHEMA;\n return {\n inputSchema: normalized,\n standardValidator: createStandardValidatorFromJsonSchema(normalized),\n };\n }\n\n if (isStandardInputJsonSchema(inputSchema)) {\n // Prefer JSON conversion for parity across JSON and Standard Schema inputs.\n const converted = convertStandardInputSchema(inputSchema);\n return {\n inputSchema: converted,\n standardValidator: createStandardValidatorFromJsonSchema(converted),\n };\n }\n\n if (isStandardInputValidatorSchema(inputSchema)) {\n return {\n inputSchema: DEFAULT_INPUT_SCHEMA,\n standardValidator: inputSchema,\n };\n }\n\n validateInputSchema(inputSchema);\n return {\n inputSchema,\n standardValidator: createStandardValidatorFromJsonSchema(inputSchema),\n };\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, PolyfillToolDescriptor>\n): PolyfillToolDescriptor {\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 = normalizeInputSchema(tool.inputSchema);\n\n return {\n ...tool,\n inputSchema: normalizedInputSchema.inputSchema,\n [STANDARD_VALIDATOR_SYMBOL]: normalizedInputSchema.standardValidator,\n };\n}\n\nexport function validateArgsWithSchema(\n args: Record<string, unknown>,\n schema: InputSchema\n): StandardValidationIssue | null {\n const validator = new Validator(schema as Schema, '2020-12', true);\n const result = validator.validate(args);\n\n if (result.valid) {\n return null;\n }\n\n // Use the deepest (last) error for the most specific message.\n const error = result.errors[result.errors.length - 1];\n if (!error) {\n return { message: 'Input validation failed' };\n }\n\n return { message: error.error };\n}\n\nfunction formatStandardIssuePath(path: StandardValidationIssue['path']) {\n if (!path || path.length === 0) {\n return null;\n }\n\n const segments = path\n .map((segment) => {\n if (isPlainObject(segment) && 'key' in segment) {\n return segment.key;\n }\n return segment;\n })\n .map((segment) => String(segment))\n .filter((segment) => segment.length > 0);\n\n if (segments.length === 0) {\n return null;\n }\n\n return segments.join('.');\n}\n\nasync function validateArgsWithStandardSchema(\n args: Record<string, unknown>,\n schema: StandardInputValidatorSchema\n): Promise<string | null> {\n let result: StandardValidationResult;\n\n try {\n result = await Promise.resolve(schema['~standard'].validate(args));\n } catch {\n return 'Input validation error: schema validation failed';\n }\n\n if (!result.issues || result.issues.length === 0) {\n return null;\n }\n\n const firstIssue = result.issues[0];\n if (!firstIssue) {\n return 'Input validation error';\n }\n\n const path = formatStandardIssuePath(firstIssue?.path);\n if (path) {\n return `Input validation error: ${firstIssue.message} at ${path}`;\n }\n\n return `Input validation error: ${firstIssue.message}`;\n}\n\nasync function validateArgsForTool(\n args: Record<string, unknown>,\n tool: PolyfillToolDescriptor\n): Promise<string | null> {\n return validateArgsWithStandardSchema(args, tool[STANDARD_VALIDATOR_SYMBOL]);\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 hasModelContext = Boolean(nav.modelContext);\n\n if (hasModelContext) {\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 ?? 'if-missing';\n const hasModelContextTesting = Boolean(nav.modelContextTesting);\n const shouldInstallTestingShim =\n installTestingShim === 'always' ||\n ((installTestingShim === true || installTestingShim === 'if-missing') &&\n !hasModelContextTesting);\n\n if (shouldInstallTestingShim) {\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"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcp-b/webmcp-polyfill",
|
|
3
|
+
"version": "0.0.0-beta-20260216200013",
|
|
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
|
+
"@cfworker/json-schema": "^4.1.1",
|
|
40
|
+
"@standard-schema/spec": "^1.1.0",
|
|
41
|
+
"@mcp-b/webmcp-types": "0.0.0-beta-20260216200013"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@vitest/browser": "^4.0.18",
|
|
45
|
+
"@vitest/browser-playwright": "^4.0.18",
|
|
46
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
47
|
+
"playwright": "^1.58.0",
|
|
48
|
+
"tsdown": "^0.15.10",
|
|
49
|
+
"typescript": "^5.8.3",
|
|
50
|
+
"vitest": "^4.0.18"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public",
|
|
57
|
+
"registry": "https://registry.npmjs.org/"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "pnpm --filter @mcp-b/webmcp-types build && tsdown",
|
|
61
|
+
"check": "biome check --write .",
|
|
62
|
+
"clean": "rm -rf dist .turbo",
|
|
63
|
+
"format": "biome format --write .",
|
|
64
|
+
"lint": "biome lint --write .",
|
|
65
|
+
"publish:dry": "pnpm publish --access public --dry-run",
|
|
66
|
+
"publish:npm": "pnpm publish --access public",
|
|
67
|
+
"test": "vitest run",
|
|
68
|
+
"test:browser": "vitest run --config vitest.browser.config.ts --browser.headless",
|
|
69
|
+
"test:browser:ui": "vitest --config vitest.browser.config.ts --browser",
|
|
70
|
+
"typecheck": "pnpm --filter @mcp-b/webmcp-types build && tsc --noEmit && vitest run --typecheck --silent"
|
|
71
|
+
}
|
|
72
|
+
}
|