@frontmcp/uipack 1.9.2 → 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.js +63 -17
- package/adapters/template-renderer.d.ts +4 -2
- 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 +63 -17
- package/esm/bridge-runtime/index.mjs +50 -11
- package/esm/component/index.mjs +61 -16
- package/esm/index.mjs +63 -17
- package/esm/package.json +2 -2
- package/esm/shell/index.mjs +61 -16
- package/index.js +63 -17
- 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/types.d.ts +2 -0
- package/shell/types.d.ts.map +1 -1
- package/types/ui-config.d.ts +18 -15
- package/types/ui-config.d.ts.map +1 -1
- package/types/ui-runtime.d.ts +1 -1
package/esm/component/index.mjs
CHANGED
|
@@ -829,6 +829,8 @@ ${json}
|
|
|
829
829
|
}
|
|
830
830
|
|
|
831
831
|
// libs/uipack/src/bridge-runtime/iife-generator.ts
|
|
832
|
+
var WIDGET_CALL_META_KEY = "frontmcp/widgetCall";
|
|
833
|
+
var MCP_APPS_DISPLAY_MODES = ["inline", "fullscreen", "pip"];
|
|
832
834
|
function generateBridgeIIFE(options = {}) {
|
|
833
835
|
const { debug = false, trustedOrigins = [], minify = false } = options;
|
|
834
836
|
const adapters = options.adapters || ["openai", "ext-apps", "claude", "gemini", "generic"];
|
|
@@ -876,6 +878,7 @@ function generateBridgeIIFE(options = {}) {
|
|
|
876
878
|
parts.push("bridge.initialize().then(function() {");
|
|
877
879
|
parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');
|
|
878
880
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');
|
|
881
|
+
parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");
|
|
879
882
|
parts.push("}).catch(function(err) {");
|
|
880
883
|
parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');
|
|
881
884
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');
|
|
@@ -1209,6 +1212,9 @@ var OpenAIAdapter = {
|
|
|
1209
1212
|
return Promise.resolve();
|
|
1210
1213
|
},
|
|
1211
1214
|
requestDisplayMode: function(context, mode) {
|
|
1215
|
+
if (window.openai && typeof window.openai.requestDisplayMode === 'function') {
|
|
1216
|
+
return Promise.resolve(window.openai.requestDisplayMode({ mode: mode }));
|
|
1217
|
+
}
|
|
1212
1218
|
return Promise.resolve();
|
|
1213
1219
|
},
|
|
1214
1220
|
setSize: function(context, size) {
|
|
@@ -1246,6 +1252,7 @@ var ExtAppsAdapter = {
|
|
|
1246
1252
|
hostCapabilities: {},
|
|
1247
1253
|
handshakeSettled: false,
|
|
1248
1254
|
pendingSize: null,
|
|
1255
|
+
modelContext: null,
|
|
1249
1256
|
canHandle: function() {
|
|
1250
1257
|
if (typeof window === 'undefined') return false;
|
|
1251
1258
|
if (window.parent === window) return false;
|
|
@@ -1324,8 +1331,19 @@ var ExtAppsAdapter = {
|
|
|
1324
1331
|
|
|
1325
1332
|
if ('method' in data && !('id' in data)) {
|
|
1326
1333
|
this.handleNotification(context, data);
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
if ('method' in data && 'id' in data) {
|
|
1338
|
+
this.handleRequest(context, data, event.origin);
|
|
1327
1339
|
}
|
|
1328
1340
|
},
|
|
1341
|
+
handleRequest: function(context, request, origin) {
|
|
1342
|
+
// ui/resource-teardown: the host is about to unmount the view; reply once listeners have cleaned up.
|
|
1343
|
+
if (request.method !== 'ui/resource-teardown') return;
|
|
1344
|
+
window.dispatchEvent(new CustomEvent('bridge:teardown', { detail: {} }));
|
|
1345
|
+
window.parent.postMessage({ jsonrpc: '2.0', id: request.id, result: {} }, origin);
|
|
1346
|
+
},
|
|
1329
1347
|
handleNotification: function(context, notification) {
|
|
1330
1348
|
var params = notification.params || {};
|
|
1331
1349
|
switch (notification.method) {
|
|
@@ -1349,6 +1367,7 @@ var ExtAppsAdapter = {
|
|
|
1349
1367
|
Object.assign(context.hostContext, params);
|
|
1350
1368
|
context.notifyContextChange(params);
|
|
1351
1369
|
break;
|
|
1370
|
+
case 'ui/notifications/tool-cancelled':
|
|
1352
1371
|
case 'ui/notifications/cancelled':
|
|
1353
1372
|
window.dispatchEvent(new CustomEvent('tool:cancelled', { detail: { reason: params.reason } }));
|
|
1354
1373
|
break;
|
|
@@ -1413,7 +1432,7 @@ var ExtAppsAdapter = {
|
|
|
1413
1432
|
var id = ++this.requestId;
|
|
1414
1433
|
var params = {
|
|
1415
1434
|
appInfo: { name: 'FrontMCP Widget', version: '1.0.0' },
|
|
1416
|
-
appCapabilities: { tools: { listChanged: false } },
|
|
1435
|
+
appCapabilities: { tools: { listChanged: false }, availableDisplayModes: ${JSON.stringify(MCP_APPS_DISPLAY_MODES)} },
|
|
1417
1436
|
protocolVersion: '2024-11-05'
|
|
1418
1437
|
};
|
|
1419
1438
|
|
|
@@ -1481,20 +1500,25 @@ var ExtAppsAdapter = {
|
|
|
1481
1500
|
return Promise.reject(new Error('Server tool proxy not supported'));
|
|
1482
1501
|
}
|
|
1483
1502
|
// Per ext-apps spec: use standard MCP method 'tools/call' (not 'ui/callServerTool')
|
|
1484
|
-
return this.sendRequest('tools/call', { name: name, arguments: args || {} });
|
|
1503
|
+
return this.sendRequest('tools/call', { name: name, arguments: args || {}, _meta: { '${WIDGET_CALL_META_KEY}': true } });
|
|
1485
1504
|
},
|
|
1486
1505
|
sendMessage: function(context, content) {
|
|
1487
1506
|
return this.sendRequest('ui/message', { content: content });
|
|
1488
1507
|
},
|
|
1489
1508
|
openLink: function(context, url) {
|
|
1490
|
-
if (!this.hostCapabilities.openLink) {
|
|
1509
|
+
if (!this.hostCapabilities.openLinks && !this.hostCapabilities.openLink) {
|
|
1491
1510
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
1492
1511
|
return Promise.resolve();
|
|
1493
1512
|
}
|
|
1494
|
-
return this.sendRequest('ui/
|
|
1513
|
+
return this.sendRequest('ui/open-link', { url: url });
|
|
1495
1514
|
},
|
|
1496
1515
|
requestDisplayMode: function(context, mode) {
|
|
1497
|
-
|
|
1516
|
+
// Ask only for a mode the host offers; it answers with the mode it actually set.
|
|
1517
|
+
var offered = context.hostContext.availableDisplayModes;
|
|
1518
|
+
if (!Array.isArray(offered) || offered.indexOf(mode) === -1) {
|
|
1519
|
+
return Promise.reject(new Error('Display mode "' + mode + '" is not available on this host'));
|
|
1520
|
+
}
|
|
1521
|
+
return this.sendRequest('ui/request-display-mode', { mode: mode });
|
|
1498
1522
|
},
|
|
1499
1523
|
setSize: function(context, size) {
|
|
1500
1524
|
// Standard ext-apps sizing: the view tells the host its dimensions with the
|
|
@@ -1515,14 +1539,22 @@ var ExtAppsAdapter = {
|
|
|
1515
1539
|
return this.sendNotification('ui/notifications/size-changed', params);
|
|
1516
1540
|
},
|
|
1517
1541
|
requestClose: function(context) {
|
|
1518
|
-
|
|
1542
|
+
// The host decides whether to tear the view down; it answers with ui/resource-teardown if it does.
|
|
1543
|
+
return this.sendNotification('ui/notifications/request-teardown', {});
|
|
1519
1544
|
},
|
|
1520
1545
|
// Extended ext-apps methods (full specification)
|
|
1521
1546
|
updateModelContext: function(context, data, merge) {
|
|
1522
|
-
if (!this.hostCapabilities.modelContextUpdate) {
|
|
1547
|
+
if (!this.hostCapabilities.updateModelContext && !this.hostCapabilities.modelContextUpdate) {
|
|
1523
1548
|
return Promise.reject(new Error('Model context update not supported'));
|
|
1524
1549
|
}
|
|
1525
|
-
|
|
1550
|
+
// The host keeps only the latest update, so an object merges into the last one here.
|
|
1551
|
+
var isObject = data !== null && typeof data === 'object' && !Array.isArray(data);
|
|
1552
|
+
var modelContext = isObject && merge !== false ? Object.assign({}, this.modelContext, data) : data;
|
|
1553
|
+
this.modelContext = isObject ? modelContext : null;
|
|
1554
|
+
var text = typeof modelContext === 'string' ? modelContext : JSON.stringify(modelContext);
|
|
1555
|
+
var params = { content: [{ type: 'text', text: text }] };
|
|
1556
|
+
if (isObject) params.structuredContent = modelContext;
|
|
1557
|
+
return this.sendRequest('ui/update-model-context', params);
|
|
1526
1558
|
},
|
|
1527
1559
|
log: function(context, level, message, data) {
|
|
1528
1560
|
if (!this.hostCapabilities.logging) {
|
|
@@ -1531,7 +1563,10 @@ var ExtAppsAdapter = {
|
|
|
1531
1563
|
logFn('[Widget] ' + message, data);
|
|
1532
1564
|
return Promise.resolve();
|
|
1533
1565
|
}
|
|
1534
|
-
return this.
|
|
1566
|
+
return this.sendNotification('notifications/message', {
|
|
1567
|
+
level: level === 'warn' ? 'warning' : level,
|
|
1568
|
+
data: data === undefined ? message : { message: message, data: data }
|
|
1569
|
+
});
|
|
1535
1570
|
},
|
|
1536
1571
|
registerTool: function(context, name, description, inputSchema) {
|
|
1537
1572
|
if (!this.hostCapabilities.widgetTools) {
|
|
@@ -1928,8 +1963,10 @@ FrontMcpBridge.prototype.openLink = function(url) {
|
|
|
1928
1963
|
FrontMcpBridge.prototype.requestDisplayMode = function(mode) {
|
|
1929
1964
|
if (!this._adapter) return Promise.reject(new Error('Not initialized'));
|
|
1930
1965
|
var self = this;
|
|
1931
|
-
return this._adapter.requestDisplayMode(this._context, mode).then(function() {
|
|
1932
|
-
|
|
1966
|
+
return this._adapter.requestDisplayMode(this._context, mode).then(function(result) {
|
|
1967
|
+
// The host may set another mode than the one asked for, e.g. when it refuses the change.
|
|
1968
|
+
var setMode = result && result.mode;
|
|
1969
|
+
if (${JSON.stringify(MCP_APPS_DISPLAY_MODES)}.indexOf(setMode) !== -1) self._context.hostContext.displayMode = setMode;
|
|
1933
1970
|
});
|
|
1934
1971
|
};
|
|
1935
1972
|
|
|
@@ -2281,7 +2318,7 @@ function hasSizing(sizing) {
|
|
|
2281
2318
|
return sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0 || sizing.autoResize !== void 0;
|
|
2282
2319
|
}
|
|
2283
2320
|
function buildDataInjectionScript(options) {
|
|
2284
|
-
const { toolName, input, output, structuredContent, sizing } = options;
|
|
2321
|
+
const { toolName, input, output, structuredContent, sizing, displayMode } = options;
|
|
2285
2322
|
const lines = [
|
|
2286
2323
|
`window.__mcpAppsEnabled = true;`,
|
|
2287
2324
|
`window.__mcpToolName = ${safeJsonForScript(toolName)};`,
|
|
@@ -2292,6 +2329,9 @@ function buildDataInjectionScript(options) {
|
|
|
2292
2329
|
if (hasSizing(sizing)) {
|
|
2293
2330
|
lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`);
|
|
2294
2331
|
}
|
|
2332
|
+
if (displayMode && displayMode !== "inline") {
|
|
2333
|
+
lines.push(`window.__mcpDisplayMode = ${safeJsonForScript(displayMode)};`);
|
|
2334
|
+
}
|
|
2295
2335
|
return `<script>
|
|
2296
2336
|
${lines.join("\n")}
|
|
2297
2337
|
</script>`;
|
|
@@ -2357,7 +2397,8 @@ function resolveDataInjectionScript(args) {
|
|
|
2357
2397
|
input: args.input,
|
|
2358
2398
|
output: args.output,
|
|
2359
2399
|
structuredContent: args.structuredContent,
|
|
2360
|
-
sizing: args.sizing
|
|
2400
|
+
sizing: args.sizing,
|
|
2401
|
+
displayMode: args.displayMode
|
|
2361
2402
|
});
|
|
2362
2403
|
}
|
|
2363
2404
|
function buildShell(content, config) {
|
|
@@ -2370,7 +2411,8 @@ function buildShell(content, config) {
|
|
|
2370
2411
|
structuredContent,
|
|
2371
2412
|
includeBridge = true,
|
|
2372
2413
|
title,
|
|
2373
|
-
sizing
|
|
2414
|
+
sizing,
|
|
2415
|
+
displayMode
|
|
2374
2416
|
} = config;
|
|
2375
2417
|
const { customShell, dataInjection } = config;
|
|
2376
2418
|
const dataScript = resolveDataInjectionScript({
|
|
@@ -2379,7 +2421,8 @@ function buildShell(content, config) {
|
|
|
2379
2421
|
input,
|
|
2380
2422
|
output,
|
|
2381
2423
|
structuredContent,
|
|
2382
|
-
sizing
|
|
2424
|
+
sizing,
|
|
2425
|
+
displayMode
|
|
2383
2426
|
});
|
|
2384
2427
|
if (!withShell) {
|
|
2385
2428
|
const html2 = `${dataScript}
|
|
@@ -2400,6 +2443,7 @@ ${content}`;
|
|
|
2400
2443
|
includeBridge,
|
|
2401
2444
|
title,
|
|
2402
2445
|
sizing,
|
|
2446
|
+
displayMode,
|
|
2403
2447
|
dataInjection
|
|
2404
2448
|
});
|
|
2405
2449
|
}
|
|
@@ -2455,7 +2499,8 @@ function buildCustomShell(content, customShell, ctx) {
|
|
|
2455
2499
|
input: ctx.input,
|
|
2456
2500
|
output: ctx.output,
|
|
2457
2501
|
structuredContent: ctx.structuredContent,
|
|
2458
|
-
sizing: ctx.sizing
|
|
2502
|
+
sizing: ctx.sizing,
|
|
2503
|
+
displayMode: ctx.displayMode
|
|
2459
2504
|
});
|
|
2460
2505
|
const sizingStyle = buildSizingStyleTag(ctx.sizing);
|
|
2461
2506
|
const dataWithSizing = sizingStyle ? `${dataScript}
|
package/esm/index.mjs
CHANGED
|
@@ -135,6 +135,8 @@ function safeJsonForScript(value) {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
// libs/uipack/src/bridge-runtime/iife-generator.ts
|
|
138
|
+
var WIDGET_CALL_META_KEY = "frontmcp/widgetCall";
|
|
139
|
+
var MCP_APPS_DISPLAY_MODES = ["inline", "fullscreen", "pip"];
|
|
138
140
|
function generateBridgeIIFE(options = {}) {
|
|
139
141
|
const { debug = false, trustedOrigins = [], minify = false } = options;
|
|
140
142
|
const adapters = options.adapters || ["openai", "ext-apps", "claude", "gemini", "generic"];
|
|
@@ -182,6 +184,7 @@ function generateBridgeIIFE(options = {}) {
|
|
|
182
184
|
parts.push("bridge.initialize().then(function() {");
|
|
183
185
|
parts.push(' log("Bridge initialized with adapter: " + bridge.adapterId);');
|
|
184
186
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:ready", { detail: { adapter: bridge.adapterId } }));');
|
|
187
|
+
parts.push(" if (window.__mcpDisplayMode) bridge.requestDisplayMode(window.__mcpDisplayMode).catch(function() {});");
|
|
185
188
|
parts.push("}).catch(function(err) {");
|
|
186
189
|
parts.push(' console.error("[FrontMcpBridge] Init failed:", err);');
|
|
187
190
|
parts.push(' window.dispatchEvent(new CustomEvent("bridge:error", { detail: { error: err } }));');
|
|
@@ -515,6 +518,9 @@ var OpenAIAdapter = {
|
|
|
515
518
|
return Promise.resolve();
|
|
516
519
|
},
|
|
517
520
|
requestDisplayMode: function(context, mode) {
|
|
521
|
+
if (window.openai && typeof window.openai.requestDisplayMode === 'function') {
|
|
522
|
+
return Promise.resolve(window.openai.requestDisplayMode({ mode: mode }));
|
|
523
|
+
}
|
|
518
524
|
return Promise.resolve();
|
|
519
525
|
},
|
|
520
526
|
setSize: function(context, size) {
|
|
@@ -552,6 +558,7 @@ var ExtAppsAdapter = {
|
|
|
552
558
|
hostCapabilities: {},
|
|
553
559
|
handshakeSettled: false,
|
|
554
560
|
pendingSize: null,
|
|
561
|
+
modelContext: null,
|
|
555
562
|
canHandle: function() {
|
|
556
563
|
if (typeof window === 'undefined') return false;
|
|
557
564
|
if (window.parent === window) return false;
|
|
@@ -630,7 +637,18 @@ var ExtAppsAdapter = {
|
|
|
630
637
|
|
|
631
638
|
if ('method' in data && !('id' in data)) {
|
|
632
639
|
this.handleNotification(context, data);
|
|
640
|
+
return;
|
|
633
641
|
}
|
|
642
|
+
|
|
643
|
+
if ('method' in data && 'id' in data) {
|
|
644
|
+
this.handleRequest(context, data, event.origin);
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
handleRequest: function(context, request, origin) {
|
|
648
|
+
// ui/resource-teardown: the host is about to unmount the view; reply once listeners have cleaned up.
|
|
649
|
+
if (request.method !== 'ui/resource-teardown') return;
|
|
650
|
+
window.dispatchEvent(new CustomEvent('bridge:teardown', { detail: {} }));
|
|
651
|
+
window.parent.postMessage({ jsonrpc: '2.0', id: request.id, result: {} }, origin);
|
|
634
652
|
},
|
|
635
653
|
handleNotification: function(context, notification) {
|
|
636
654
|
var params = notification.params || {};
|
|
@@ -655,6 +673,7 @@ var ExtAppsAdapter = {
|
|
|
655
673
|
Object.assign(context.hostContext, params);
|
|
656
674
|
context.notifyContextChange(params);
|
|
657
675
|
break;
|
|
676
|
+
case 'ui/notifications/tool-cancelled':
|
|
658
677
|
case 'ui/notifications/cancelled':
|
|
659
678
|
window.dispatchEvent(new CustomEvent('tool:cancelled', { detail: { reason: params.reason } }));
|
|
660
679
|
break;
|
|
@@ -719,7 +738,7 @@ var ExtAppsAdapter = {
|
|
|
719
738
|
var id = ++this.requestId;
|
|
720
739
|
var params = {
|
|
721
740
|
appInfo: { name: 'FrontMCP Widget', version: '1.0.0' },
|
|
722
|
-
appCapabilities: { tools: { listChanged: false } },
|
|
741
|
+
appCapabilities: { tools: { listChanged: false }, availableDisplayModes: ${JSON.stringify(MCP_APPS_DISPLAY_MODES)} },
|
|
723
742
|
protocolVersion: '2024-11-05'
|
|
724
743
|
};
|
|
725
744
|
|
|
@@ -787,20 +806,25 @@ var ExtAppsAdapter = {
|
|
|
787
806
|
return Promise.reject(new Error('Server tool proxy not supported'));
|
|
788
807
|
}
|
|
789
808
|
// Per ext-apps spec: use standard MCP method 'tools/call' (not 'ui/callServerTool')
|
|
790
|
-
return this.sendRequest('tools/call', { name: name, arguments: args || {} });
|
|
809
|
+
return this.sendRequest('tools/call', { name: name, arguments: args || {}, _meta: { '${WIDGET_CALL_META_KEY}': true } });
|
|
791
810
|
},
|
|
792
811
|
sendMessage: function(context, content) {
|
|
793
812
|
return this.sendRequest('ui/message', { content: content });
|
|
794
813
|
},
|
|
795
814
|
openLink: function(context, url) {
|
|
796
|
-
if (!this.hostCapabilities.openLink) {
|
|
815
|
+
if (!this.hostCapabilities.openLinks && !this.hostCapabilities.openLink) {
|
|
797
816
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
798
817
|
return Promise.resolve();
|
|
799
818
|
}
|
|
800
|
-
return this.sendRequest('ui/
|
|
819
|
+
return this.sendRequest('ui/open-link', { url: url });
|
|
801
820
|
},
|
|
802
821
|
requestDisplayMode: function(context, mode) {
|
|
803
|
-
|
|
822
|
+
// Ask only for a mode the host offers; it answers with the mode it actually set.
|
|
823
|
+
var offered = context.hostContext.availableDisplayModes;
|
|
824
|
+
if (!Array.isArray(offered) || offered.indexOf(mode) === -1) {
|
|
825
|
+
return Promise.reject(new Error('Display mode "' + mode + '" is not available on this host'));
|
|
826
|
+
}
|
|
827
|
+
return this.sendRequest('ui/request-display-mode', { mode: mode });
|
|
804
828
|
},
|
|
805
829
|
setSize: function(context, size) {
|
|
806
830
|
// Standard ext-apps sizing: the view tells the host its dimensions with the
|
|
@@ -821,14 +845,22 @@ var ExtAppsAdapter = {
|
|
|
821
845
|
return this.sendNotification('ui/notifications/size-changed', params);
|
|
822
846
|
},
|
|
823
847
|
requestClose: function(context) {
|
|
824
|
-
|
|
848
|
+
// The host decides whether to tear the view down; it answers with ui/resource-teardown if it does.
|
|
849
|
+
return this.sendNotification('ui/notifications/request-teardown', {});
|
|
825
850
|
},
|
|
826
851
|
// Extended ext-apps methods (full specification)
|
|
827
852
|
updateModelContext: function(context, data, merge) {
|
|
828
|
-
if (!this.hostCapabilities.modelContextUpdate) {
|
|
853
|
+
if (!this.hostCapabilities.updateModelContext && !this.hostCapabilities.modelContextUpdate) {
|
|
829
854
|
return Promise.reject(new Error('Model context update not supported'));
|
|
830
855
|
}
|
|
831
|
-
|
|
856
|
+
// The host keeps only the latest update, so an object merges into the last one here.
|
|
857
|
+
var isObject = data !== null && typeof data === 'object' && !Array.isArray(data);
|
|
858
|
+
var modelContext = isObject && merge !== false ? Object.assign({}, this.modelContext, data) : data;
|
|
859
|
+
this.modelContext = isObject ? modelContext : null;
|
|
860
|
+
var text = typeof modelContext === 'string' ? modelContext : JSON.stringify(modelContext);
|
|
861
|
+
var params = { content: [{ type: 'text', text: text }] };
|
|
862
|
+
if (isObject) params.structuredContent = modelContext;
|
|
863
|
+
return this.sendRequest('ui/update-model-context', params);
|
|
832
864
|
},
|
|
833
865
|
log: function(context, level, message, data) {
|
|
834
866
|
if (!this.hostCapabilities.logging) {
|
|
@@ -837,7 +869,10 @@ var ExtAppsAdapter = {
|
|
|
837
869
|
logFn('[Widget] ' + message, data);
|
|
838
870
|
return Promise.resolve();
|
|
839
871
|
}
|
|
840
|
-
return this.
|
|
872
|
+
return this.sendNotification('notifications/message', {
|
|
873
|
+
level: level === 'warn' ? 'warning' : level,
|
|
874
|
+
data: data === undefined ? message : { message: message, data: data }
|
|
875
|
+
});
|
|
841
876
|
},
|
|
842
877
|
registerTool: function(context, name, description, inputSchema) {
|
|
843
878
|
if (!this.hostCapabilities.widgetTools) {
|
|
@@ -1234,8 +1269,10 @@ FrontMcpBridge.prototype.openLink = function(url) {
|
|
|
1234
1269
|
FrontMcpBridge.prototype.requestDisplayMode = function(mode) {
|
|
1235
1270
|
if (!this._adapter) return Promise.reject(new Error('Not initialized'));
|
|
1236
1271
|
var self = this;
|
|
1237
|
-
return this._adapter.requestDisplayMode(this._context, mode).then(function() {
|
|
1238
|
-
|
|
1272
|
+
return this._adapter.requestDisplayMode(this._context, mode).then(function(result) {
|
|
1273
|
+
// The host may set another mode than the one asked for, e.g. when it refuses the change.
|
|
1274
|
+
var setMode = result && result.mode;
|
|
1275
|
+
if (${JSON.stringify(MCP_APPS_DISPLAY_MODES)}.indexOf(setMode) !== -1) self._context.hostContext.displayMode = setMode;
|
|
1239
1276
|
});
|
|
1240
1277
|
};
|
|
1241
1278
|
|
|
@@ -3101,7 +3138,7 @@ function hasSizing(sizing) {
|
|
|
3101
3138
|
return sizing.preferredHeight !== void 0 || sizing.minHeight !== void 0 || sizing.maxHeight !== void 0 || sizing.aspectRatio !== void 0 || sizing.autoResize !== void 0;
|
|
3102
3139
|
}
|
|
3103
3140
|
function buildDataInjectionScript(options) {
|
|
3104
|
-
const { toolName, input, output, structuredContent, sizing } = options;
|
|
3141
|
+
const { toolName, input, output, structuredContent, sizing, displayMode } = options;
|
|
3105
3142
|
const lines = [
|
|
3106
3143
|
`window.__mcpAppsEnabled = true;`,
|
|
3107
3144
|
`window.__mcpToolName = ${safeJsonForScript(toolName)};`,
|
|
@@ -3112,6 +3149,9 @@ function buildDataInjectionScript(options) {
|
|
|
3112
3149
|
if (hasSizing(sizing)) {
|
|
3113
3150
|
lines.push(`window.__mcpWidgetSizing = ${safeJsonForScript(sizing)};`);
|
|
3114
3151
|
}
|
|
3152
|
+
if (displayMode && displayMode !== "inline") {
|
|
3153
|
+
lines.push(`window.__mcpDisplayMode = ${safeJsonForScript(displayMode)};`);
|
|
3154
|
+
}
|
|
3115
3155
|
return `<script>
|
|
3116
3156
|
${lines.join("\n")}
|
|
3117
3157
|
</script>`;
|
|
@@ -3203,7 +3243,8 @@ function resolveDataInjectionScript(args) {
|
|
|
3203
3243
|
input: args.input,
|
|
3204
3244
|
output: args.output,
|
|
3205
3245
|
structuredContent: args.structuredContent,
|
|
3206
|
-
sizing: args.sizing
|
|
3246
|
+
sizing: args.sizing,
|
|
3247
|
+
displayMode: args.displayMode
|
|
3207
3248
|
});
|
|
3208
3249
|
}
|
|
3209
3250
|
function buildShell(content, config) {
|
|
@@ -3216,7 +3257,8 @@ function buildShell(content, config) {
|
|
|
3216
3257
|
structuredContent,
|
|
3217
3258
|
includeBridge = true,
|
|
3218
3259
|
title,
|
|
3219
|
-
sizing
|
|
3260
|
+
sizing,
|
|
3261
|
+
displayMode
|
|
3220
3262
|
} = config;
|
|
3221
3263
|
const { customShell, dataInjection } = config;
|
|
3222
3264
|
const dataScript = resolveDataInjectionScript({
|
|
@@ -3225,7 +3267,8 @@ function buildShell(content, config) {
|
|
|
3225
3267
|
input,
|
|
3226
3268
|
output,
|
|
3227
3269
|
structuredContent,
|
|
3228
|
-
sizing
|
|
3270
|
+
sizing,
|
|
3271
|
+
displayMode
|
|
3229
3272
|
});
|
|
3230
3273
|
if (!withShell) {
|
|
3231
3274
|
const html3 = `${dataScript}
|
|
@@ -3246,6 +3289,7 @@ ${content}`;
|
|
|
3246
3289
|
includeBridge,
|
|
3247
3290
|
title,
|
|
3248
3291
|
sizing,
|
|
3292
|
+
displayMode,
|
|
3249
3293
|
dataInjection
|
|
3250
3294
|
});
|
|
3251
3295
|
}
|
|
@@ -3301,7 +3345,8 @@ function buildCustomShell(content, customShell, ctx) {
|
|
|
3301
3345
|
input: ctx.input,
|
|
3302
3346
|
output: ctx.output,
|
|
3303
3347
|
structuredContent: ctx.structuredContent,
|
|
3304
|
-
sizing: ctx.sizing
|
|
3348
|
+
sizing: ctx.sizing,
|
|
3349
|
+
displayMode: ctx.displayMode
|
|
3305
3350
|
});
|
|
3306
3351
|
const sizingStyle = buildSizingStyleTag(ctx.sizing);
|
|
3307
3352
|
const dataWithSizing = sizingStyle ? `${dataScript}
|
|
@@ -4319,7 +4364,7 @@ function noticeStringResult(toolName, logger) {
|
|
|
4319
4364
|
if (noticedStringResultTools.has(toolName)) return;
|
|
4320
4365
|
noticedStringResultTools.add(toolName);
|
|
4321
4366
|
logger.warn(
|
|
4322
|
-
`[frontmcp] The UI template of tool "${toolName}" returned a plain string containing markup.
|
|
4367
|
+
`[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}`
|
|
4323
4368
|
);
|
|
4324
4369
|
}
|
|
4325
4370
|
function renderUnwrappedResult(rawResult, options) {
|
|
@@ -4378,6 +4423,7 @@ function renderToolTemplate(options) {
|
|
|
4378
4423
|
includeBridge: true,
|
|
4379
4424
|
resolver,
|
|
4380
4425
|
sizing,
|
|
4426
|
+
displayMode: options.displayMode,
|
|
4381
4427
|
csp: options.csp ? buildCspConfig(resolver, options.csp) : void 0
|
|
4382
4428
|
};
|
|
4383
4429
|
let html2;
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/uipack",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
4
4
|
"description": "FrontMCP UIpack - HTML shell builder, pluggable import resolver, and NPM component loader for MCP UI (React-free core)",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"typescript": "^5.9.3"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
64
|
+
"@frontmcp/lazy-zod": "1.9.3",
|
|
65
65
|
"esbuild": ">=0.27.0 <1"
|
|
66
66
|
},
|
|
67
67
|
"peerDependenciesMeta": {
|