@webmcp-auto-ui/core 0.5.0 → 2.5.4
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 +39 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -1
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/multi-client.d.ts +7 -3
- package/dist/multi-client.d.ts.map +1 -1
- package/dist/multi-client.js +49 -4
- package/dist/multi-client.js.map +1 -1
- package/dist/utils.d.ts +27 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +136 -3
- package/dist/utils.js.map +1 -1
- package/dist/webmcp-helpers.d.ts +0 -16
- package/dist/webmcp-helpers.d.ts.map +1 -1
- package/dist/webmcp-helpers.js +5 -47
- package/dist/webmcp-helpers.js.map +1 -1
- package/dist/webmcp-server.d.ts +54 -0
- package/dist/webmcp-server.d.ts.map +1 -0
- package/dist/webmcp-server.js +425 -0
- package/dist/webmcp-server.js.map +1 -0
- package/package.json +1 -1
- package/src/client.d.ts +26 -0
- package/src/client.ts +3 -1
- package/src/events.d.ts +16 -0
- package/src/index.d.ts +13 -0
- package/src/index.ts +9 -7
- package/src/multi-client.d.ts +55 -0
- package/src/multi-client.ts +53 -4
- package/src/polyfill.d.ts +51 -0
- package/src/types.d.ts +331 -0
- package/src/utils.d.ts +81 -0
- package/src/utils.ts +163 -0
- package/src/validate.d.ts +13 -0
- package/src/webmcp-helpers.d.ts +3 -0
- package/src/webmcp-helpers.ts +6 -63
- package/src/webmcp-server.d.ts +53 -0
- package/src/webmcp-server.ts +538 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webmcp-helpers.js","sourceRoot":"","sources":["../src/webmcp-helpers.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wCAAwC;AACxC,
|
|
1
|
+
{"version":3,"file":"webmcp-helpers.js","sourceRoot":"","sources":["../src/webmcp-helpers.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wCAAwC;AACxC,8CAA8C;AAC9C,0CAA0C;AAC1C,EAAE;AACF,4EAA4E;AAC5E,wEAAwE;AACxE,kFAAkF;AAClF,8EAA8E;AAI9E,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface WebMcpServerOptions {
|
|
2
|
+
description: string;
|
|
3
|
+
}
|
|
4
|
+
export interface WebMcpToolDef {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
inputSchema: Record<string, unknown>;
|
|
8
|
+
execute: (params: Record<string, unknown>) => Promise<unknown>;
|
|
9
|
+
}
|
|
10
|
+
/** A vanilla renderer: receives a container + data, optionally returns a cleanup function. */
|
|
11
|
+
export type WidgetRenderer = ((container: HTMLElement, data: Record<string, unknown>) => void | (() => void)) | unknown;
|
|
12
|
+
export interface WidgetEntry {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
inputSchema: Record<string, unknown>;
|
|
16
|
+
recipe: string;
|
|
17
|
+
renderer: WidgetRenderer;
|
|
18
|
+
group?: string;
|
|
19
|
+
/** True when the renderer is a plain function (not a framework component). */
|
|
20
|
+
vanilla: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface WebMcpServer {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly description: string;
|
|
25
|
+
registerWidget(recipeMarkdown: string, renderer: WidgetRenderer): void;
|
|
26
|
+
addTool(tool: WebMcpToolDef): void;
|
|
27
|
+
layer(): {
|
|
28
|
+
protocol: 'webmcp';
|
|
29
|
+
serverName: string;
|
|
30
|
+
description: string;
|
|
31
|
+
tools: WebMcpToolDef[];
|
|
32
|
+
};
|
|
33
|
+
getWidget(name: string): WidgetEntry | undefined;
|
|
34
|
+
listWidgets(): WidgetEntry[];
|
|
35
|
+
}
|
|
36
|
+
export interface ParsedFrontmatter {
|
|
37
|
+
frontmatter: Record<string, unknown>;
|
|
38
|
+
body: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parse a markdown file with YAML frontmatter (--- delimited).
|
|
42
|
+
* Supports: scalars, nested objects (indentation), arrays (- item), inline values.
|
|
43
|
+
* No external YAML dependency.
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseFrontmatter(markdown: string): ParsedFrontmatter;
|
|
46
|
+
/**
|
|
47
|
+
* Mount a widget into a DOM container by searching registered servers.
|
|
48
|
+
* If the renderer is a function (vanilla renderer), it is called directly.
|
|
49
|
+
* Returns an optional cleanup function.
|
|
50
|
+
* Falls back to a text placeholder if no server provides the widget.
|
|
51
|
+
*/
|
|
52
|
+
export declare function mountWidget(container: HTMLElement, type: string, data: Record<string, unknown>, servers: WebMcpServer[]): (() => void) | void;
|
|
53
|
+
export declare function createWebMcpServer(name: string, options: WebMcpServerOptions): WebMcpServer;
|
|
54
|
+
//# sourceMappingURL=webmcp-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webmcp-server.d.ts","sourceRoot":"","sources":["../src/webmcp-server.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChE;AAED,8FAA8F;AAC9F,MAAM,MAAM,cAAc,GACtB,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAChF,OAAO,CAAC;AAEZ,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IACvE,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAEnC,KAAK,IAAI;QACP,QAAQ,EAAE,QAAQ,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,aAAa,EAAE,CAAC;KACxB,CAAC;IAEF,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IACjD,WAAW,IAAI,WAAW,EAAE,CAAC;CAC9B;AAMD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAgBpE;AAsMD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,WAAW,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,YAAY,EAAE,GACtB,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAQrB;AA6CD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,mBAAmB,GAC3B,YAAY,CAwLd"}
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @webmcp-auto-ui/core — WebMCP Server
|
|
3
|
+
// A WebMCP server exposes tools and widget recipes for local UI rendering.
|
|
4
|
+
// Symmetric to MCP (remote data) — WebMCP handles display/interaction.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
import { validateJsonSchema } from './validate.js';
|
|
7
|
+
/**
|
|
8
|
+
* Parse a markdown file with YAML frontmatter (--- delimited).
|
|
9
|
+
* Supports: scalars, nested objects (indentation), arrays (- item), inline values.
|
|
10
|
+
* No external YAML dependency.
|
|
11
|
+
*/
|
|
12
|
+
export function parseFrontmatter(markdown) {
|
|
13
|
+
const trimmed = markdown.trimStart();
|
|
14
|
+
if (!trimmed.startsWith('---\n') && !trimmed.startsWith('---\r\n')) {
|
|
15
|
+
return { frontmatter: {}, body: markdown };
|
|
16
|
+
}
|
|
17
|
+
const endIdx = trimmed.indexOf('\n---', 3);
|
|
18
|
+
if (endIdx === -1) {
|
|
19
|
+
return { frontmatter: {}, body: markdown };
|
|
20
|
+
}
|
|
21
|
+
const yamlBlock = trimmed.slice(4, endIdx); // skip opening "---\n"
|
|
22
|
+
const body = trimmed.slice(endIdx + 4).replace(/^\r?\n/, ''); // skip closing "---\n" or "---\r\n"
|
|
23
|
+
const frontmatter = parseYaml(yamlBlock);
|
|
24
|
+
return { frontmatter, body };
|
|
25
|
+
}
|
|
26
|
+
function tokenize(yaml) {
|
|
27
|
+
return yaml.split('\n').map(raw => {
|
|
28
|
+
const match = raw.match(/^(\s*)/);
|
|
29
|
+
const indent = match ? match[1].length : 0;
|
|
30
|
+
return { indent, raw, content: raw.trim() };
|
|
31
|
+
}).filter(l => l.content !== '' && !l.content.startsWith('#'));
|
|
32
|
+
}
|
|
33
|
+
function parseYaml(yaml) {
|
|
34
|
+
const lines = tokenize(yaml);
|
|
35
|
+
const [result] = parseObject(lines, 0, 0);
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse an object starting at `start` with minimum indentation `minIndent`.
|
|
40
|
+
* Returns [parsed object, next line index].
|
|
41
|
+
*/
|
|
42
|
+
function parseObject(lines, start, minIndent) {
|
|
43
|
+
const obj = {};
|
|
44
|
+
let i = start;
|
|
45
|
+
while (i < lines.length) {
|
|
46
|
+
const line = lines[i];
|
|
47
|
+
if (line.indent < minIndent)
|
|
48
|
+
break;
|
|
49
|
+
// key: value
|
|
50
|
+
const kvMatch = line.content.match(/^([^:]+?):\s*(.*)?$/);
|
|
51
|
+
if (!kvMatch) {
|
|
52
|
+
i++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const key = kvMatch[1].trim();
|
|
56
|
+
const valuePart = (kvMatch[2] ?? '').trim();
|
|
57
|
+
if (valuePart !== '') {
|
|
58
|
+
// Inline value
|
|
59
|
+
obj[key] = parseScalar(valuePart);
|
|
60
|
+
i++;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// Block value — look ahead to determine if array or nested object
|
|
64
|
+
if (i + 1 < lines.length && lines[i + 1].indent > line.indent) {
|
|
65
|
+
const childIndent = lines[i + 1].indent;
|
|
66
|
+
if (lines[i + 1].content.startsWith('- ')) {
|
|
67
|
+
const [arr, next] = parseArray(lines, i + 1, childIndent);
|
|
68
|
+
obj[key] = arr;
|
|
69
|
+
i = next;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const [nested, next] = parseObject(lines, i + 1, childIndent);
|
|
73
|
+
obj[key] = nested;
|
|
74
|
+
i = next;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
obj[key] = null;
|
|
79
|
+
i++;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return [obj, i];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Parse an array starting at `start` with items at `minIndent`.
|
|
87
|
+
*/
|
|
88
|
+
function parseArray(lines, start, minIndent) {
|
|
89
|
+
const arr = [];
|
|
90
|
+
let i = start;
|
|
91
|
+
while (i < lines.length) {
|
|
92
|
+
const line = lines[i];
|
|
93
|
+
if (line.indent < minIndent)
|
|
94
|
+
break;
|
|
95
|
+
if (!line.content.startsWith('- '))
|
|
96
|
+
break;
|
|
97
|
+
const itemContent = line.content.slice(2).trim();
|
|
98
|
+
// Check if this is a mapping item (- key: value on same line, possibly with children)
|
|
99
|
+
const kvMatch = itemContent.match(/^([^:]+?):\s*(.*)?$/);
|
|
100
|
+
if (kvMatch) {
|
|
101
|
+
// It's a mapping starting on the dash line
|
|
102
|
+
const firstKey = kvMatch[1].trim();
|
|
103
|
+
const firstVal = (kvMatch[2] ?? '').trim();
|
|
104
|
+
const itemObj = {};
|
|
105
|
+
itemObj[firstKey] = firstVal !== '' ? parseScalar(firstVal) : null;
|
|
106
|
+
// Collect remaining keys of this mapping (indented deeper than the dash)
|
|
107
|
+
i++;
|
|
108
|
+
const childIndent = line.indent + 2; // standard: items indented 2 past dash
|
|
109
|
+
while (i < lines.length && lines[i].indent >= childIndent && !lines[i].content.startsWith('- ')) {
|
|
110
|
+
const childKv = lines[i].content.match(/^([^:]+?):\s*(.*)?$/);
|
|
111
|
+
if (childKv) {
|
|
112
|
+
const ck = childKv[1].trim();
|
|
113
|
+
const cv = (childKv[2] ?? '').trim();
|
|
114
|
+
if (cv !== '') {
|
|
115
|
+
itemObj[ck] = parseScalar(cv);
|
|
116
|
+
}
|
|
117
|
+
else if (i + 1 < lines.length && lines[i + 1].indent > lines[i].indent) {
|
|
118
|
+
const nextIndent = lines[i + 1].indent;
|
|
119
|
+
if (lines[i + 1].content.startsWith('- ')) {
|
|
120
|
+
const [subArr, next] = parseArray(lines, i + 1, nextIndent);
|
|
121
|
+
itemObj[ck] = subArr;
|
|
122
|
+
i = next;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const [subObj, next] = parseObject(lines, i + 1, nextIndent);
|
|
127
|
+
itemObj[ck] = subObj;
|
|
128
|
+
i = next;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
itemObj[ck] = null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
i++;
|
|
137
|
+
}
|
|
138
|
+
arr.push(itemObj);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Simple scalar item
|
|
142
|
+
arr.push(parseScalar(itemContent));
|
|
143
|
+
i++;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return [arr, i];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Parse a scalar YAML value: numbers, booleans, null, inline objects/arrays, or strings.
|
|
150
|
+
*/
|
|
151
|
+
function parseScalar(value) {
|
|
152
|
+
if (value === 'true')
|
|
153
|
+
return true;
|
|
154
|
+
if (value === 'false')
|
|
155
|
+
return false;
|
|
156
|
+
if (value === 'null' || value === '~')
|
|
157
|
+
return null;
|
|
158
|
+
// Quoted string
|
|
159
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
160
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
161
|
+
return value.slice(1, -1);
|
|
162
|
+
}
|
|
163
|
+
// Inline JSON-style object { key: val, ... }
|
|
164
|
+
if (value.startsWith('{') && value.endsWith('}')) {
|
|
165
|
+
return parseInlineObject(value);
|
|
166
|
+
}
|
|
167
|
+
// Inline array [a, b, c]
|
|
168
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
169
|
+
const inner = value.slice(1, -1).trim();
|
|
170
|
+
if (inner === '')
|
|
171
|
+
return [];
|
|
172
|
+
return inner.split(',').map(s => parseScalar(s.trim()));
|
|
173
|
+
}
|
|
174
|
+
// Number
|
|
175
|
+
const num = Number(value);
|
|
176
|
+
if (!isNaN(num) && value !== '')
|
|
177
|
+
return num;
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Parse inline YAML object like { type: string, description: Some text }
|
|
182
|
+
*/
|
|
183
|
+
function parseInlineObject(value) {
|
|
184
|
+
const inner = value.slice(1, -1).trim();
|
|
185
|
+
const obj = {};
|
|
186
|
+
// Split on ", " but only at top level (no nested braces handling needed for our use case)
|
|
187
|
+
const parts = inner.split(/,\s*/);
|
|
188
|
+
for (const part of parts) {
|
|
189
|
+
const colonIdx = part.indexOf(':');
|
|
190
|
+
if (colonIdx === -1)
|
|
191
|
+
continue;
|
|
192
|
+
const k = part.slice(0, colonIdx).trim();
|
|
193
|
+
const v = part.slice(colonIdx + 1).trim();
|
|
194
|
+
obj[k] = parseScalar(v);
|
|
195
|
+
}
|
|
196
|
+
return obj;
|
|
197
|
+
}
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// Mount helper — framework-agnostic widget mounting
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
/**
|
|
202
|
+
* Mount a widget into a DOM container by searching registered servers.
|
|
203
|
+
* If the renderer is a function (vanilla renderer), it is called directly.
|
|
204
|
+
* Returns an optional cleanup function.
|
|
205
|
+
* Falls back to a text placeholder if no server provides the widget.
|
|
206
|
+
*/
|
|
207
|
+
export function mountWidget(container, type, data, servers) {
|
|
208
|
+
for (const server of servers) {
|
|
209
|
+
const widget = server.getWidget(type);
|
|
210
|
+
if (widget?.renderer && widget.vanilla) {
|
|
211
|
+
return widget.renderer(container, data);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
container.textContent = `[${type}]`;
|
|
215
|
+
}
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
// Factory
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
// Image URL sanitizer — strips hallucinated URLs from widget params
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
const VALID_URL_PREFIXES = ['http://', 'https://', 'data:', '/'];
|
|
223
|
+
const IMAGE_KEY_PATTERN = /^(src|image|avatar|photo|thumbnail|poster|icon|logo|cover|banner|background)$/i;
|
|
224
|
+
/** Recursively scan widget params and nullify image-like fields with invalid URLs. */
|
|
225
|
+
function sanitizeImageUrls(obj) {
|
|
226
|
+
if (Array.isArray(obj))
|
|
227
|
+
return obj.map(sanitizeImageUrls);
|
|
228
|
+
if (obj !== null && typeof obj === 'object') {
|
|
229
|
+
const result = {};
|
|
230
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
231
|
+
if (IMAGE_KEY_PATTERN.test(key) && typeof value === 'string') {
|
|
232
|
+
if (VALID_URL_PREFIXES.some(p => value.startsWith(p))) {
|
|
233
|
+
result[key] = value;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// Invalid image URL — strip it (likely hallucinated)
|
|
237
|
+
// Keep the key but set to undefined so the widget can use its fallback
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else if (typeof value === 'object' && value !== null) {
|
|
241
|
+
// Special case: avatar as object { src: '...' }
|
|
242
|
+
if (IMAGE_KEY_PATTERN.test(key) && 'src' in value) {
|
|
243
|
+
const srcVal = value.src;
|
|
244
|
+
if (typeof srcVal === 'string' && !VALID_URL_PREFIXES.some(p => srcVal.startsWith(p))) {
|
|
245
|
+
// Strip the whole avatar object if src is invalid
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
result[key] = sanitizeImageUrls(value);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
result[key] = value;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
return obj;
|
|
258
|
+
}
|
|
259
|
+
export function createWebMcpServer(name, options) {
|
|
260
|
+
const widgets = new Map();
|
|
261
|
+
const customTools = [];
|
|
262
|
+
let builtinTools = null;
|
|
263
|
+
function generateId() {
|
|
264
|
+
return 'w_' + Math.random().toString(36).slice(2, 8);
|
|
265
|
+
}
|
|
266
|
+
/** Lazily create the 3 built-in tools on first widget registration. */
|
|
267
|
+
function ensureBuiltinTools() {
|
|
268
|
+
if (builtinTools)
|
|
269
|
+
return;
|
|
270
|
+
builtinTools = [
|
|
271
|
+
{
|
|
272
|
+
name: 'search_recipes',
|
|
273
|
+
description: 'List available widget recipes with their descriptions.',
|
|
274
|
+
inputSchema: {
|
|
275
|
+
type: 'object',
|
|
276
|
+
properties: {
|
|
277
|
+
query: {
|
|
278
|
+
type: 'string',
|
|
279
|
+
description: 'Optional search term to filter recipes',
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
additionalProperties: false,
|
|
283
|
+
},
|
|
284
|
+
execute: async (params) => {
|
|
285
|
+
const query = params.query?.toLowerCase();
|
|
286
|
+
const results = [...widgets.values()]
|
|
287
|
+
.filter(w => !query || w.name.includes(query) || w.description.toLowerCase().includes(query))
|
|
288
|
+
.map(w => ({ name: w.name, description: w.description, group: w.group }));
|
|
289
|
+
return results;
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: 'list_recipes',
|
|
294
|
+
description: 'List all available widget recipes with their name and description.',
|
|
295
|
+
inputSchema: {
|
|
296
|
+
type: 'object',
|
|
297
|
+
properties: {},
|
|
298
|
+
additionalProperties: false,
|
|
299
|
+
},
|
|
300
|
+
execute: async () => {
|
|
301
|
+
const results = [...widgets.values()]
|
|
302
|
+
.map(w => ({ name: w.name, description: w.description, group: w.group }));
|
|
303
|
+
return results;
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: 'get_recipe',
|
|
308
|
+
description: 'Get the full recipe for a widget: JSON schema + usage instructions.',
|
|
309
|
+
inputSchema: {
|
|
310
|
+
type: 'object',
|
|
311
|
+
properties: {
|
|
312
|
+
name: { type: 'string', description: 'Widget name' },
|
|
313
|
+
},
|
|
314
|
+
required: ['name'],
|
|
315
|
+
additionalProperties: false,
|
|
316
|
+
},
|
|
317
|
+
execute: async (params) => {
|
|
318
|
+
const widgetName = params.name;
|
|
319
|
+
const entry = widgets.get(widgetName);
|
|
320
|
+
if (!entry) {
|
|
321
|
+
return { error: `Widget "${widgetName}" not found. Available: ${[...widgets.keys()].join(', ')}` };
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
name: entry.name,
|
|
325
|
+
description: entry.description,
|
|
326
|
+
schema: entry.inputSchema,
|
|
327
|
+
recipe: entry.recipe,
|
|
328
|
+
};
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: 'widget_display',
|
|
333
|
+
// Description is dynamic — rebuilt in layer()
|
|
334
|
+
description: 'Display a widget on the canvas. REQUIRED: {name: "widget_type", params: {…}}. Example: {name: "text", params: {content: "Hello world"}}',
|
|
335
|
+
inputSchema: {
|
|
336
|
+
type: 'object',
|
|
337
|
+
properties: {
|
|
338
|
+
name: { type: 'string', description: 'Widget name (e.g. "text", "stat", "list", "chart", "data-table")' },
|
|
339
|
+
params: {
|
|
340
|
+
type: 'object',
|
|
341
|
+
description: 'Widget parameters as JSON object (call get_recipe for the full schema). Example for text: {content: "Hello"}',
|
|
342
|
+
additionalProperties: true,
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
required: ['name'],
|
|
346
|
+
additionalProperties: false,
|
|
347
|
+
},
|
|
348
|
+
execute: async (params) => {
|
|
349
|
+
const widgetName = params.name;
|
|
350
|
+
const entry = widgets.get(widgetName);
|
|
351
|
+
if (!entry) {
|
|
352
|
+
return {
|
|
353
|
+
error: `Widget "${widgetName}" not found. Available: ${[...widgets.keys()].join(', ')}`,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const rawParams = (params.params ?? {});
|
|
357
|
+
const validation = validateJsonSchema(rawParams, entry.inputSchema);
|
|
358
|
+
if (!validation.valid) {
|
|
359
|
+
return {
|
|
360
|
+
error: 'Validation failed',
|
|
361
|
+
details: validation.errors,
|
|
362
|
+
expected_schema: entry.inputSchema,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
// Sanitize image URLs — strip hallucinated/invalid URLs before sending to UI
|
|
366
|
+
const widgetParams = sanitizeImageUrls(rawParams);
|
|
367
|
+
return { widget: widgetName, data: widgetParams, id: generateId() };
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
];
|
|
371
|
+
}
|
|
372
|
+
const server = {
|
|
373
|
+
get name() { return name; },
|
|
374
|
+
get description() { return options.description; },
|
|
375
|
+
registerWidget(recipeMarkdown, renderer) {
|
|
376
|
+
const { frontmatter, body } = parseFrontmatter(recipeMarkdown);
|
|
377
|
+
const widgetName = frontmatter.widget;
|
|
378
|
+
if (!widgetName) {
|
|
379
|
+
throw new Error('Recipe frontmatter must include a "widget" field.');
|
|
380
|
+
}
|
|
381
|
+
const schema = frontmatter.schema;
|
|
382
|
+
if (!schema) {
|
|
383
|
+
throw new Error(`Recipe "${widgetName}" frontmatter must include a "schema" field.`);
|
|
384
|
+
}
|
|
385
|
+
const entry = {
|
|
386
|
+
name: widgetName,
|
|
387
|
+
description: frontmatter.description ?? '',
|
|
388
|
+
inputSchema: schema,
|
|
389
|
+
recipe: body,
|
|
390
|
+
renderer,
|
|
391
|
+
group: frontmatter.group,
|
|
392
|
+
vanilla: typeof renderer === 'function',
|
|
393
|
+
};
|
|
394
|
+
widgets.set(widgetName, entry);
|
|
395
|
+
ensureBuiltinTools();
|
|
396
|
+
},
|
|
397
|
+
addTool(tool) {
|
|
398
|
+
customTools.push(tool);
|
|
399
|
+
},
|
|
400
|
+
layer() {
|
|
401
|
+
const allTools = [...customTools];
|
|
402
|
+
if (builtinTools) {
|
|
403
|
+
// Rebuild widget_display description with current widget names
|
|
404
|
+
const names = [...widgets.keys()];
|
|
405
|
+
const displayTool = builtinTools.find(t => t.name === 'widget_display');
|
|
406
|
+
displayTool.description = `Display a widget on the canvas. REQUIRED: {name: "widget_type", params: {…}}. Example: {name: "text", params: {content: "Hello"}}. Available widgets: ${names.join(', ')}.`;
|
|
407
|
+
allTools.push(...builtinTools);
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
protocol: 'webmcp',
|
|
411
|
+
serverName: name,
|
|
412
|
+
description: options.description,
|
|
413
|
+
tools: allTools,
|
|
414
|
+
};
|
|
415
|
+
},
|
|
416
|
+
getWidget(widgetName) {
|
|
417
|
+
return widgets.get(widgetName);
|
|
418
|
+
},
|
|
419
|
+
listWidgets() {
|
|
420
|
+
return [...widgets.values()];
|
|
421
|
+
},
|
|
422
|
+
};
|
|
423
|
+
return server;
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=webmcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webmcp-server.js","sourceRoot":"","sources":["../src/webmcp-server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/client.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { McpServerInfo, McpCapabilities, McpInitializeResult, McpTool, McpToolResult, McpClientOptions } from './types.js';
|
|
2
|
+
export declare class McpClient {
|
|
3
|
+
private url;
|
|
4
|
+
private options;
|
|
5
|
+
private sessionId;
|
|
6
|
+
private tools;
|
|
7
|
+
private serverInfo;
|
|
8
|
+
private capabilities;
|
|
9
|
+
private connected;
|
|
10
|
+
private rpcIdCounter;
|
|
11
|
+
private isReconnecting;
|
|
12
|
+
private reconnectPromise;
|
|
13
|
+
constructor(url: string, options?: McpClientOptions);
|
|
14
|
+
connect(): Promise<McpInitializeResult>;
|
|
15
|
+
listTools(): Promise<McpTool[]>;
|
|
16
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<McpToolResult>;
|
|
17
|
+
disconnect(): Promise<void>;
|
|
18
|
+
isConnected(): boolean;
|
|
19
|
+
getServerInfo(): McpServerInfo | null;
|
|
20
|
+
getCapabilities(): McpCapabilities | null;
|
|
21
|
+
getTools(): McpTool[];
|
|
22
|
+
getSessionId(): string | null;
|
|
23
|
+
private notify;
|
|
24
|
+
private rpc;
|
|
25
|
+
private parseSseResponse;
|
|
26
|
+
}
|
package/src/client.ts
CHANGED
|
@@ -131,7 +131,9 @@ export class McpClient {
|
|
|
131
131
|
...this.options.headers,
|
|
132
132
|
};
|
|
133
133
|
if (this.sessionId) headers['Mcp-Session-Id'] = this.sessionId;
|
|
134
|
-
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
const timer = setTimeout(() => controller.abort(), this.options.timeout);
|
|
136
|
+
await fetch(this.url, { method: 'POST', headers, body: JSON.stringify(body), signal: controller.signal }).catch((e) => console.warn('[McpClient] notification failed:', e)).finally(() => clearTimeout(timer));
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
private async rpc<T>(method: string, params?: Record<string, unknown>, attempt = 0): Promise<T> {
|
package/src/events.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ToolExecuteResult, PostMessageBridgeOptions } from './types.js';
|
|
2
|
+
type ToolExecutor = (name: string, args: Record<string, unknown>) => Promise<ToolExecuteResult>;
|
|
3
|
+
export declare function listenForAgentCalls(executor: ToolExecutor, options?: PostMessageBridgeOptions): () => void;
|
|
4
|
+
/** @deprecated Use the stop function returned by listenForAgentCalls() instead. */
|
|
5
|
+
export declare function stopListening(): void;
|
|
6
|
+
/**
|
|
7
|
+
* Helper for agents / Chrome extensions that want to call a tool via
|
|
8
|
+
* postMessage and get the result as a Promise.
|
|
9
|
+
*/
|
|
10
|
+
export declare function callToolViaPostMessage(name: string, args: Record<string, unknown>, options?: {
|
|
11
|
+
timeout?: number;
|
|
12
|
+
targetWindow?: Window;
|
|
13
|
+
} & PostMessageBridgeOptions): Promise<ToolExecuteResult>;
|
|
14
|
+
/** Type guard — returns true if data looks like any webmcp:* event. */
|
|
15
|
+
export declare function isWebMCPEvent(data: unknown): boolean;
|
|
16
|
+
export {};
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { JsonSchemaType, JsonSchemaObject, JsonSchema, ToolAnnotations, ModelContextTool, ToolExecuteCallback, ModelContextClient, UserInteractionOptions, UserInteractionResult, ToolRegistrationOptions, RegisteredTool, ContextRegistration, ToolsChangedCallback, ModelContext, ModelContextTesting, ModelContextTestingToolInfo, ToolContentType, ToolContentText, ToolContentImage, ToolContentResource, ToolContentError, ToolContent, ToolExecuteResult, ToolResultMetadata, AuthContext, ConfirmationTier, ConfirmationPolicy, WebMCPPolyfillOptions, JsonRpcRequest, JsonRpcError, JsonRpcResponse, McpServerInfo, McpCapabilities, McpInitializeResult, McpTool, McpToolResultContent, McpToolResult, McpListToolsResult, McpClientOptions, WebMCPCallToolEvent, WebMCPToolResultEvent, WebMCPToolErrorEvent, PostMessageBridgeOptions, } from './types.js';
|
|
2
|
+
export { validateJsonSchema } from './validate.js';
|
|
3
|
+
export type { ValidationResult, ValidationError } from './validate.js';
|
|
4
|
+
export { initializeWebMCPPolyfill, cleanupWebMCPPolyfill, hasNativeWebMCP, executeToolInternal, } from './polyfill.js';
|
|
5
|
+
export { McpClient } from './client.js';
|
|
6
|
+
export { listenForAgentCalls, stopListening, callToolViaPostMessage, isWebMCPEvent, } from './events.js';
|
|
7
|
+
export { dispatchAndWait, signalCompletion, sanitizeSchema, sanitizeSchemaWithReport, flattenSchema, unflattenParams, createToolGroup, } from './utils.js';
|
|
8
|
+
export type { SchemaPatch } from './utils.js';
|
|
9
|
+
export { textResult, jsonResult, } from './webmcp-helpers.js';
|
|
10
|
+
export { McpMultiClient } from './multi-client.js';
|
|
11
|
+
export type { ConnectedServer } from './multi-client.js';
|
|
12
|
+
export { createWebMcpServer, parseFrontmatter, mountWidget } from './webmcp-server.js';
|
|
13
|
+
export type { WebMcpServer, WebMcpServerOptions, WebMcpToolDef, WidgetEntry, WidgetRenderer } from './webmcp-server.js';
|
package/src/index.ts
CHANGED
|
@@ -76,21 +76,23 @@ export {
|
|
|
76
76
|
dispatchAndWait,
|
|
77
77
|
signalCompletion,
|
|
78
78
|
sanitizeSchema,
|
|
79
|
+
sanitizeSchemaWithReport,
|
|
80
|
+
flattenSchema,
|
|
81
|
+
unflattenParams,
|
|
79
82
|
createToolGroup,
|
|
80
83
|
} from './utils.js';
|
|
84
|
+
export type { SchemaPatch } from './utils.js';
|
|
81
85
|
|
|
82
|
-
// WebMCP helpers (
|
|
86
|
+
// WebMCP helpers (result builders)
|
|
83
87
|
export {
|
|
84
88
|
textResult,
|
|
85
89
|
jsonResult,
|
|
86
|
-
registerSkill,
|
|
87
|
-
unregisterSkill,
|
|
88
|
-
getSkill,
|
|
89
|
-
listSkills,
|
|
90
|
-
clearSkills,
|
|
91
90
|
} from './webmcp-helpers.js';
|
|
92
|
-
export type { SkillDef } from './webmcp-helpers.js';
|
|
93
91
|
|
|
94
92
|
// Multi-MCP client
|
|
95
93
|
export { McpMultiClient } from './multi-client.js';
|
|
96
94
|
export type { ConnectedServer } from './multi-client.js';
|
|
95
|
+
|
|
96
|
+
// WebMCP Server
|
|
97
|
+
export { createWebMcpServer, parseFrontmatter, mountWidget } from './webmcp-server.js';
|
|
98
|
+
export type { WebMcpServer, WebMcpServerOptions, WebMcpToolDef, WidgetEntry, WidgetRenderer } from './webmcp-server.js';
|