@sentientui/mcp 0.5.2 → 0.6.0
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/dist/{chunk-OPMHTLTY.js → chunk-LZDDLCPW.js} +274 -8
- package/dist/index.cjs +274 -8
- package/dist/index.js +1 -1
- package/dist/lib.cjs +274 -8
- package/dist/lib.js +1 -1
- package/package.json +1 -1
|
@@ -215,6 +215,263 @@ function registerProjectTools(server, client) {
|
|
|
215
215
|
|
|
216
216
|
// src/tools/components.ts
|
|
217
217
|
import { z as z2 } from "zod";
|
|
218
|
+
|
|
219
|
+
// src/ui/templates.ts
|
|
220
|
+
var VIZ_TITLES = {
|
|
221
|
+
"persona-breakdown": "Persona breakdown",
|
|
222
|
+
"variant-performance": "Variant performance",
|
|
223
|
+
"goal-funnel": "Goal funnel",
|
|
224
|
+
"layout-stats": "Layout stats"
|
|
225
|
+
};
|
|
226
|
+
var SHARED_CSS = `
|
|
227
|
+
:root {
|
|
228
|
+
--surface: #fcfcfb;
|
|
229
|
+
--plane: #f9f9f7;
|
|
230
|
+
--ink: #0b0b0b;
|
|
231
|
+
--ink-2: #52514e;
|
|
232
|
+
--muted: #898781;
|
|
233
|
+
--track: #ecebe6;
|
|
234
|
+
--border: rgba(11,11,11,0.10);
|
|
235
|
+
--series-1: #2a78d6;
|
|
236
|
+
--good: #006300;
|
|
237
|
+
--critical: #c0392b;
|
|
238
|
+
}
|
|
239
|
+
@media (prefers-color-scheme: dark) {
|
|
240
|
+
:root {
|
|
241
|
+
--surface: #1a1a19;
|
|
242
|
+
--plane: #0d0d0d;
|
|
243
|
+
--ink: #ffffff;
|
|
244
|
+
--ink-2: #c3c2b7;
|
|
245
|
+
--muted: #898781;
|
|
246
|
+
--track: #2c2c2a;
|
|
247
|
+
--border: rgba(255,255,255,0.10);
|
|
248
|
+
--series-1: #3987e5;
|
|
249
|
+
--good: #0ca30c;
|
|
250
|
+
--critical: #e06a5c;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
* { box-sizing: border-box; }
|
|
254
|
+
html, body { margin: 0; }
|
|
255
|
+
body {
|
|
256
|
+
background: var(--surface);
|
|
257
|
+
color: var(--ink);
|
|
258
|
+
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
259
|
+
font-size: 14px;
|
|
260
|
+
line-height: 1.45;
|
|
261
|
+
padding: 16px;
|
|
262
|
+
}
|
|
263
|
+
h1 { font-size: 15px; font-weight: 650; margin: 0 0 2px; }
|
|
264
|
+
.sub { color: var(--ink-2); font-size: 12px; margin: 0 0 14px; }
|
|
265
|
+
.rows { display: flex; flex-direction: column; gap: 10px; }
|
|
266
|
+
.row { display: grid; grid-template-columns: 1fr; gap: 4px; }
|
|
267
|
+
.row-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
|
|
268
|
+
.label { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
269
|
+
.val { color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
270
|
+
.track {
|
|
271
|
+
position: relative; height: 14px; border-radius: 4px;
|
|
272
|
+
background: var(--track); overflow: hidden;
|
|
273
|
+
}
|
|
274
|
+
.bar {
|
|
275
|
+
position: absolute; left: 0; top: 0; bottom: 0;
|
|
276
|
+
background: var(--series-1); border-radius: 4px; min-width: 3px;
|
|
277
|
+
}
|
|
278
|
+
.meta { color: var(--ink-2); font-size: 12px; }
|
|
279
|
+
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
|
|
280
|
+
.chip {
|
|
281
|
+
border: 1px solid var(--border); border-radius: 999px;
|
|
282
|
+
padding: 2px 9px; font-size: 12px; color: var(--ink-2);
|
|
283
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
284
|
+
}
|
|
285
|
+
.chip .rank { color: var(--muted); font-variant-numeric: tabular-nums; }
|
|
286
|
+
.delta { font-variant-numeric: tabular-nums; font-weight: 550; white-space: nowrap; }
|
|
287
|
+
.delta.up { color: var(--good); }
|
|
288
|
+
.delta.down { color: var(--critical); }
|
|
289
|
+
.delta.flat { color: var(--muted); }
|
|
290
|
+
.empty { color: var(--ink-2); padding: 8px 0; }
|
|
291
|
+
.foot { color: var(--muted); font-size: 11px; margin-top: 14px; }
|
|
292
|
+
`;
|
|
293
|
+
var HELPERS_JS = `
|
|
294
|
+
function esc(s){ return String(s == null ? '' : s).replace(/[&<>"']/g, function(c){
|
|
295
|
+
return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c]; }); }
|
|
296
|
+
function pct1(n){ return (Number(n) || 0).toFixed(1) + '%'; }
|
|
297
|
+
function clampPct(n){ n = Number(n) || 0; return n < 0 ? 0 : n > 100 ? 100 : n; }
|
|
298
|
+
function el(id){ return document.getElementById(id); }
|
|
299
|
+
function barRow(label, valText, widthPct, metaText){
|
|
300
|
+
return '<div class="row"><div class="row-head"><span class="label">' + esc(label) +
|
|
301
|
+
'</span><span class="val">' + esc(valText) + '</span></div>' +
|
|
302
|
+
'<div class="track"><span class="bar" style="width:' + clampPct(widthPct) + '%"></span></div>' +
|
|
303
|
+
(metaText ? '<div class="meta">' + esc(metaText) + '</div>' : '') + '</div>';
|
|
304
|
+
}
|
|
305
|
+
function showEmpty(msg){ el('viz').innerHTML = '<div class="empty">' + esc(msg) + '</div>'; }
|
|
306
|
+
`;
|
|
307
|
+
var BOOTSTRAP_JS = `
|
|
308
|
+
function __extract(m){
|
|
309
|
+
if (!m) return null;
|
|
310
|
+
if (m.structuredContent) return m.structuredContent;
|
|
311
|
+
if (m.toolOutput) return m.toolOutput;
|
|
312
|
+
if (m.globals && m.globals.toolOutput) return m.globals.toolOutput;
|
|
313
|
+
if (m.payload && m.payload.renderData) return __extract(m.payload.renderData);
|
|
314
|
+
if (m.renderData) return __extract(m.renderData);
|
|
315
|
+
return m;
|
|
316
|
+
}
|
|
317
|
+
function __boot(){
|
|
318
|
+
try {
|
|
319
|
+
var g = (window.openai && window.openai.toolOutput) || window.mcpUiRenderData ||
|
|
320
|
+
(window.__MCP_UI__ && window.__MCP_UI__.toolOutput);
|
|
321
|
+
if (g) { window.__render(g); return; }
|
|
322
|
+
} catch (e) {}
|
|
323
|
+
window.addEventListener('message', function(ev){
|
|
324
|
+
var data = __extract(ev && ev.data);
|
|
325
|
+
if (data && typeof data === 'object') { try { window.__render(data); } catch (e) {} }
|
|
326
|
+
});
|
|
327
|
+
try {
|
|
328
|
+
window.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*');
|
|
329
|
+
window.parent.postMessage({ type: 'openai:request_globals' }, '*');
|
|
330
|
+
} catch (e) {}
|
|
331
|
+
}
|
|
332
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', __boot);
|
|
333
|
+
else __boot();
|
|
334
|
+
`;
|
|
335
|
+
var RENDER_JS = {
|
|
336
|
+
"persona-breakdown": `
|
|
337
|
+
window.__render = function(data){
|
|
338
|
+
var clusters = (data && data.clusters) || [];
|
|
339
|
+
var total = (data && data.totalSessions) || 0;
|
|
340
|
+
el('sub').textContent = total + ' total sessions across ' + clusters.length + ' persona' + (clusters.length === 1 ? '' : 's');
|
|
341
|
+
if (!clusters.length) { showEmpty('No persona clusters yet \u2014 more visitor data is needed.'); return; }
|
|
342
|
+
var sorted = clusters.slice().sort(function(a,b){ return (b.sharePct||0) - (a.sharePct||0); });
|
|
343
|
+
el('viz').innerHTML = sorted.map(function(c){
|
|
344
|
+
var rel = Math.round((c.reliability || 0) * 100);
|
|
345
|
+
return barRow(c.label, pct1(c.sharePct), c.sharePct,
|
|
346
|
+
c.sessionCount + ' sessions \xB7 reliability ' + rel + '%');
|
|
347
|
+
}).join('');
|
|
348
|
+
};
|
|
349
|
+
`,
|
|
350
|
+
"variant-performance": `
|
|
351
|
+
window.__render = function(data){
|
|
352
|
+
var variants = (data && data.variants) || [];
|
|
353
|
+
el('sub').textContent = variants.length + ' variant' + (variants.length === 1 ? '' : 's') + ' \xB7 conversion, last 7 days vs prior 7';
|
|
354
|
+
if (!variants.length) { showEmpty('No variant data available yet.'); return; }
|
|
355
|
+
var max = variants.reduce(function(m,v){ return Math.max(m, v.currentCvr || 0); }, 0) || 1;
|
|
356
|
+
var sorted = variants.slice().sort(function(a,b){ return (b.currentCvr||0) - (a.currentCvr||0); });
|
|
357
|
+
el('viz').innerHTML = sorted.map(function(v){
|
|
358
|
+
var cur = (v.currentCvr || 0) * 100;
|
|
359
|
+
var dp = Number(v.deltaPp) || 0;
|
|
360
|
+
var dir = dp > 0.05 ? 'up' : dp < -0.05 ? 'down' : 'flat';
|
|
361
|
+
var arrow = dir === 'up' ? '\u25B2' : dir === 'down' ? '\u25BC' : '\u2014';
|
|
362
|
+
var sign = dp > 0 ? '+' : '';
|
|
363
|
+
var deltaHtml = '<span class="delta ' + dir + '">' + arrow + ' ' + sign + dp.toFixed(1) + ' pp</span>';
|
|
364
|
+
var head = '<div class="row-head"><span class="label">' + esc(v.variantId) +
|
|
365
|
+
'</span><span class="val">' + cur.toFixed(2) + '% ' + deltaHtml + '</span></div>';
|
|
366
|
+
return '<div class="row">' + head +
|
|
367
|
+
'<div class="track"><span class="bar" style="width:' + clampPct((v.currentCvr || 0) / max * 100) + '%"></span></div>' +
|
|
368
|
+
'<div class="meta">prior ' + ((v.priorCvr||0)*100).toFixed(2) + '% \xB7 momentum ' + esc(v.momentum || 'stable') + '</div></div>';
|
|
369
|
+
}).join('');
|
|
370
|
+
};
|
|
371
|
+
`,
|
|
372
|
+
"goal-funnel": `
|
|
373
|
+
window.__render = function(data){
|
|
374
|
+
var goals = (data && data.goals) || [];
|
|
375
|
+
el('sub').textContent = goals.length + ' goal' + (goals.length === 1 ? '' : 's') + ' \xB7 unique-session conversion';
|
|
376
|
+
if (!goals.length) { showEmpty('No goals configured for this project.'); return; }
|
|
377
|
+
el('viz').innerHTML = goals.map(function(g){
|
|
378
|
+
var cr = (g.conversionRate || 0) * 100;
|
|
379
|
+
var best = (g.variants || []).slice().sort(function(a,b){ return (b.completionRate||0)-(a.completionRate||0); })[0];
|
|
380
|
+
var meta = g.hits + ' hits \xB7 ' + g.uniqueSessions + ' unique sessions' +
|
|
381
|
+
(best ? ' \xB7 best: ' + esc(best.componentId + '/' + best.variantId) + ' ' + ((best.completionRate||0)*100).toFixed(1) + '%' : '');
|
|
382
|
+
return barRow(g.goalName, pct1(cr), cr, meta);
|
|
383
|
+
}).join('');
|
|
384
|
+
};
|
|
385
|
+
`,
|
|
386
|
+
"layout-stats": `
|
|
387
|
+
window.__render = function(data){
|
|
388
|
+
var layouts = (data && data.layouts) || [];
|
|
389
|
+
el('sub').textContent = layouts.length + ' persona' + (layouts.length === 1 ? '' : 's') + ' \xB7 section order by reward';
|
|
390
|
+
if (!layouts.length) { showEmpty('No layout data yet \u2014 more visitor sessions are needed.'); return; }
|
|
391
|
+
var max = layouts.reduce(function(m,l){ return Math.max(m, l.avgReward || 0); }, 0) || 1;
|
|
392
|
+
var sorted = layouts.slice().sort(function(a,b){ return (b.avgReward||0)-(a.avgReward||0); });
|
|
393
|
+
el('viz').innerHTML = sorted.map(function(l){
|
|
394
|
+
var order = (l.layoutOrder || []).map(function(s, i){
|
|
395
|
+
return '<span class="chip"><span class="rank">' + (i+1) + '</span>' + esc(s) + '</span>';
|
|
396
|
+
}).join('');
|
|
397
|
+
var head = '<div class="row-head"><span class="label">' + esc(l.persona) +
|
|
398
|
+
'</span><span class="val">reward ' + (Number(l.avgReward)||0).toFixed(2) + '</span></div>';
|
|
399
|
+
return '<div class="row">' + head +
|
|
400
|
+
'<div class="track"><span class="bar" style="width:' + clampPct((l.avgReward||0)/max*100) + '%"></span></div>' +
|
|
401
|
+
'<div class="chips">' + order + '</div>' +
|
|
402
|
+
'<div class="meta">' + (l.pulls || 0) + ' pulls</div></div>';
|
|
403
|
+
}).join('');
|
|
404
|
+
};
|
|
405
|
+
`
|
|
406
|
+
};
|
|
407
|
+
function buildTemplate(id) {
|
|
408
|
+
const title = VIZ_TITLES[id];
|
|
409
|
+
return `<!doctype html>
|
|
410
|
+
<html lang="en">
|
|
411
|
+
<head>
|
|
412
|
+
<meta charset="utf-8">
|
|
413
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
414
|
+
<title>${title} \u2014 SentientUI</title>
|
|
415
|
+
<style>${SHARED_CSS}</style>
|
|
416
|
+
</head>
|
|
417
|
+
<body class="viz-root">
|
|
418
|
+
<h1>${title}</h1>
|
|
419
|
+
<p class="sub" id="sub">Waiting for data\u2026</p>
|
|
420
|
+
<div class="rows" id="viz"><div class="empty">Loading\u2026</div></div>
|
|
421
|
+
<p class="foot">SentientUI \xB7 rendered by your agent host</p>
|
|
422
|
+
<script>
|
|
423
|
+
${HELPERS_JS}
|
|
424
|
+
${RENDER_JS[id]}
|
|
425
|
+
${BOOTSTRAP_JS}
|
|
426
|
+
</script>
|
|
427
|
+
</body>
|
|
428
|
+
</html>`;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// src/ui/index.ts
|
|
432
|
+
var UI_TOOL_VIZ = {
|
|
433
|
+
get_persona_breakdown: "persona-breakdown",
|
|
434
|
+
get_variant_performance: "variant-performance",
|
|
435
|
+
get_goal_funnel: "goal-funnel",
|
|
436
|
+
get_layout_stats: "layout-stats"
|
|
437
|
+
};
|
|
438
|
+
function uiResourceUri(id) {
|
|
439
|
+
return `ui://sentientui/${id}`;
|
|
440
|
+
}
|
|
441
|
+
function uiMeta(id) {
|
|
442
|
+
const uri = uiResourceUri(id);
|
|
443
|
+
return {
|
|
444
|
+
ui: {
|
|
445
|
+
resourceUri: uri,
|
|
446
|
+
preferredFrameSize: ["720px", "480px"]
|
|
447
|
+
},
|
|
448
|
+
"openai/outputTemplate": uri
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
function registerUiResources(server) {
|
|
452
|
+
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
453
|
+
server.registerResource(
|
|
454
|
+
id,
|
|
455
|
+
uiResourceUri(id),
|
|
456
|
+
{
|
|
457
|
+
title: `${VIZ_TITLES[id]} (UI)`,
|
|
458
|
+
description: `Interactive ${VIZ_TITLES[id]} view for agent hosts that support MCP UI.`,
|
|
459
|
+
mimeType: "text/html"
|
|
460
|
+
},
|
|
461
|
+
async (uri) => ({
|
|
462
|
+
contents: [
|
|
463
|
+
{
|
|
464
|
+
uri: uri.href,
|
|
465
|
+
mimeType: "text/html",
|
|
466
|
+
text: buildTemplate(id)
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
})
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/tools/components.ts
|
|
218
475
|
var projectIdSchema2 = z2.string().uuid().describe("The project UUID");
|
|
219
476
|
function registerComponentTools(server, client) {
|
|
220
477
|
server.registerTool(
|
|
@@ -268,6 +525,7 @@ function registerComponentTools(server, client) {
|
|
|
268
525
|
title: "Variant performance",
|
|
269
526
|
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
|
|
270
527
|
inputSchema: { projectId: projectIdSchema2 },
|
|
528
|
+
_meta: uiMeta("variant-performance"),
|
|
271
529
|
outputSchema: {
|
|
272
530
|
variants: z2.array(
|
|
273
531
|
z2.object({
|
|
@@ -301,13 +559,14 @@ function registerComponentTools(server, client) {
|
|
|
301
559
|
if (!data.cvr?.length) {
|
|
302
560
|
return {
|
|
303
561
|
content: [{ type: "text", text: "No variant data available yet." }],
|
|
304
|
-
structuredContent
|
|
562
|
+
structuredContent,
|
|
563
|
+
_meta: uiMeta("variant-performance")
|
|
305
564
|
};
|
|
306
565
|
}
|
|
307
566
|
const text = data.cvr.map(
|
|
308
567
|
(v) => `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${momentumMap.get(v.variantId) ?? "stable"})`
|
|
309
568
|
).join("\n");
|
|
310
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
569
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
311
570
|
}
|
|
312
571
|
);
|
|
313
572
|
}
|
|
@@ -387,6 +646,7 @@ function registerPersonaTools(server, client) {
|
|
|
387
646
|
title: "Persona breakdown",
|
|
388
647
|
description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
|
|
389
648
|
inputSchema: { projectId: projectIdSchema4 },
|
|
649
|
+
_meta: uiMeta("persona-breakdown"),
|
|
390
650
|
outputSchema: {
|
|
391
651
|
totalSessions: z4.number().describe("Total sessions across all clusters"),
|
|
392
652
|
clusters: z4.array(
|
|
@@ -419,7 +679,8 @@ function registerPersonaTools(server, client) {
|
|
|
419
679
|
if (!data.clusters.length) {
|
|
420
680
|
return {
|
|
421
681
|
content: [{ type: "text", text: "No persona clusters yet. More visitor data is needed." }],
|
|
422
|
-
structuredContent
|
|
682
|
+
structuredContent,
|
|
683
|
+
_meta: uiMeta("persona-breakdown")
|
|
423
684
|
};
|
|
424
685
|
}
|
|
425
686
|
const lines = [
|
|
@@ -431,7 +692,7 @@ function registerPersonaTools(server, client) {
|
|
|
431
692
|
return `- ${c.label}: ${c.sessionCount} sessions (${pct.toFixed(1)}% of traffic, reliability ${(c.avgReliability * 100).toFixed(0)}%)`;
|
|
432
693
|
})
|
|
433
694
|
];
|
|
434
|
-
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
|
|
695
|
+
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
|
|
435
696
|
}
|
|
436
697
|
);
|
|
437
698
|
}
|
|
@@ -446,6 +707,7 @@ function registerGoalTools(server, client) {
|
|
|
446
707
|
title: "Goal funnel",
|
|
447
708
|
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
|
|
448
709
|
inputSchema: { projectId: projectIdSchema5 },
|
|
710
|
+
_meta: uiMeta("goal-funnel"),
|
|
449
711
|
outputSchema: {
|
|
450
712
|
goals: z5.array(
|
|
451
713
|
z5.object({
|
|
@@ -488,7 +750,8 @@ function registerGoalTools(server, client) {
|
|
|
488
750
|
if (!data.goals.length) {
|
|
489
751
|
return {
|
|
490
752
|
content: [{ type: "text", text: "No goals configured for this project." }],
|
|
491
|
-
structuredContent
|
|
753
|
+
structuredContent,
|
|
754
|
+
_meta: uiMeta("goal-funnel")
|
|
492
755
|
};
|
|
493
756
|
}
|
|
494
757
|
const lines = data.goals.flatMap((g) => [
|
|
@@ -496,7 +759,7 @@ function registerGoalTools(server, client) {
|
|
|
496
759
|
...g.variants.map((v) => ` ${v.componentId}/${v.variantId}: ${(v.completionRate * 100).toFixed(1)}% per assigned session`),
|
|
497
760
|
""
|
|
498
761
|
]);
|
|
499
|
-
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent };
|
|
762
|
+
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
500
763
|
}
|
|
501
764
|
);
|
|
502
765
|
}
|
|
@@ -560,6 +823,7 @@ function registerLayoutTools(server, client) {
|
|
|
560
823
|
title: "Layout stats",
|
|
561
824
|
description: "Get per-persona section layout rankings and bandit reward weights.",
|
|
562
825
|
inputSchema: { projectId: projectIdSchema7 },
|
|
826
|
+
_meta: uiMeta("layout-stats"),
|
|
563
827
|
outputSchema: {
|
|
564
828
|
layouts: z7.array(
|
|
565
829
|
z7.object({
|
|
@@ -590,13 +854,14 @@ function registerLayoutTools(server, client) {
|
|
|
590
854
|
if (!stats.length) {
|
|
591
855
|
return {
|
|
592
856
|
content: [{ type: "text", text: "No layout data yet. More visitor sessions are needed." }],
|
|
593
|
-
structuredContent
|
|
857
|
+
structuredContent,
|
|
858
|
+
_meta: uiMeta("layout-stats")
|
|
594
859
|
};
|
|
595
860
|
}
|
|
596
861
|
const text = stats.map(
|
|
597
862
|
(s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
|
|
598
863
|
).join("\n");
|
|
599
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
864
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
|
|
600
865
|
}
|
|
601
866
|
);
|
|
602
867
|
}
|
|
@@ -1117,6 +1382,7 @@ function createMcpServer(client) {
|
|
|
1117
1382
|
name: "@sentientui/mcp",
|
|
1118
1383
|
version: PKG_VERSION
|
|
1119
1384
|
});
|
|
1385
|
+
registerUiResources(server);
|
|
1120
1386
|
registerProjectTools(server, client);
|
|
1121
1387
|
registerComponentTools(server, client);
|
|
1122
1388
|
registerInsightTools(server, client);
|
package/dist/index.cjs
CHANGED
|
@@ -223,6 +223,263 @@ function registerProjectTools(server, client) {
|
|
|
223
223
|
|
|
224
224
|
// src/tools/components.ts
|
|
225
225
|
var import_zod2 = require("zod");
|
|
226
|
+
|
|
227
|
+
// src/ui/templates.ts
|
|
228
|
+
var VIZ_TITLES = {
|
|
229
|
+
"persona-breakdown": "Persona breakdown",
|
|
230
|
+
"variant-performance": "Variant performance",
|
|
231
|
+
"goal-funnel": "Goal funnel",
|
|
232
|
+
"layout-stats": "Layout stats"
|
|
233
|
+
};
|
|
234
|
+
var SHARED_CSS = `
|
|
235
|
+
:root {
|
|
236
|
+
--surface: #fcfcfb;
|
|
237
|
+
--plane: #f9f9f7;
|
|
238
|
+
--ink: #0b0b0b;
|
|
239
|
+
--ink-2: #52514e;
|
|
240
|
+
--muted: #898781;
|
|
241
|
+
--track: #ecebe6;
|
|
242
|
+
--border: rgba(11,11,11,0.10);
|
|
243
|
+
--series-1: #2a78d6;
|
|
244
|
+
--good: #006300;
|
|
245
|
+
--critical: #c0392b;
|
|
246
|
+
}
|
|
247
|
+
@media (prefers-color-scheme: dark) {
|
|
248
|
+
:root {
|
|
249
|
+
--surface: #1a1a19;
|
|
250
|
+
--plane: #0d0d0d;
|
|
251
|
+
--ink: #ffffff;
|
|
252
|
+
--ink-2: #c3c2b7;
|
|
253
|
+
--muted: #898781;
|
|
254
|
+
--track: #2c2c2a;
|
|
255
|
+
--border: rgba(255,255,255,0.10);
|
|
256
|
+
--series-1: #3987e5;
|
|
257
|
+
--good: #0ca30c;
|
|
258
|
+
--critical: #e06a5c;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
* { box-sizing: border-box; }
|
|
262
|
+
html, body { margin: 0; }
|
|
263
|
+
body {
|
|
264
|
+
background: var(--surface);
|
|
265
|
+
color: var(--ink);
|
|
266
|
+
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
267
|
+
font-size: 14px;
|
|
268
|
+
line-height: 1.45;
|
|
269
|
+
padding: 16px;
|
|
270
|
+
}
|
|
271
|
+
h1 { font-size: 15px; font-weight: 650; margin: 0 0 2px; }
|
|
272
|
+
.sub { color: var(--ink-2); font-size: 12px; margin: 0 0 14px; }
|
|
273
|
+
.rows { display: flex; flex-direction: column; gap: 10px; }
|
|
274
|
+
.row { display: grid; grid-template-columns: 1fr; gap: 4px; }
|
|
275
|
+
.row-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
|
|
276
|
+
.label { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
277
|
+
.val { color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
278
|
+
.track {
|
|
279
|
+
position: relative; height: 14px; border-radius: 4px;
|
|
280
|
+
background: var(--track); overflow: hidden;
|
|
281
|
+
}
|
|
282
|
+
.bar {
|
|
283
|
+
position: absolute; left: 0; top: 0; bottom: 0;
|
|
284
|
+
background: var(--series-1); border-radius: 4px; min-width: 3px;
|
|
285
|
+
}
|
|
286
|
+
.meta { color: var(--ink-2); font-size: 12px; }
|
|
287
|
+
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
|
|
288
|
+
.chip {
|
|
289
|
+
border: 1px solid var(--border); border-radius: 999px;
|
|
290
|
+
padding: 2px 9px; font-size: 12px; color: var(--ink-2);
|
|
291
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
292
|
+
}
|
|
293
|
+
.chip .rank { color: var(--muted); font-variant-numeric: tabular-nums; }
|
|
294
|
+
.delta { font-variant-numeric: tabular-nums; font-weight: 550; white-space: nowrap; }
|
|
295
|
+
.delta.up { color: var(--good); }
|
|
296
|
+
.delta.down { color: var(--critical); }
|
|
297
|
+
.delta.flat { color: var(--muted); }
|
|
298
|
+
.empty { color: var(--ink-2); padding: 8px 0; }
|
|
299
|
+
.foot { color: var(--muted); font-size: 11px; margin-top: 14px; }
|
|
300
|
+
`;
|
|
301
|
+
var HELPERS_JS = `
|
|
302
|
+
function esc(s){ return String(s == null ? '' : s).replace(/[&<>"']/g, function(c){
|
|
303
|
+
return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c]; }); }
|
|
304
|
+
function pct1(n){ return (Number(n) || 0).toFixed(1) + '%'; }
|
|
305
|
+
function clampPct(n){ n = Number(n) || 0; return n < 0 ? 0 : n > 100 ? 100 : n; }
|
|
306
|
+
function el(id){ return document.getElementById(id); }
|
|
307
|
+
function barRow(label, valText, widthPct, metaText){
|
|
308
|
+
return '<div class="row"><div class="row-head"><span class="label">' + esc(label) +
|
|
309
|
+
'</span><span class="val">' + esc(valText) + '</span></div>' +
|
|
310
|
+
'<div class="track"><span class="bar" style="width:' + clampPct(widthPct) + '%"></span></div>' +
|
|
311
|
+
(metaText ? '<div class="meta">' + esc(metaText) + '</div>' : '') + '</div>';
|
|
312
|
+
}
|
|
313
|
+
function showEmpty(msg){ el('viz').innerHTML = '<div class="empty">' + esc(msg) + '</div>'; }
|
|
314
|
+
`;
|
|
315
|
+
var BOOTSTRAP_JS = `
|
|
316
|
+
function __extract(m){
|
|
317
|
+
if (!m) return null;
|
|
318
|
+
if (m.structuredContent) return m.structuredContent;
|
|
319
|
+
if (m.toolOutput) return m.toolOutput;
|
|
320
|
+
if (m.globals && m.globals.toolOutput) return m.globals.toolOutput;
|
|
321
|
+
if (m.payload && m.payload.renderData) return __extract(m.payload.renderData);
|
|
322
|
+
if (m.renderData) return __extract(m.renderData);
|
|
323
|
+
return m;
|
|
324
|
+
}
|
|
325
|
+
function __boot(){
|
|
326
|
+
try {
|
|
327
|
+
var g = (window.openai && window.openai.toolOutput) || window.mcpUiRenderData ||
|
|
328
|
+
(window.__MCP_UI__ && window.__MCP_UI__.toolOutput);
|
|
329
|
+
if (g) { window.__render(g); return; }
|
|
330
|
+
} catch (e) {}
|
|
331
|
+
window.addEventListener('message', function(ev){
|
|
332
|
+
var data = __extract(ev && ev.data);
|
|
333
|
+
if (data && typeof data === 'object') { try { window.__render(data); } catch (e) {} }
|
|
334
|
+
});
|
|
335
|
+
try {
|
|
336
|
+
window.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*');
|
|
337
|
+
window.parent.postMessage({ type: 'openai:request_globals' }, '*');
|
|
338
|
+
} catch (e) {}
|
|
339
|
+
}
|
|
340
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', __boot);
|
|
341
|
+
else __boot();
|
|
342
|
+
`;
|
|
343
|
+
var RENDER_JS = {
|
|
344
|
+
"persona-breakdown": `
|
|
345
|
+
window.__render = function(data){
|
|
346
|
+
var clusters = (data && data.clusters) || [];
|
|
347
|
+
var total = (data && data.totalSessions) || 0;
|
|
348
|
+
el('sub').textContent = total + ' total sessions across ' + clusters.length + ' persona' + (clusters.length === 1 ? '' : 's');
|
|
349
|
+
if (!clusters.length) { showEmpty('No persona clusters yet \u2014 more visitor data is needed.'); return; }
|
|
350
|
+
var sorted = clusters.slice().sort(function(a,b){ return (b.sharePct||0) - (a.sharePct||0); });
|
|
351
|
+
el('viz').innerHTML = sorted.map(function(c){
|
|
352
|
+
var rel = Math.round((c.reliability || 0) * 100);
|
|
353
|
+
return barRow(c.label, pct1(c.sharePct), c.sharePct,
|
|
354
|
+
c.sessionCount + ' sessions \xB7 reliability ' + rel + '%');
|
|
355
|
+
}).join('');
|
|
356
|
+
};
|
|
357
|
+
`,
|
|
358
|
+
"variant-performance": `
|
|
359
|
+
window.__render = function(data){
|
|
360
|
+
var variants = (data && data.variants) || [];
|
|
361
|
+
el('sub').textContent = variants.length + ' variant' + (variants.length === 1 ? '' : 's') + ' \xB7 conversion, last 7 days vs prior 7';
|
|
362
|
+
if (!variants.length) { showEmpty('No variant data available yet.'); return; }
|
|
363
|
+
var max = variants.reduce(function(m,v){ return Math.max(m, v.currentCvr || 0); }, 0) || 1;
|
|
364
|
+
var sorted = variants.slice().sort(function(a,b){ return (b.currentCvr||0) - (a.currentCvr||0); });
|
|
365
|
+
el('viz').innerHTML = sorted.map(function(v){
|
|
366
|
+
var cur = (v.currentCvr || 0) * 100;
|
|
367
|
+
var dp = Number(v.deltaPp) || 0;
|
|
368
|
+
var dir = dp > 0.05 ? 'up' : dp < -0.05 ? 'down' : 'flat';
|
|
369
|
+
var arrow = dir === 'up' ? '\u25B2' : dir === 'down' ? '\u25BC' : '\u2014';
|
|
370
|
+
var sign = dp > 0 ? '+' : '';
|
|
371
|
+
var deltaHtml = '<span class="delta ' + dir + '">' + arrow + ' ' + sign + dp.toFixed(1) + ' pp</span>';
|
|
372
|
+
var head = '<div class="row-head"><span class="label">' + esc(v.variantId) +
|
|
373
|
+
'</span><span class="val">' + cur.toFixed(2) + '% ' + deltaHtml + '</span></div>';
|
|
374
|
+
return '<div class="row">' + head +
|
|
375
|
+
'<div class="track"><span class="bar" style="width:' + clampPct((v.currentCvr || 0) / max * 100) + '%"></span></div>' +
|
|
376
|
+
'<div class="meta">prior ' + ((v.priorCvr||0)*100).toFixed(2) + '% \xB7 momentum ' + esc(v.momentum || 'stable') + '</div></div>';
|
|
377
|
+
}).join('');
|
|
378
|
+
};
|
|
379
|
+
`,
|
|
380
|
+
"goal-funnel": `
|
|
381
|
+
window.__render = function(data){
|
|
382
|
+
var goals = (data && data.goals) || [];
|
|
383
|
+
el('sub').textContent = goals.length + ' goal' + (goals.length === 1 ? '' : 's') + ' \xB7 unique-session conversion';
|
|
384
|
+
if (!goals.length) { showEmpty('No goals configured for this project.'); return; }
|
|
385
|
+
el('viz').innerHTML = goals.map(function(g){
|
|
386
|
+
var cr = (g.conversionRate || 0) * 100;
|
|
387
|
+
var best = (g.variants || []).slice().sort(function(a,b){ return (b.completionRate||0)-(a.completionRate||0); })[0];
|
|
388
|
+
var meta = g.hits + ' hits \xB7 ' + g.uniqueSessions + ' unique sessions' +
|
|
389
|
+
(best ? ' \xB7 best: ' + esc(best.componentId + '/' + best.variantId) + ' ' + ((best.completionRate||0)*100).toFixed(1) + '%' : '');
|
|
390
|
+
return barRow(g.goalName, pct1(cr), cr, meta);
|
|
391
|
+
}).join('');
|
|
392
|
+
};
|
|
393
|
+
`,
|
|
394
|
+
"layout-stats": `
|
|
395
|
+
window.__render = function(data){
|
|
396
|
+
var layouts = (data && data.layouts) || [];
|
|
397
|
+
el('sub').textContent = layouts.length + ' persona' + (layouts.length === 1 ? '' : 's') + ' \xB7 section order by reward';
|
|
398
|
+
if (!layouts.length) { showEmpty('No layout data yet \u2014 more visitor sessions are needed.'); return; }
|
|
399
|
+
var max = layouts.reduce(function(m,l){ return Math.max(m, l.avgReward || 0); }, 0) || 1;
|
|
400
|
+
var sorted = layouts.slice().sort(function(a,b){ return (b.avgReward||0)-(a.avgReward||0); });
|
|
401
|
+
el('viz').innerHTML = sorted.map(function(l){
|
|
402
|
+
var order = (l.layoutOrder || []).map(function(s, i){
|
|
403
|
+
return '<span class="chip"><span class="rank">' + (i+1) + '</span>' + esc(s) + '</span>';
|
|
404
|
+
}).join('');
|
|
405
|
+
var head = '<div class="row-head"><span class="label">' + esc(l.persona) +
|
|
406
|
+
'</span><span class="val">reward ' + (Number(l.avgReward)||0).toFixed(2) + '</span></div>';
|
|
407
|
+
return '<div class="row">' + head +
|
|
408
|
+
'<div class="track"><span class="bar" style="width:' + clampPct((l.avgReward||0)/max*100) + '%"></span></div>' +
|
|
409
|
+
'<div class="chips">' + order + '</div>' +
|
|
410
|
+
'<div class="meta">' + (l.pulls || 0) + ' pulls</div></div>';
|
|
411
|
+
}).join('');
|
|
412
|
+
};
|
|
413
|
+
`
|
|
414
|
+
};
|
|
415
|
+
function buildTemplate(id) {
|
|
416
|
+
const title = VIZ_TITLES[id];
|
|
417
|
+
return `<!doctype html>
|
|
418
|
+
<html lang="en">
|
|
419
|
+
<head>
|
|
420
|
+
<meta charset="utf-8">
|
|
421
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
422
|
+
<title>${title} \u2014 SentientUI</title>
|
|
423
|
+
<style>${SHARED_CSS}</style>
|
|
424
|
+
</head>
|
|
425
|
+
<body class="viz-root">
|
|
426
|
+
<h1>${title}</h1>
|
|
427
|
+
<p class="sub" id="sub">Waiting for data\u2026</p>
|
|
428
|
+
<div class="rows" id="viz"><div class="empty">Loading\u2026</div></div>
|
|
429
|
+
<p class="foot">SentientUI \xB7 rendered by your agent host</p>
|
|
430
|
+
<script>
|
|
431
|
+
${HELPERS_JS}
|
|
432
|
+
${RENDER_JS[id]}
|
|
433
|
+
${BOOTSTRAP_JS}
|
|
434
|
+
</script>
|
|
435
|
+
</body>
|
|
436
|
+
</html>`;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/ui/index.ts
|
|
440
|
+
var UI_TOOL_VIZ = {
|
|
441
|
+
get_persona_breakdown: "persona-breakdown",
|
|
442
|
+
get_variant_performance: "variant-performance",
|
|
443
|
+
get_goal_funnel: "goal-funnel",
|
|
444
|
+
get_layout_stats: "layout-stats"
|
|
445
|
+
};
|
|
446
|
+
function uiResourceUri(id) {
|
|
447
|
+
return `ui://sentientui/${id}`;
|
|
448
|
+
}
|
|
449
|
+
function uiMeta(id) {
|
|
450
|
+
const uri = uiResourceUri(id);
|
|
451
|
+
return {
|
|
452
|
+
ui: {
|
|
453
|
+
resourceUri: uri,
|
|
454
|
+
preferredFrameSize: ["720px", "480px"]
|
|
455
|
+
},
|
|
456
|
+
"openai/outputTemplate": uri
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function registerUiResources(server) {
|
|
460
|
+
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
461
|
+
server.registerResource(
|
|
462
|
+
id,
|
|
463
|
+
uiResourceUri(id),
|
|
464
|
+
{
|
|
465
|
+
title: `${VIZ_TITLES[id]} (UI)`,
|
|
466
|
+
description: `Interactive ${VIZ_TITLES[id]} view for agent hosts that support MCP UI.`,
|
|
467
|
+
mimeType: "text/html"
|
|
468
|
+
},
|
|
469
|
+
async (uri) => ({
|
|
470
|
+
contents: [
|
|
471
|
+
{
|
|
472
|
+
uri: uri.href,
|
|
473
|
+
mimeType: "text/html",
|
|
474
|
+
text: buildTemplate(id)
|
|
475
|
+
}
|
|
476
|
+
]
|
|
477
|
+
})
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// src/tools/components.ts
|
|
226
483
|
var projectIdSchema2 = import_zod2.z.string().uuid().describe("The project UUID");
|
|
227
484
|
function registerComponentTools(server, client) {
|
|
228
485
|
server.registerTool(
|
|
@@ -276,6 +533,7 @@ function registerComponentTools(server, client) {
|
|
|
276
533
|
title: "Variant performance",
|
|
277
534
|
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
|
|
278
535
|
inputSchema: { projectId: projectIdSchema2 },
|
|
536
|
+
_meta: uiMeta("variant-performance"),
|
|
279
537
|
outputSchema: {
|
|
280
538
|
variants: import_zod2.z.array(
|
|
281
539
|
import_zod2.z.object({
|
|
@@ -309,13 +567,14 @@ function registerComponentTools(server, client) {
|
|
|
309
567
|
if (!data.cvr?.length) {
|
|
310
568
|
return {
|
|
311
569
|
content: [{ type: "text", text: "No variant data available yet." }],
|
|
312
|
-
structuredContent
|
|
570
|
+
structuredContent,
|
|
571
|
+
_meta: uiMeta("variant-performance")
|
|
313
572
|
};
|
|
314
573
|
}
|
|
315
574
|
const text = data.cvr.map(
|
|
316
575
|
(v) => `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${momentumMap.get(v.variantId) ?? "stable"})`
|
|
317
576
|
).join("\n");
|
|
318
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
577
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
319
578
|
}
|
|
320
579
|
);
|
|
321
580
|
}
|
|
@@ -395,6 +654,7 @@ function registerPersonaTools(server, client) {
|
|
|
395
654
|
title: "Persona breakdown",
|
|
396
655
|
description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
|
|
397
656
|
inputSchema: { projectId: projectIdSchema4 },
|
|
657
|
+
_meta: uiMeta("persona-breakdown"),
|
|
398
658
|
outputSchema: {
|
|
399
659
|
totalSessions: import_zod4.z.number().describe("Total sessions across all clusters"),
|
|
400
660
|
clusters: import_zod4.z.array(
|
|
@@ -427,7 +687,8 @@ function registerPersonaTools(server, client) {
|
|
|
427
687
|
if (!data.clusters.length) {
|
|
428
688
|
return {
|
|
429
689
|
content: [{ type: "text", text: "No persona clusters yet. More visitor data is needed." }],
|
|
430
|
-
structuredContent
|
|
690
|
+
structuredContent,
|
|
691
|
+
_meta: uiMeta("persona-breakdown")
|
|
431
692
|
};
|
|
432
693
|
}
|
|
433
694
|
const lines = [
|
|
@@ -439,7 +700,7 @@ function registerPersonaTools(server, client) {
|
|
|
439
700
|
return `- ${c.label}: ${c.sessionCount} sessions (${pct.toFixed(1)}% of traffic, reliability ${(c.avgReliability * 100).toFixed(0)}%)`;
|
|
440
701
|
})
|
|
441
702
|
];
|
|
442
|
-
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
|
|
703
|
+
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
|
|
443
704
|
}
|
|
444
705
|
);
|
|
445
706
|
}
|
|
@@ -454,6 +715,7 @@ function registerGoalTools(server, client) {
|
|
|
454
715
|
title: "Goal funnel",
|
|
455
716
|
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
|
|
456
717
|
inputSchema: { projectId: projectIdSchema5 },
|
|
718
|
+
_meta: uiMeta("goal-funnel"),
|
|
457
719
|
outputSchema: {
|
|
458
720
|
goals: import_zod5.z.array(
|
|
459
721
|
import_zod5.z.object({
|
|
@@ -496,7 +758,8 @@ function registerGoalTools(server, client) {
|
|
|
496
758
|
if (!data.goals.length) {
|
|
497
759
|
return {
|
|
498
760
|
content: [{ type: "text", text: "No goals configured for this project." }],
|
|
499
|
-
structuredContent
|
|
761
|
+
structuredContent,
|
|
762
|
+
_meta: uiMeta("goal-funnel")
|
|
500
763
|
};
|
|
501
764
|
}
|
|
502
765
|
const lines = data.goals.flatMap((g) => [
|
|
@@ -504,7 +767,7 @@ function registerGoalTools(server, client) {
|
|
|
504
767
|
...g.variants.map((v) => ` ${v.componentId}/${v.variantId}: ${(v.completionRate * 100).toFixed(1)}% per assigned session`),
|
|
505
768
|
""
|
|
506
769
|
]);
|
|
507
|
-
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent };
|
|
770
|
+
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
508
771
|
}
|
|
509
772
|
);
|
|
510
773
|
}
|
|
@@ -568,6 +831,7 @@ function registerLayoutTools(server, client) {
|
|
|
568
831
|
title: "Layout stats",
|
|
569
832
|
description: "Get per-persona section layout rankings and bandit reward weights.",
|
|
570
833
|
inputSchema: { projectId: projectIdSchema7 },
|
|
834
|
+
_meta: uiMeta("layout-stats"),
|
|
571
835
|
outputSchema: {
|
|
572
836
|
layouts: import_zod7.z.array(
|
|
573
837
|
import_zod7.z.object({
|
|
@@ -598,13 +862,14 @@ function registerLayoutTools(server, client) {
|
|
|
598
862
|
if (!stats.length) {
|
|
599
863
|
return {
|
|
600
864
|
content: [{ type: "text", text: "No layout data yet. More visitor sessions are needed." }],
|
|
601
|
-
structuredContent
|
|
865
|
+
structuredContent,
|
|
866
|
+
_meta: uiMeta("layout-stats")
|
|
602
867
|
};
|
|
603
868
|
}
|
|
604
869
|
const text = stats.map(
|
|
605
870
|
(s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
|
|
606
871
|
).join("\n");
|
|
607
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
872
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
|
|
608
873
|
}
|
|
609
874
|
);
|
|
610
875
|
}
|
|
@@ -1125,6 +1390,7 @@ function createMcpServer(client) {
|
|
|
1125
1390
|
name: "@sentientui/mcp",
|
|
1126
1391
|
version: PKG_VERSION
|
|
1127
1392
|
});
|
|
1393
|
+
registerUiResources(server);
|
|
1128
1394
|
registerProjectTools(server, client);
|
|
1129
1395
|
registerComponentTools(server, client);
|
|
1130
1396
|
registerInsightTools(server, client);
|
package/dist/index.js
CHANGED
package/dist/lib.cjs
CHANGED
|
@@ -248,6 +248,263 @@ function registerProjectTools(server, client) {
|
|
|
248
248
|
|
|
249
249
|
// src/tools/components.ts
|
|
250
250
|
var import_zod2 = require("zod");
|
|
251
|
+
|
|
252
|
+
// src/ui/templates.ts
|
|
253
|
+
var VIZ_TITLES = {
|
|
254
|
+
"persona-breakdown": "Persona breakdown",
|
|
255
|
+
"variant-performance": "Variant performance",
|
|
256
|
+
"goal-funnel": "Goal funnel",
|
|
257
|
+
"layout-stats": "Layout stats"
|
|
258
|
+
};
|
|
259
|
+
var SHARED_CSS = `
|
|
260
|
+
:root {
|
|
261
|
+
--surface: #fcfcfb;
|
|
262
|
+
--plane: #f9f9f7;
|
|
263
|
+
--ink: #0b0b0b;
|
|
264
|
+
--ink-2: #52514e;
|
|
265
|
+
--muted: #898781;
|
|
266
|
+
--track: #ecebe6;
|
|
267
|
+
--border: rgba(11,11,11,0.10);
|
|
268
|
+
--series-1: #2a78d6;
|
|
269
|
+
--good: #006300;
|
|
270
|
+
--critical: #c0392b;
|
|
271
|
+
}
|
|
272
|
+
@media (prefers-color-scheme: dark) {
|
|
273
|
+
:root {
|
|
274
|
+
--surface: #1a1a19;
|
|
275
|
+
--plane: #0d0d0d;
|
|
276
|
+
--ink: #ffffff;
|
|
277
|
+
--ink-2: #c3c2b7;
|
|
278
|
+
--muted: #898781;
|
|
279
|
+
--track: #2c2c2a;
|
|
280
|
+
--border: rgba(255,255,255,0.10);
|
|
281
|
+
--series-1: #3987e5;
|
|
282
|
+
--good: #0ca30c;
|
|
283
|
+
--critical: #e06a5c;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
* { box-sizing: border-box; }
|
|
287
|
+
html, body { margin: 0; }
|
|
288
|
+
body {
|
|
289
|
+
background: var(--surface);
|
|
290
|
+
color: var(--ink);
|
|
291
|
+
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
292
|
+
font-size: 14px;
|
|
293
|
+
line-height: 1.45;
|
|
294
|
+
padding: 16px;
|
|
295
|
+
}
|
|
296
|
+
h1 { font-size: 15px; font-weight: 650; margin: 0 0 2px; }
|
|
297
|
+
.sub { color: var(--ink-2); font-size: 12px; margin: 0 0 14px; }
|
|
298
|
+
.rows { display: flex; flex-direction: column; gap: 10px; }
|
|
299
|
+
.row { display: grid; grid-template-columns: 1fr; gap: 4px; }
|
|
300
|
+
.row-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
|
|
301
|
+
.label { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
302
|
+
.val { color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
303
|
+
.track {
|
|
304
|
+
position: relative; height: 14px; border-radius: 4px;
|
|
305
|
+
background: var(--track); overflow: hidden;
|
|
306
|
+
}
|
|
307
|
+
.bar {
|
|
308
|
+
position: absolute; left: 0; top: 0; bottom: 0;
|
|
309
|
+
background: var(--series-1); border-radius: 4px; min-width: 3px;
|
|
310
|
+
}
|
|
311
|
+
.meta { color: var(--ink-2); font-size: 12px; }
|
|
312
|
+
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
|
|
313
|
+
.chip {
|
|
314
|
+
border: 1px solid var(--border); border-radius: 999px;
|
|
315
|
+
padding: 2px 9px; font-size: 12px; color: var(--ink-2);
|
|
316
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
317
|
+
}
|
|
318
|
+
.chip .rank { color: var(--muted); font-variant-numeric: tabular-nums; }
|
|
319
|
+
.delta { font-variant-numeric: tabular-nums; font-weight: 550; white-space: nowrap; }
|
|
320
|
+
.delta.up { color: var(--good); }
|
|
321
|
+
.delta.down { color: var(--critical); }
|
|
322
|
+
.delta.flat { color: var(--muted); }
|
|
323
|
+
.empty { color: var(--ink-2); padding: 8px 0; }
|
|
324
|
+
.foot { color: var(--muted); font-size: 11px; margin-top: 14px; }
|
|
325
|
+
`;
|
|
326
|
+
var HELPERS_JS = `
|
|
327
|
+
function esc(s){ return String(s == null ? '' : s).replace(/[&<>"']/g, function(c){
|
|
328
|
+
return ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[c]; }); }
|
|
329
|
+
function pct1(n){ return (Number(n) || 0).toFixed(1) + '%'; }
|
|
330
|
+
function clampPct(n){ n = Number(n) || 0; return n < 0 ? 0 : n > 100 ? 100 : n; }
|
|
331
|
+
function el(id){ return document.getElementById(id); }
|
|
332
|
+
function barRow(label, valText, widthPct, metaText){
|
|
333
|
+
return '<div class="row"><div class="row-head"><span class="label">' + esc(label) +
|
|
334
|
+
'</span><span class="val">' + esc(valText) + '</span></div>' +
|
|
335
|
+
'<div class="track"><span class="bar" style="width:' + clampPct(widthPct) + '%"></span></div>' +
|
|
336
|
+
(metaText ? '<div class="meta">' + esc(metaText) + '</div>' : '') + '</div>';
|
|
337
|
+
}
|
|
338
|
+
function showEmpty(msg){ el('viz').innerHTML = '<div class="empty">' + esc(msg) + '</div>'; }
|
|
339
|
+
`;
|
|
340
|
+
var BOOTSTRAP_JS = `
|
|
341
|
+
function __extract(m){
|
|
342
|
+
if (!m) return null;
|
|
343
|
+
if (m.structuredContent) return m.structuredContent;
|
|
344
|
+
if (m.toolOutput) return m.toolOutput;
|
|
345
|
+
if (m.globals && m.globals.toolOutput) return m.globals.toolOutput;
|
|
346
|
+
if (m.payload && m.payload.renderData) return __extract(m.payload.renderData);
|
|
347
|
+
if (m.renderData) return __extract(m.renderData);
|
|
348
|
+
return m;
|
|
349
|
+
}
|
|
350
|
+
function __boot(){
|
|
351
|
+
try {
|
|
352
|
+
var g = (window.openai && window.openai.toolOutput) || window.mcpUiRenderData ||
|
|
353
|
+
(window.__MCP_UI__ && window.__MCP_UI__.toolOutput);
|
|
354
|
+
if (g) { window.__render(g); return; }
|
|
355
|
+
} catch (e) {}
|
|
356
|
+
window.addEventListener('message', function(ev){
|
|
357
|
+
var data = __extract(ev && ev.data);
|
|
358
|
+
if (data && typeof data === 'object') { try { window.__render(data); } catch (e) {} }
|
|
359
|
+
});
|
|
360
|
+
try {
|
|
361
|
+
window.parent.postMessage({ type: 'ui-lifecycle-iframe-ready' }, '*');
|
|
362
|
+
window.parent.postMessage({ type: 'openai:request_globals' }, '*');
|
|
363
|
+
} catch (e) {}
|
|
364
|
+
}
|
|
365
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', __boot);
|
|
366
|
+
else __boot();
|
|
367
|
+
`;
|
|
368
|
+
var RENDER_JS = {
|
|
369
|
+
"persona-breakdown": `
|
|
370
|
+
window.__render = function(data){
|
|
371
|
+
var clusters = (data && data.clusters) || [];
|
|
372
|
+
var total = (data && data.totalSessions) || 0;
|
|
373
|
+
el('sub').textContent = total + ' total sessions across ' + clusters.length + ' persona' + (clusters.length === 1 ? '' : 's');
|
|
374
|
+
if (!clusters.length) { showEmpty('No persona clusters yet \u2014 more visitor data is needed.'); return; }
|
|
375
|
+
var sorted = clusters.slice().sort(function(a,b){ return (b.sharePct||0) - (a.sharePct||0); });
|
|
376
|
+
el('viz').innerHTML = sorted.map(function(c){
|
|
377
|
+
var rel = Math.round((c.reliability || 0) * 100);
|
|
378
|
+
return barRow(c.label, pct1(c.sharePct), c.sharePct,
|
|
379
|
+
c.sessionCount + ' sessions \xB7 reliability ' + rel + '%');
|
|
380
|
+
}).join('');
|
|
381
|
+
};
|
|
382
|
+
`,
|
|
383
|
+
"variant-performance": `
|
|
384
|
+
window.__render = function(data){
|
|
385
|
+
var variants = (data && data.variants) || [];
|
|
386
|
+
el('sub').textContent = variants.length + ' variant' + (variants.length === 1 ? '' : 's') + ' \xB7 conversion, last 7 days vs prior 7';
|
|
387
|
+
if (!variants.length) { showEmpty('No variant data available yet.'); return; }
|
|
388
|
+
var max = variants.reduce(function(m,v){ return Math.max(m, v.currentCvr || 0); }, 0) || 1;
|
|
389
|
+
var sorted = variants.slice().sort(function(a,b){ return (b.currentCvr||0) - (a.currentCvr||0); });
|
|
390
|
+
el('viz').innerHTML = sorted.map(function(v){
|
|
391
|
+
var cur = (v.currentCvr || 0) * 100;
|
|
392
|
+
var dp = Number(v.deltaPp) || 0;
|
|
393
|
+
var dir = dp > 0.05 ? 'up' : dp < -0.05 ? 'down' : 'flat';
|
|
394
|
+
var arrow = dir === 'up' ? '\u25B2' : dir === 'down' ? '\u25BC' : '\u2014';
|
|
395
|
+
var sign = dp > 0 ? '+' : '';
|
|
396
|
+
var deltaHtml = '<span class="delta ' + dir + '">' + arrow + ' ' + sign + dp.toFixed(1) + ' pp</span>';
|
|
397
|
+
var head = '<div class="row-head"><span class="label">' + esc(v.variantId) +
|
|
398
|
+
'</span><span class="val">' + cur.toFixed(2) + '% ' + deltaHtml + '</span></div>';
|
|
399
|
+
return '<div class="row">' + head +
|
|
400
|
+
'<div class="track"><span class="bar" style="width:' + clampPct((v.currentCvr || 0) / max * 100) + '%"></span></div>' +
|
|
401
|
+
'<div class="meta">prior ' + ((v.priorCvr||0)*100).toFixed(2) + '% \xB7 momentum ' + esc(v.momentum || 'stable') + '</div></div>';
|
|
402
|
+
}).join('');
|
|
403
|
+
};
|
|
404
|
+
`,
|
|
405
|
+
"goal-funnel": `
|
|
406
|
+
window.__render = function(data){
|
|
407
|
+
var goals = (data && data.goals) || [];
|
|
408
|
+
el('sub').textContent = goals.length + ' goal' + (goals.length === 1 ? '' : 's') + ' \xB7 unique-session conversion';
|
|
409
|
+
if (!goals.length) { showEmpty('No goals configured for this project.'); return; }
|
|
410
|
+
el('viz').innerHTML = goals.map(function(g){
|
|
411
|
+
var cr = (g.conversionRate || 0) * 100;
|
|
412
|
+
var best = (g.variants || []).slice().sort(function(a,b){ return (b.completionRate||0)-(a.completionRate||0); })[0];
|
|
413
|
+
var meta = g.hits + ' hits \xB7 ' + g.uniqueSessions + ' unique sessions' +
|
|
414
|
+
(best ? ' \xB7 best: ' + esc(best.componentId + '/' + best.variantId) + ' ' + ((best.completionRate||0)*100).toFixed(1) + '%' : '');
|
|
415
|
+
return barRow(g.goalName, pct1(cr), cr, meta);
|
|
416
|
+
}).join('');
|
|
417
|
+
};
|
|
418
|
+
`,
|
|
419
|
+
"layout-stats": `
|
|
420
|
+
window.__render = function(data){
|
|
421
|
+
var layouts = (data && data.layouts) || [];
|
|
422
|
+
el('sub').textContent = layouts.length + ' persona' + (layouts.length === 1 ? '' : 's') + ' \xB7 section order by reward';
|
|
423
|
+
if (!layouts.length) { showEmpty('No layout data yet \u2014 more visitor sessions are needed.'); return; }
|
|
424
|
+
var max = layouts.reduce(function(m,l){ return Math.max(m, l.avgReward || 0); }, 0) || 1;
|
|
425
|
+
var sorted = layouts.slice().sort(function(a,b){ return (b.avgReward||0)-(a.avgReward||0); });
|
|
426
|
+
el('viz').innerHTML = sorted.map(function(l){
|
|
427
|
+
var order = (l.layoutOrder || []).map(function(s, i){
|
|
428
|
+
return '<span class="chip"><span class="rank">' + (i+1) + '</span>' + esc(s) + '</span>';
|
|
429
|
+
}).join('');
|
|
430
|
+
var head = '<div class="row-head"><span class="label">' + esc(l.persona) +
|
|
431
|
+
'</span><span class="val">reward ' + (Number(l.avgReward)||0).toFixed(2) + '</span></div>';
|
|
432
|
+
return '<div class="row">' + head +
|
|
433
|
+
'<div class="track"><span class="bar" style="width:' + clampPct((l.avgReward||0)/max*100) + '%"></span></div>' +
|
|
434
|
+
'<div class="chips">' + order + '</div>' +
|
|
435
|
+
'<div class="meta">' + (l.pulls || 0) + ' pulls</div></div>';
|
|
436
|
+
}).join('');
|
|
437
|
+
};
|
|
438
|
+
`
|
|
439
|
+
};
|
|
440
|
+
function buildTemplate(id) {
|
|
441
|
+
const title = VIZ_TITLES[id];
|
|
442
|
+
return `<!doctype html>
|
|
443
|
+
<html lang="en">
|
|
444
|
+
<head>
|
|
445
|
+
<meta charset="utf-8">
|
|
446
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
447
|
+
<title>${title} \u2014 SentientUI</title>
|
|
448
|
+
<style>${SHARED_CSS}</style>
|
|
449
|
+
</head>
|
|
450
|
+
<body class="viz-root">
|
|
451
|
+
<h1>${title}</h1>
|
|
452
|
+
<p class="sub" id="sub">Waiting for data\u2026</p>
|
|
453
|
+
<div class="rows" id="viz"><div class="empty">Loading\u2026</div></div>
|
|
454
|
+
<p class="foot">SentientUI \xB7 rendered by your agent host</p>
|
|
455
|
+
<script>
|
|
456
|
+
${HELPERS_JS}
|
|
457
|
+
${RENDER_JS[id]}
|
|
458
|
+
${BOOTSTRAP_JS}
|
|
459
|
+
</script>
|
|
460
|
+
</body>
|
|
461
|
+
</html>`;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/ui/index.ts
|
|
465
|
+
var UI_TOOL_VIZ = {
|
|
466
|
+
get_persona_breakdown: "persona-breakdown",
|
|
467
|
+
get_variant_performance: "variant-performance",
|
|
468
|
+
get_goal_funnel: "goal-funnel",
|
|
469
|
+
get_layout_stats: "layout-stats"
|
|
470
|
+
};
|
|
471
|
+
function uiResourceUri(id) {
|
|
472
|
+
return `ui://sentientui/${id}`;
|
|
473
|
+
}
|
|
474
|
+
function uiMeta(id) {
|
|
475
|
+
const uri = uiResourceUri(id);
|
|
476
|
+
return {
|
|
477
|
+
ui: {
|
|
478
|
+
resourceUri: uri,
|
|
479
|
+
preferredFrameSize: ["720px", "480px"]
|
|
480
|
+
},
|
|
481
|
+
"openai/outputTemplate": uri
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function registerUiResources(server) {
|
|
485
|
+
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
486
|
+
server.registerResource(
|
|
487
|
+
id,
|
|
488
|
+
uiResourceUri(id),
|
|
489
|
+
{
|
|
490
|
+
title: `${VIZ_TITLES[id]} (UI)`,
|
|
491
|
+
description: `Interactive ${VIZ_TITLES[id]} view for agent hosts that support MCP UI.`,
|
|
492
|
+
mimeType: "text/html"
|
|
493
|
+
},
|
|
494
|
+
async (uri) => ({
|
|
495
|
+
contents: [
|
|
496
|
+
{
|
|
497
|
+
uri: uri.href,
|
|
498
|
+
mimeType: "text/html",
|
|
499
|
+
text: buildTemplate(id)
|
|
500
|
+
}
|
|
501
|
+
]
|
|
502
|
+
})
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// src/tools/components.ts
|
|
251
508
|
var projectIdSchema2 = import_zod2.z.string().uuid().describe("The project UUID");
|
|
252
509
|
function registerComponentTools(server, client) {
|
|
253
510
|
server.registerTool(
|
|
@@ -301,6 +558,7 @@ function registerComponentTools(server, client) {
|
|
|
301
558
|
title: "Variant performance",
|
|
302
559
|
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
|
|
303
560
|
inputSchema: { projectId: projectIdSchema2 },
|
|
561
|
+
_meta: uiMeta("variant-performance"),
|
|
304
562
|
outputSchema: {
|
|
305
563
|
variants: import_zod2.z.array(
|
|
306
564
|
import_zod2.z.object({
|
|
@@ -334,13 +592,14 @@ function registerComponentTools(server, client) {
|
|
|
334
592
|
if (!data.cvr?.length) {
|
|
335
593
|
return {
|
|
336
594
|
content: [{ type: "text", text: "No variant data available yet." }],
|
|
337
|
-
structuredContent
|
|
595
|
+
structuredContent,
|
|
596
|
+
_meta: uiMeta("variant-performance")
|
|
338
597
|
};
|
|
339
598
|
}
|
|
340
599
|
const text = data.cvr.map(
|
|
341
600
|
(v) => `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${momentumMap.get(v.variantId) ?? "stable"})`
|
|
342
601
|
).join("\n");
|
|
343
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
602
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
344
603
|
}
|
|
345
604
|
);
|
|
346
605
|
}
|
|
@@ -420,6 +679,7 @@ function registerPersonaTools(server, client) {
|
|
|
420
679
|
title: "Persona breakdown",
|
|
421
680
|
description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
|
|
422
681
|
inputSchema: { projectId: projectIdSchema4 },
|
|
682
|
+
_meta: uiMeta("persona-breakdown"),
|
|
423
683
|
outputSchema: {
|
|
424
684
|
totalSessions: import_zod4.z.number().describe("Total sessions across all clusters"),
|
|
425
685
|
clusters: import_zod4.z.array(
|
|
@@ -452,7 +712,8 @@ function registerPersonaTools(server, client) {
|
|
|
452
712
|
if (!data.clusters.length) {
|
|
453
713
|
return {
|
|
454
714
|
content: [{ type: "text", text: "No persona clusters yet. More visitor data is needed." }],
|
|
455
|
-
structuredContent
|
|
715
|
+
structuredContent,
|
|
716
|
+
_meta: uiMeta("persona-breakdown")
|
|
456
717
|
};
|
|
457
718
|
}
|
|
458
719
|
const lines = [
|
|
@@ -464,7 +725,7 @@ function registerPersonaTools(server, client) {
|
|
|
464
725
|
return `- ${c.label}: ${c.sessionCount} sessions (${pct.toFixed(1)}% of traffic, reliability ${(c.avgReliability * 100).toFixed(0)}%)`;
|
|
465
726
|
})
|
|
466
727
|
];
|
|
467
|
-
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
|
|
728
|
+
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
|
|
468
729
|
}
|
|
469
730
|
);
|
|
470
731
|
}
|
|
@@ -479,6 +740,7 @@ function registerGoalTools(server, client) {
|
|
|
479
740
|
title: "Goal funnel",
|
|
480
741
|
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
|
|
481
742
|
inputSchema: { projectId: projectIdSchema5 },
|
|
743
|
+
_meta: uiMeta("goal-funnel"),
|
|
482
744
|
outputSchema: {
|
|
483
745
|
goals: import_zod5.z.array(
|
|
484
746
|
import_zod5.z.object({
|
|
@@ -521,7 +783,8 @@ function registerGoalTools(server, client) {
|
|
|
521
783
|
if (!data.goals.length) {
|
|
522
784
|
return {
|
|
523
785
|
content: [{ type: "text", text: "No goals configured for this project." }],
|
|
524
|
-
structuredContent
|
|
786
|
+
structuredContent,
|
|
787
|
+
_meta: uiMeta("goal-funnel")
|
|
525
788
|
};
|
|
526
789
|
}
|
|
527
790
|
const lines = data.goals.flatMap((g) => [
|
|
@@ -529,7 +792,7 @@ function registerGoalTools(server, client) {
|
|
|
529
792
|
...g.variants.map((v) => ` ${v.componentId}/${v.variantId}: ${(v.completionRate * 100).toFixed(1)}% per assigned session`),
|
|
530
793
|
""
|
|
531
794
|
]);
|
|
532
|
-
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent };
|
|
795
|
+
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
533
796
|
}
|
|
534
797
|
);
|
|
535
798
|
}
|
|
@@ -593,6 +856,7 @@ function registerLayoutTools(server, client) {
|
|
|
593
856
|
title: "Layout stats",
|
|
594
857
|
description: "Get per-persona section layout rankings and bandit reward weights.",
|
|
595
858
|
inputSchema: { projectId: projectIdSchema7 },
|
|
859
|
+
_meta: uiMeta("layout-stats"),
|
|
596
860
|
outputSchema: {
|
|
597
861
|
layouts: import_zod7.z.array(
|
|
598
862
|
import_zod7.z.object({
|
|
@@ -623,13 +887,14 @@ function registerLayoutTools(server, client) {
|
|
|
623
887
|
if (!stats.length) {
|
|
624
888
|
return {
|
|
625
889
|
content: [{ type: "text", text: "No layout data yet. More visitor sessions are needed." }],
|
|
626
|
-
structuredContent
|
|
890
|
+
structuredContent,
|
|
891
|
+
_meta: uiMeta("layout-stats")
|
|
627
892
|
};
|
|
628
893
|
}
|
|
629
894
|
const text = stats.map(
|
|
630
895
|
(s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
|
|
631
896
|
).join("\n");
|
|
632
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
897
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
|
|
633
898
|
}
|
|
634
899
|
);
|
|
635
900
|
}
|
|
@@ -1150,6 +1415,7 @@ function createMcpServer(client) {
|
|
|
1150
1415
|
name: "@sentientui/mcp",
|
|
1151
1416
|
version: PKG_VERSION
|
|
1152
1417
|
});
|
|
1418
|
+
registerUiResources(server);
|
|
1153
1419
|
registerProjectTools(server, client);
|
|
1154
1420
|
registerComponentTools(server, client);
|
|
1155
1421
|
registerInsightTools(server, client);
|
package/dist/lib.js
CHANGED