@frontmcp/uipack 1.9.1 → 1.9.3
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/adapters/index.d.ts +1 -1
- package/adapters/index.d.ts.map +1 -1
- package/adapters/index.js +84 -23
- package/adapters/template-renderer.d.ts +15 -3
- package/adapters/template-renderer.d.ts.map +1 -1
- package/bridge-runtime/iife-generator.d.ts +7 -0
- package/bridge-runtime/iife-generator.d.ts.map +1 -1
- package/bridge-runtime/index.d.ts +1 -1
- package/bridge-runtime/index.d.ts.map +1 -1
- package/bridge-runtime/index.js +52 -11
- package/component/index.js +61 -16
- package/esm/adapters/index.mjs +83 -23
- package/esm/bridge-runtime/index.mjs +50 -11
- package/esm/component/index.mjs +61 -16
- package/esm/index.mjs +83 -23
- package/esm/package.json +2 -2
- package/esm/shell/index.mjs +61 -16
- package/index.js +84 -23
- package/package.json +2 -2
- package/shell/builder.d.ts.map +1 -1
- package/shell/data-injector.d.ts +3 -1
- package/shell/data-injector.d.ts.map +1 -1
- package/shell/index.js +61 -16
- package/shell/trusted-html.d.ts +2 -2
- package/shell/types.d.ts +2 -0
- package/shell/types.d.ts.map +1 -1
- package/types/ui-config.d.ts +23 -20
- package/types/ui-config.d.ts.map +1 -1
- package/types/ui-runtime.d.ts +1 -1
package/adapters/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { MCP_APPS_MIME_TYPE, MCP_APPS_EXTENSION_ID } from './constants';
|
|
|
11
11
|
export { resolveServingMode, type ResolveServingModeOptions, type ServingModeResult, type AdapterPlatformType, } from './serving-mode';
|
|
12
12
|
export { buildToolResponseContent, type ToolResponseContent, type BuildToolResponseContentOptions, } from './response-builder';
|
|
13
13
|
export { isUIRenderFailure, type UIRenderFailure } from './render-failure';
|
|
14
|
-
export { renderToolTemplate, type RenderToolTemplateOptions, type RenderToolTemplateResult } from './template-renderer';
|
|
14
|
+
export { renderToolTemplate, warnIfComponentReference, type RenderToolTemplateOptions, type RenderToolTemplateResult, } from './template-renderer';
|
|
15
15
|
export { detectContentType, type DetectedContentType } from './content-detector';
|
|
16
16
|
export { buildChartHtml, buildMermaidHtml, buildPdfHtml, wrapDetectedContent } from './content-renderers';
|
|
17
17
|
export { createDefaultBaseTemplate, type DefaultBaseTemplateOptions } from './base-template';
|
package/adapters/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAKxE,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EACL,wBAAwB,EACxB,KAAK,mBAAmB,EACxB,KAAK,+BAA+B,GACrC,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAK3E,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAKxE,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AAKxB,OAAO,EACL,wBAAwB,EACxB,KAAK,mBAAmB,EACxB,KAAK,+BAA+B,GACrC,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAK3E,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EAAE,iBAAiB,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAK1G,OAAO,EAAE,yBAAyB,EAAE,KAAK,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAK7F,OAAO,EAAE,qBAAqB,EAAE,KAAK,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKzF,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
|
package/adapters/index.js
CHANGED
|
@@ -33,6 +33,7 @@ __export(adapters_exports, {
|
|
|
33
33
|
isUIRenderFailure: () => isUIRenderFailure,
|
|
34
34
|
renderToolTemplate: () => renderToolTemplate,
|
|
35
35
|
resolveServingMode: () => resolveServingMode,
|
|
36
|
+
warnIfComponentReference: () => warnIfComponentReference,
|
|
36
37
|
wrapDetectedContent: () => wrapDetectedContent
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(adapters_exports);
|
|
@@ -563,6 +564,8 @@ ${json}
|
|
|
563
564
|
}
|
|
564
565
|
|
|
565
566
|
// libs/uipack/src/bridge-runtime/iife-generator.ts
|
|
567
|
+
var WIDGET_CALL_META_KEY = "frontmcp/widgetCall";
|
|
568
|
+
var MCP_APPS_DISPLAY_MODES = ["inline", "fullscreen", "pip"];
|
|
566
569
|
function generateBridgeIIFE(options = {}) {
|
|
567
570
|
const { debug = false, trustedOrigins = [], minify = false } = options;
|
|
568
571
|
const adapters = options.adapters || ["openai", "ext-apps", "claude", "gemini", "generic"];
|
|
@@ -610,6 +613,7 @@ function generateBridgeIIFE(options = {}) {
|
|
|
610
613
|
parts.push("bridge.initialize().then(function() {");
|
|
611
614
|
parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');
|
|
612
615
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');
|
|
616
|
+
parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");
|
|
613
617
|
parts.push("}).catch(function(err) {");
|
|
614
618
|
parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');
|
|
615
619
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');
|
|
@@ -943,6 +947,9 @@ var OpenAIAdapter = {
|
|
|
943
947
|
return Promise.resolve();
|
|
944
948
|
},
|
|
945
949
|
requestDisplayMode: function(context, mode) {
|
|
950
|
+
if (window.openai && typeof window.openai.requestDisplayMode === 'function') {
|
|
951
|
+
return Promise.resolve(window.openai.requestDisplayMode({ mode: mode }));
|
|
952
|
+
}
|
|
946
953
|
return Promise.resolve();
|
|
947
954
|
},
|
|
948
955
|
setSize: function(context, size) {
|
|
@@ -980,6 +987,7 @@ var ExtAppsAdapter = {
|
|
|
980
987
|
hostCapabilities: {},
|
|
981
988
|
handshakeSettled: false,
|
|
982
989
|
pendingSize: null,
|
|
990
|
+
modelContext: null,
|
|
983
991
|
canHandle: function() {
|
|
984
992
|
if (typeof window === 'undefined') return false;
|
|
985
993
|
if (window.parent === window) return false;
|
|
@@ -1058,8 +1066,19 @@ var ExtAppsAdapter = {
|
|
|
1058
1066
|
|
|
1059
1067
|
if ('method' in data && !('id' in data)) {
|
|
1060
1068
|
this.handleNotification(context, data);
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
if ('method' in data && 'id' in data) {
|
|
1073
|
+
this.handleRequest(context, data, event.origin);
|
|
1061
1074
|
}
|
|
1062
1075
|
},
|
|
1076
|
+
handleRequest: function(context, request, origin) {
|
|
1077
|
+
// ui/resource-teardown: the host is about to unmount the view; reply once listeners have cleaned up.
|
|
1078
|
+
if (request.method !== 'ui/resource-teardown') return;
|
|
1079
|
+
window.dispatchEvent(new CustomEvent('bridge:teardown', { detail: {} }));
|
|
1080
|
+
window.parent.postMessage({ jsonrpc: '2.0', id: request.id, result: {} }, origin);
|
|
1081
|
+
},
|
|
1063
1082
|
handleNotification: function(context, notification) {
|
|
1064
1083
|
var params = notification.params || {};
|
|
1065
1084
|
switch (notification.method) {
|
|
@@ -1083,6 +1102,7 @@ var ExtAppsAdapter = {
|
|
|
1083
1102
|
Object.assign(context.hostContext, params);
|
|
1084
1103
|
context.notifyContextChange(params);
|
|
1085
1104
|
break;
|
|
1105
|
+
case 'ui/notifications/tool-cancelled':
|
|
1086
1106
|
case 'ui/notifications/cancelled':
|
|
1087
1107
|
window.dispatchEvent(new CustomEvent('tool:cancelled', { detail: { reason: params.reason } }));
|
|
1088
1108
|
break;
|
|
@@ -1147,7 +1167,7 @@ var ExtAppsAdapter = {
|
|
|
1147
1167
|
var id = ++this.requestId;
|
|
1148
1168
|
var params = {
|
|
1149
1169
|
appInfo: { name: 'FrontMCP Widget', version: '1.0.0' },
|
|
1150
|
-
appCapabilities: { tools: { listChanged: false } },
|
|
1170
|
+
appCapabilities: { tools: { listChanged: false }, availableDisplayModes: ${JSON.stringify(MCP_APPS_DISPLAY_MODES)} },
|
|
1151
1171
|
protocolVersion: '2024-11-05'
|
|
1152
1172
|
};
|
|
1153
1173
|
|
|
@@ -1215,20 +1235,25 @@ var ExtAppsAdapter = {
|
|
|
1215
1235
|
return Promise.reject(new Error('Server tool proxy not supported'));
|
|
1216
1236
|
}
|
|
1217
1237
|
// Per ext-apps spec: use standard MCP method 'tools/call' (not 'ui/callServerTool')
|
|
1218
|
-
return this.sendRequest('tools/call', { name: name, arguments: args || {} });
|
|
1238
|
+
return this.sendRequest('tools/call', { name: name, arguments: args || {}, _meta: { '${WIDGET_CALL_META_KEY}': true } });
|
|
1219
1239
|
},
|
|
1220
1240
|
sendMessage: function(context, content) {
|
|
1221
1241
|
return this.sendRequest('ui/message', { content: content });
|
|
1222
1242
|
},
|
|
1223
1243
|
openLink: function(context, url) {
|
|
1224
|
-
if (!this.hostCapabilities.openLink) {
|
|
1244
|
+
if (!this.hostCapabilities.openLinks && !this.hostCapabilities.openLink) {
|
|
1225
1245
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
1226
1246
|
return Promise.resolve();
|
|
1227
1247
|
}
|
|
1228
|
-
return this.sendRequest('ui/
|
|
1248
|
+
return this.sendRequest('ui/open-link', { url: url });
|
|
1229
1249
|
},
|
|
1230
1250
|
requestDisplayMode: function(context, mode) {
|
|
1231
|
-
|
|
1251
|
+
// Ask only for a mode the host offers; it answers with the mode it actually set.
|
|
1252
|
+
var offered = context.hostContext.availableDisplayModes;
|
|
1253
|
+
if (!Array.isArray(offered) || offered.indexOf(mode) === -1) {
|
|
1254
|
+
return Promise.reject(new Error('Display mode "' + mode + '" is not available on this host'));
|
|
1255
|
+
}
|
|
1256
|
+
return this.sendRequest('ui/request-display-mode', { mode: mode });
|
|
1232
1257
|
},
|
|
1233
1258
|
setSize: function(context, size) {
|
|
1234
1259
|
// Standard ext-apps sizing: the view tells the host its dimensions with the
|
|
@@ -1249,14 +1274,22 @@ var ExtAppsAdapter = {
|
|
|
1249
1274
|
return this.sendNotification('ui/notifications/size-changed', params);
|
|
1250
1275
|
},
|
|
1251
1276
|
requestClose: function(context) {
|
|
1252
|
-
|
|
1277
|
+
// The host decides whether to tear the view down; it answers with ui/resource-teardown if it does.
|
|
1278
|
+
return this.sendNotification('ui/notifications/request-teardown', {});
|
|
1253
1279
|
},
|
|
1254
1280
|
// Extended ext-apps methods (full specification)
|
|
1255
1281
|
updateModelContext: function(context, data, merge) {
|
|
1256
|
-
if (!this.hostCapabilities.modelContextUpdate) {
|
|
1282
|
+
if (!this.hostCapabilities.updateModelContext && !this.hostCapabilities.modelContextUpdate) {
|
|
1257
1283
|
return Promise.reject(new Error('Model context update not supported'));
|
|
1258
1284
|
}
|
|
1259
|
-
|
|
1285
|
+
// The host keeps only the latest update, so an object merges into the last one here.
|
|
1286
|
+
var isObject = data !== null && typeof data === 'object' && !Array.isArray(data);
|
|
1287
|
+
var modelContext = isObject && merge !== false ? Object.assign({}, this.modelContext, data) : data;
|
|
1288
|
+
this.modelContext = isObject ? modelContext : null;
|
|
1289
|
+
var text = typeof modelContext === 'string' ? modelContext : JSON.stringify(modelContext);
|
|
1290
|
+
var params = { content: [{ type: 'text', text: text }] };
|
|
1291
|
+
if (isObject) params.structuredContent = modelContext;
|
|
1292
|
+
return this.sendRequest('ui/update-model-context', params);
|
|
1260
1293
|
},
|
|
1261
1294
|
log: function(context, level, message, data) {
|
|
1262
1295
|
if (!this.hostCapabilities.logging) {
|
|
@@ -1265,7 +1298,10 @@ var ExtAppsAdapter = {
|
|
|
1265
1298
|
logFn('[Widget] ' + message, data);
|
|
1266
1299
|
return Promise.resolve();
|
|
1267
1300
|
}
|
|
1268
|
-
return this.
|
|
1301
|
+
return this.sendNotification('notifications/message', {
|
|
1302
|
+
level: level === 'warn' ? 'warning' : level,
|
|
1303
|
+
data: data === undefined ? message : { message: message, data: data }
|
|
1304
|
+
});
|
|
1269
1305
|
},
|
|
1270
1306
|
registerTool: function(context, name, description, inputSchema) {
|
|
1271
1307
|
if (!this.hostCapabilities.widgetTools) {
|
|
@@ -1662,8 +1698,10 @@ FrontMcpBridge.prototype.openLink = function(url) {
|
|
|
1662
1698
|
FrontMcpBridge.prototype.requestDisplayMode = function(mode) {
|
|
1663
1699
|
if (!this._adapter) return Promise.reject(new Error('Not initialized'));
|
|
1664
1700
|
var self = this;
|
|
1665
|
-
return this._adapter.requestDisplayMode(this._context, mode).then(function() {
|
|
1666
|
-
|
|
1701
|
+
return this._adapter.requestDisplayMode(this._context, mode).then(function(result) {
|
|
1702
|
+
// The host may set another mode than the one asked for, e.g. when it refuses the change.
|
|
1703
|
+
var setMode = result && result.mode;
|
|
1704
|
+
if (${JSON.stringify(MCP_APPS_DISPLAY_MODES)}.indexOf(setMode) !== -1) self._context.hostContext.displayMode = setMode;
|
|
1667
1705
|
});
|
|
1668
1706
|
};
|
|
1669
1707
|
|
|
@@ -2038,7 +2076,7 @@ function hasSizing(sizing) {
|
|
|
2038
2076
|
return sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0 || sizing.autoResize !== void 0;
|
|
2039
2077
|
}
|
|
2040
2078
|
function buildDataInjectionScript(options) {
|
|
2041
|
-
const { toolName, input, output, structuredContent, sizing } = options;
|
|
2079
|
+
const { toolName, input, output, structuredContent, sizing, displayMode } = options;
|
|
2042
2080
|
const lines = [
|
|
2043
2081
|
`window.__mcpAppsEnabled = true;`,
|
|
2044
2082
|
`window.__mcpToolName = ${safeJsonForScript(toolName)};`,
|
|
@@ -2049,6 +2087,9 @@ function buildDataInjectionScript(options) {
|
|
|
2049
2087
|
if (hasSizing(sizing)) {
|
|
2050
2088
|
lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`);
|
|
2051
2089
|
}
|
|
2090
|
+
if (displayMode && displayMode !== "inline") {
|
|
2091
|
+
lines.push(`window.__mcpDisplayMode = ${safeJsonForScript(displayMode)};`);
|
|
2092
|
+
}
|
|
2052
2093
|
return `<script>
|
|
2053
2094
|
${lines.join("\n")}
|
|
2054
2095
|
</script>`;
|
|
@@ -2140,7 +2181,8 @@ function resolveDataInjectionScript(args) {
|
|
|
2140
2181
|
input: args.input,
|
|
2141
2182
|
output: args.output,
|
|
2142
2183
|
structuredContent: args.structuredContent,
|
|
2143
|
-
sizing: args.sizing
|
|
2184
|
+
sizing: args.sizing,
|
|
2185
|
+
displayMode: args.displayMode
|
|
2144
2186
|
});
|
|
2145
2187
|
}
|
|
2146
2188
|
function buildShell(content, config) {
|
|
@@ -2153,7 +2195,8 @@ function buildShell(content, config) {
|
|
|
2153
2195
|
structuredContent,
|
|
2154
2196
|
includeBridge = true,
|
|
2155
2197
|
title,
|
|
2156
|
-
sizing
|
|
2198
|
+
sizing,
|
|
2199
|
+
displayMode
|
|
2157
2200
|
} = config;
|
|
2158
2201
|
const { customShell, dataInjection } = config;
|
|
2159
2202
|
const dataScript = resolveDataInjectionScript({
|
|
@@ -2162,7 +2205,8 @@ function buildShell(content, config) {
|
|
|
2162
2205
|
input,
|
|
2163
2206
|
output,
|
|
2164
2207
|
structuredContent,
|
|
2165
|
-
sizing
|
|
2208
|
+
sizing,
|
|
2209
|
+
displayMode
|
|
2166
2210
|
});
|
|
2167
2211
|
if (!withShell) {
|
|
2168
2212
|
const html3 = `${dataScript}
|
|
@@ -2183,6 +2227,7 @@ ${content}`;
|
|
|
2183
2227
|
includeBridge,
|
|
2184
2228
|
title,
|
|
2185
2229
|
sizing,
|
|
2230
|
+
displayMode,
|
|
2186
2231
|
dataInjection
|
|
2187
2232
|
});
|
|
2188
2233
|
}
|
|
@@ -2238,7 +2283,8 @@ function buildCustomShell(content, customShell, ctx) {
|
|
|
2238
2283
|
input: ctx.input,
|
|
2239
2284
|
output: ctx.output,
|
|
2240
2285
|
structuredContent: ctx.structuredContent,
|
|
2241
|
-
sizing: ctx.sizing
|
|
2286
|
+
sizing: ctx.sizing,
|
|
2287
|
+
displayMode: ctx.displayMode
|
|
2242
2288
|
});
|
|
2243
2289
|
const sizingStyle = buildSizingStyleTag(ctx.sizing);
|
|
2244
2290
|
const dataWithSizing = sizingStyle ? `${dataScript}
|
|
@@ -3077,7 +3123,7 @@ function noticeStringResult(toolName, logger) {
|
|
|
3077
3123
|
if (noticedStringResultTools.has(toolName)) return;
|
|
3078
3124
|
noticedStringResultTools.add(toolName);
|
|
3079
3125
|
logger.warn(
|
|
3080
|
-
`[frontmcp] The UI template of tool "${toolName}" returned a plain string containing markup
|
|
3126
|
+
`[frontmcp] The UI template of tool "${toolName}" returned a plain string containing markup. Since 1.9.2, FrontMCP HTML-escapes plain string results by default, so it is shown as text. Build the markup with ctx.helpers.html\`\u2026\` (interpolated values are escaped) or wrap safe markup with ctx.helpers.trustedHtml(). Set ui.escapeStringResults: false to render plain strings as markup, or true to silence this notice. See ${STRING_RESULT_DOCS}`
|
|
3081
3127
|
);
|
|
3082
3128
|
}
|
|
3083
3129
|
function renderUnwrappedResult(rawResult, options) {
|
|
@@ -3087,13 +3133,14 @@ function renderUnwrappedResult(rawResult, options) {
|
|
|
3087
3133
|
if (typeof rawResult !== "string") {
|
|
3088
3134
|
return `<pre>${escapeHtml(JSON.stringify(rawResult, null, 2))}</pre>`;
|
|
3089
3135
|
}
|
|
3090
|
-
|
|
3091
|
-
|
|
3136
|
+
const looksLikeMarkup = detectContentType(rawResult) === "html";
|
|
3137
|
+
if (looksLikeMarkup && options.escapeStringResults === false) {
|
|
3138
|
+
return rawResult;
|
|
3092
3139
|
}
|
|
3093
|
-
if (options.escapeStringResults === void 0) {
|
|
3140
|
+
if (looksLikeMarkup && options.escapeStringResults === void 0) {
|
|
3094
3141
|
noticeStringResult(options.toolName, options.logger ?? console);
|
|
3095
3142
|
}
|
|
3096
|
-
return rawResult;
|
|
3143
|
+
return escapeHtml(rawResult);
|
|
3097
3144
|
}
|
|
3098
3145
|
var warnedComponentReferences = /* @__PURE__ */ new WeakMap();
|
|
3099
3146
|
function warnComponentReference(template, toolName, logger) {
|
|
@@ -3105,7 +3152,18 @@ function warnComponentReference(template, toolName, logger) {
|
|
|
3105
3152
|
`[FrontMCP] Tool "${toolName}": \`ui.template\` is a React component reference, which cannot be bundled (there is no source file to compile), so the widget would render an empty page. Use \`template: { file: './widget.tsx' }\` instead.`
|
|
3106
3153
|
);
|
|
3107
3154
|
}
|
|
3108
|
-
|
|
3155
|
+
var COMPILED_JSX_PATTERN = /\b(?:React\.createElement|_?jsx(?:s|DEV)?)\)?\s*\(/;
|
|
3156
|
+
function isComponentReference(template) {
|
|
3157
|
+
if (isReactTypedObject(template)) return true;
|
|
3158
|
+
if (typeof template !== "function" || detectUIType(template) !== "react") return false;
|
|
3159
|
+
return isDefinitelyReactComponent(template) || COMPILED_JSX_PATTERN.test(Function.prototype.toString.call(template));
|
|
3160
|
+
}
|
|
3161
|
+
function warnIfComponentReference(toolName, template, logger = console) {
|
|
3162
|
+
if (!isComponentReference(template)) return false;
|
|
3163
|
+
warnComponentReference(template, toolName, logger);
|
|
3164
|
+
return true;
|
|
3165
|
+
}
|
|
3166
|
+
function isReactTypedObject(value) {
|
|
3109
3167
|
return typeof value === "object" && value !== null && "$$typeof" in value;
|
|
3110
3168
|
}
|
|
3111
3169
|
function isDefinitelyReactComponent(template) {
|
|
@@ -3124,6 +3182,7 @@ function renderToolTemplate(options) {
|
|
|
3124
3182
|
includeBridge: true,
|
|
3125
3183
|
resolver,
|
|
3126
3184
|
sizing,
|
|
3185
|
+
displayMode: options.displayMode,
|
|
3127
3186
|
csp: options.csp ? buildCspConfig(resolver, options.csp) : void 0
|
|
3128
3187
|
};
|
|
3129
3188
|
let html2;
|
|
@@ -3145,7 +3204,7 @@ function renderToolTemplate(options) {
|
|
|
3145
3204
|
if (isHtmlBuilder) {
|
|
3146
3205
|
try {
|
|
3147
3206
|
rawResult = template(ctx);
|
|
3148
|
-
isHtmlBuilder = !
|
|
3207
|
+
isHtmlBuilder = !isReactTypedObject(rawResult);
|
|
3149
3208
|
} catch (error) {
|
|
3150
3209
|
if (uiType !== "react") throw error;
|
|
3151
3210
|
isHtmlBuilder = false;
|
|
@@ -3174,6 +3233,7 @@ function renderToolTemplate(options) {
|
|
|
3174
3233
|
hash = shellResult.hash;
|
|
3175
3234
|
size = shellResult.size;
|
|
3176
3235
|
} else {
|
|
3236
|
+
if (isReactTypedObject(template)) warnComponentReference(template, toolName, options.logger ?? console);
|
|
3177
3237
|
const shellResult = buildShell('<div id="root"></div>', shellConfig);
|
|
3178
3238
|
html2 = shellResult.html;
|
|
3179
3239
|
hash = shellResult.hash;
|
|
@@ -3288,5 +3348,6 @@ function buildCDNInfoForUIType(uiType) {
|
|
|
3288
3348
|
isUIRenderFailure,
|
|
3289
3349
|
renderToolTemplate,
|
|
3290
3350
|
resolveServingMode,
|
|
3351
|
+
warnIfComponentReference,
|
|
3291
3352
|
wrapDetectedContent
|
|
3292
3353
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @packageDocumentation
|
|
7
7
|
*/
|
|
8
8
|
import type { ImportResolver } from '../resolver/types';
|
|
9
|
-
import type { WidgetSizing } from '../shell/types';
|
|
9
|
+
import type { ShellConfig, WidgetSizing } from '../shell/types';
|
|
10
10
|
/**
|
|
11
11
|
* Options for rendering a tool template.
|
|
12
12
|
*/
|
|
@@ -36,6 +36,8 @@ export interface RenderToolTemplateOptions {
|
|
|
36
36
|
* shell, and is mirrored onto the returned `meta` as `ui/preferredHeight` etc.
|
|
37
37
|
*/
|
|
38
38
|
sizing?: WidgetSizing;
|
|
39
|
+
/** `ui.displayMode`: the display mode the page asks the host for once its bridge connects. */
|
|
40
|
+
displayMode?: ShellConfig['displayMode'];
|
|
39
41
|
/**
|
|
40
42
|
* Extra origins the widget may load from (`resourceDomains`) or call (`connectDomains`), from the
|
|
41
43
|
* tool's `ui.csp`. Merged into the page's own Content-Security-Policy on every template path.
|
|
@@ -46,8 +48,9 @@ export interface RenderToolTemplateOptions {
|
|
|
46
48
|
};
|
|
47
49
|
/**
|
|
48
50
|
* HTML-escape a plain string returned by a template function; results built with
|
|
49
|
-
* `html` / `trustedHtml` stay markup.
|
|
50
|
-
*
|
|
51
|
+
* `html` / `trustedHtml` stay markup. Unset is the default since 1.9.2: strings are escaped, and a
|
|
52
|
+
* one-time notice per tool is logged when one looked like markup. `true` escapes without the
|
|
53
|
+
* notice; `false` renders strings that look like HTML as markup.
|
|
51
54
|
*/
|
|
52
55
|
escapeStringResults?: boolean;
|
|
53
56
|
/** Receives the one-time string-result notice. Defaults to `console`. */
|
|
@@ -70,6 +73,15 @@ export interface RenderToolTemplateResult {
|
|
|
70
73
|
/** Platform-specific metadata */
|
|
71
74
|
meta: Record<string, unknown>;
|
|
72
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Warn, once per tool, that `template` is a React component reference the widget cannot bundle.
|
|
78
|
+
* The server calls this while it registers UI tools, so the warning appears at startup (#769).
|
|
79
|
+
*
|
|
80
|
+
* @returns Whether the template is a component reference
|
|
81
|
+
*/
|
|
82
|
+
export declare function warnIfComponentReference(toolName: string, template: unknown, logger?: {
|
|
83
|
+
warn: (message: string) => void;
|
|
84
|
+
}): boolean;
|
|
73
85
|
/**
|
|
74
86
|
* Render a tool template into HTML.
|
|
75
87
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAQhE;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACzC;;;OAGG;IACH,GAAG,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAChE;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,yEAAyE;IACzE,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAiGD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,MAAM,GAAE;IAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAAY,GACpD,OAAO,CAIT;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,wBAAwB,CAsH/F"}
|
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* The `_meta` key the bridge sets on a widget's own `tools/call`, so the server answers with the
|
|
11
|
+
* data and does not render the tool's page again into a widget that is already on screen.
|
|
12
|
+
*/
|
|
13
|
+
export declare const WIDGET_CALL_META_KEY = "frontmcp/widgetCall";
|
|
14
|
+
/** The display modes a widget supports, declared to an MCP Apps host in `ui/initialize`. */
|
|
15
|
+
export declare const MCP_APPS_DISPLAY_MODES: readonly ["inline", "fullscreen", "pip"];
|
|
9
16
|
/**
|
|
10
17
|
* Options for generating the bridge IIFE.
|
|
11
18
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iife-generator.d.ts","sourceRoot":"","sources":["../../src/bridge-runtime/iife-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC;IACvE,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"iife-generator.d.ts","sourceRoot":"","sources":["../../src/bridge-runtime/iife-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D,4FAA4F;AAC5F,eAAO,MAAM,sBAAsB,0CAA2C,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC;IACvE,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAgH7E;AAg0CD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,EACvD,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAM,GACnD,MAAM,CAYR;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAuB,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;CAK9B,CAAC"}
|
|
@@ -6,5 +6,5 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
|
-
export { generateBridgeIIFE, generatePlatformBundle, UNIVERSAL_BRIDGE_SCRIPT, BRIDGE_SCRIPT_TAGS, type IIFEGeneratorOptions, } from './iife-generator';
|
|
9
|
+
export { generateBridgeIIFE, generatePlatformBundle, UNIVERSAL_BRIDGE_SCRIPT, BRIDGE_SCRIPT_TAGS, WIDGET_CALL_META_KEY, MCP_APPS_DISPLAY_MODES, type IIFEGeneratorOptions, } from './iife-generator';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge-runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge-runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAC"}
|
package/bridge-runtime/index.js
CHANGED
|
@@ -21,13 +21,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var bridge_runtime_exports = {};
|
|
22
22
|
__export(bridge_runtime_exports, {
|
|
23
23
|
BRIDGE_SCRIPT_TAGS: () => BRIDGE_SCRIPT_TAGS,
|
|
24
|
+
MCP_APPS_DISPLAY_MODES: () => MCP_APPS_DISPLAY_MODES,
|
|
24
25
|
UNIVERSAL_BRIDGE_SCRIPT: () => UNIVERSAL_BRIDGE_SCRIPT,
|
|
26
|
+
WIDGET_CALL_META_KEY: () => WIDGET_CALL_META_KEY,
|
|
25
27
|
generateBridgeIIFE: () => generateBridgeIIFE,
|
|
26
28
|
generatePlatformBundle: () => generatePlatformBundle
|
|
27
29
|
});
|
|
28
30
|
module.exports = __toCommonJS(bridge_runtime_exports);
|
|
29
31
|
|
|
30
32
|
// libs/uipack/src/bridge-runtime/iife-generator.ts
|
|
33
|
+
var WIDGET_CALL_META_KEY = "frontmcp/widgetCall";
|
|
34
|
+
var MCP_APPS_DISPLAY_MODES = ["inline", "fullscreen", "pip"];
|
|
31
35
|
function generateBridgeIIFE(options = {}) {
|
|
32
36
|
const { debug = false, trustedOrigins = [], minify = false } = options;
|
|
33
37
|
const adapters = options.adapters || ["openai", "ext-apps", "claude", "gemini", "generic"];
|
|
@@ -75,6 +79,7 @@ function generateBridgeIIFE(options = {}) {
|
|
|
75
79
|
parts.push("bridge.initialize().then(function() {");
|
|
76
80
|
parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');
|
|
77
81
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');
|
|
82
|
+
parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");
|
|
78
83
|
parts.push("}).catch(function(err) {");
|
|
79
84
|
parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');
|
|
80
85
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');
|
|
@@ -408,6 +413,9 @@ var OpenAIAdapter = {
|
|
|
408
413
|
return Promise.resolve();
|
|
409
414
|
},
|
|
410
415
|
requestDisplayMode: function(context, mode) {
|
|
416
|
+
if (window.openai && typeof window.openai.requestDisplayMode === 'function') {
|
|
417
|
+
return Promise.resolve(window.openai.requestDisplayMode({ mode: mode }));
|
|
418
|
+
}
|
|
411
419
|
return Promise.resolve();
|
|
412
420
|
},
|
|
413
421
|
setSize: function(context, size) {
|
|
@@ -445,6 +453,7 @@ var ExtAppsAdapter = {
|
|
|
445
453
|
hostCapabilities: {},
|
|
446
454
|
handshakeSettled: false,
|
|
447
455
|
pendingSize: null,
|
|
456
|
+
modelContext: null,
|
|
448
457
|
canHandle: function() {
|
|
449
458
|
if (typeof window === 'undefined') return false;
|
|
450
459
|
if (window.parent === window) return false;
|
|
@@ -523,8 +532,19 @@ var ExtAppsAdapter = {
|
|
|
523
532
|
|
|
524
533
|
if ('method' in data && !('id' in data)) {
|
|
525
534
|
this.handleNotification(context, data);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if ('method' in data && 'id' in data) {
|
|
539
|
+
this.handleRequest(context, data, event.origin);
|
|
526
540
|
}
|
|
527
541
|
},
|
|
542
|
+
handleRequest: function(context, request, origin) {
|
|
543
|
+
// ui/resource-teardown: the host is about to unmount the view; reply once listeners have cleaned up.
|
|
544
|
+
if (request.method !== 'ui/resource-teardown') return;
|
|
545
|
+
window.dispatchEvent(new CustomEvent('bridge:teardown', { detail: {} }));
|
|
546
|
+
window.parent.postMessage({ jsonrpc: '2.0', id: request.id, result: {} }, origin);
|
|
547
|
+
},
|
|
528
548
|
handleNotification: function(context, notification) {
|
|
529
549
|
var params = notification.params || {};
|
|
530
550
|
switch (notification.method) {
|
|
@@ -548,6 +568,7 @@ var ExtAppsAdapter = {
|
|
|
548
568
|
Object.assign(context.hostContext, params);
|
|
549
569
|
context.notifyContextChange(params);
|
|
550
570
|
break;
|
|
571
|
+
case 'ui/notifications/tool-cancelled':
|
|
551
572
|
case 'ui/notifications/cancelled':
|
|
552
573
|
window.dispatchEvent(new CustomEvent('tool:cancelled', { detail: { reason: params.reason } }));
|
|
553
574
|
break;
|
|
@@ -612,7 +633,7 @@ var ExtAppsAdapter = {
|
|
|
612
633
|
var id = ++this.requestId;
|
|
613
634
|
var params = {
|
|
614
635
|
appInfo: { name: 'FrontMCP Widget', version: '1.0.0' },
|
|
615
|
-
appCapabilities: { tools: { listChanged: false } },
|
|
636
|
+
appCapabilities: { tools: { listChanged: false }, availableDisplayModes: ${JSON.stringify(MCP_APPS_DISPLAY_MODES)} },
|
|
616
637
|
protocolVersion: '2024-11-05'
|
|
617
638
|
};
|
|
618
639
|
|
|
@@ -680,20 +701,25 @@ var ExtAppsAdapter = {
|
|
|
680
701
|
return Promise.reject(new Error('Server tool proxy not supported'));
|
|
681
702
|
}
|
|
682
703
|
// Per ext-apps spec: use standard MCP method 'tools/call' (not 'ui/callServerTool')
|
|
683
|
-
return this.sendRequest('tools/call', { name: name, arguments: args || {} });
|
|
704
|
+
return this.sendRequest('tools/call', { name: name, arguments: args || {}, _meta: { '${WIDGET_CALL_META_KEY}': true } });
|
|
684
705
|
},
|
|
685
706
|
sendMessage: function(context, content) {
|
|
686
707
|
return this.sendRequest('ui/message', { content: content });
|
|
687
708
|
},
|
|
688
709
|
openLink: function(context, url) {
|
|
689
|
-
if (!this.hostCapabilities.openLink) {
|
|
710
|
+
if (!this.hostCapabilities.openLinks && !this.hostCapabilities.openLink) {
|
|
690
711
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
691
712
|
return Promise.resolve();
|
|
692
713
|
}
|
|
693
|
-
return this.sendRequest('ui/
|
|
714
|
+
return this.sendRequest('ui/open-link', { url: url });
|
|
694
715
|
},
|
|
695
716
|
requestDisplayMode: function(context, mode) {
|
|
696
|
-
|
|
717
|
+
// Ask only for a mode the host offers; it answers with the mode it actually set.
|
|
718
|
+
var offered = context.hostContext.availableDisplayModes;
|
|
719
|
+
if (!Array.isArray(offered) || offered.indexOf(mode) === -1) {
|
|
720
|
+
return Promise.reject(new Error('Display mode "' + mode + '" is not available on this host'));
|
|
721
|
+
}
|
|
722
|
+
return this.sendRequest('ui/request-display-mode', { mode: mode });
|
|
697
723
|
},
|
|
698
724
|
setSize: function(context, size) {
|
|
699
725
|
// Standard ext-apps sizing: the view tells the host its dimensions with the
|
|
@@ -714,14 +740,22 @@ var ExtAppsAdapter = {
|
|
|
714
740
|
return this.sendNotification('ui/notifications/size-changed', params);
|
|
715
741
|
},
|
|
716
742
|
requestClose: function(context) {
|
|
717
|
-
|
|
743
|
+
// The host decides whether to tear the view down; it answers with ui/resource-teardown if it does.
|
|
744
|
+
return this.sendNotification('ui/notifications/request-teardown', {});
|
|
718
745
|
},
|
|
719
746
|
// Extended ext-apps methods (full specification)
|
|
720
747
|
updateModelContext: function(context, data, merge) {
|
|
721
|
-
if (!this.hostCapabilities.modelContextUpdate) {
|
|
748
|
+
if (!this.hostCapabilities.updateModelContext && !this.hostCapabilities.modelContextUpdate) {
|
|
722
749
|
return Promise.reject(new Error('Model context update not supported'));
|
|
723
750
|
}
|
|
724
|
-
|
|
751
|
+
// The host keeps only the latest update, so an object merges into the last one here.
|
|
752
|
+
var isObject = data !== null && typeof data === 'object' && !Array.isArray(data);
|
|
753
|
+
var modelContext = isObject && merge !== false ? Object.assign({}, this.modelContext, data) : data;
|
|
754
|
+
this.modelContext = isObject ? modelContext : null;
|
|
755
|
+
var text = typeof modelContext === 'string' ? modelContext : JSON.stringify(modelContext);
|
|
756
|
+
var params = { content: [{ type: 'text', text: text }] };
|
|
757
|
+
if (isObject) params.structuredContent = modelContext;
|
|
758
|
+
return this.sendRequest('ui/update-model-context', params);
|
|
725
759
|
},
|
|
726
760
|
log: function(context, level, message, data) {
|
|
727
761
|
if (!this.hostCapabilities.logging) {
|
|
@@ -730,7 +764,10 @@ var ExtAppsAdapter = {
|
|
|
730
764
|
logFn('[Widget] ' + message, data);
|
|
731
765
|
return Promise.resolve();
|
|
732
766
|
}
|
|
733
|
-
return this.
|
|
767
|
+
return this.sendNotification('notifications/message', {
|
|
768
|
+
level: level === 'warn' ? 'warning' : level,
|
|
769
|
+
data: data === undefined ? message : { message: message, data: data }
|
|
770
|
+
});
|
|
734
771
|
},
|
|
735
772
|
registerTool: function(context, name, description, inputSchema) {
|
|
736
773
|
if (!this.hostCapabilities.widgetTools) {
|
|
@@ -1127,8 +1164,10 @@ FrontMcpBridge.prototype.openLink = function(url) {
|
|
|
1127
1164
|
FrontMcpBridge.prototype.requestDisplayMode = function(mode) {
|
|
1128
1165
|
if (!this._adapter) return Promise.reject(new Error('Not initialized'));
|
|
1129
1166
|
var self = this;
|
|
1130
|
-
return this._adapter.requestDisplayMode(this._context, mode).then(function() {
|
|
1131
|
-
|
|
1167
|
+
return this._adapter.requestDisplayMode(this._context, mode).then(function(result) {
|
|
1168
|
+
// The host may set another mode than the one asked for, e.g. when it refuses the change.
|
|
1169
|
+
var setMode = result && result.mode;
|
|
1170
|
+
if (${JSON.stringify(MCP_APPS_DISPLAY_MODES)}.indexOf(setMode) !== -1) self._context.hostContext.displayMode = setMode;
|
|
1132
1171
|
});
|
|
1133
1172
|
};
|
|
1134
1173
|
|
|
@@ -1356,7 +1395,9 @@ var BRIDGE_SCRIPT_TAGS = {
|
|
|
1356
1395
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1357
1396
|
0 && (module.exports = {
|
|
1358
1397
|
BRIDGE_SCRIPT_TAGS,
|
|
1398
|
+
MCP_APPS_DISPLAY_MODES,
|
|
1359
1399
|
UNIVERSAL_BRIDGE_SCRIPT,
|
|
1400
|
+
WIDGET_CALL_META_KEY,
|
|
1360
1401
|
generateBridgeIIFE,
|
|
1361
1402
|
generatePlatformBundle
|
|
1362
1403
|
});
|