@sentientui/mcp 0.5.2 → 0.6.1
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-OQ2K3O7A.js} +294 -12
- package/dist/index.cjs +294 -12
- package/dist/index.js +1 -1
- package/dist/lib.cjs +294 -12
- package/dist/lib.js +1 -1
- package/package.json +1 -1
|
@@ -215,6 +215,264 @@ 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 RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
433
|
+
var UI_TOOL_VIZ = {
|
|
434
|
+
get_persona_breakdown: "persona-breakdown",
|
|
435
|
+
get_variant_performance: "variant-performance",
|
|
436
|
+
get_goal_funnel: "goal-funnel",
|
|
437
|
+
get_layout_stats: "layout-stats"
|
|
438
|
+
};
|
|
439
|
+
function uiResourceUri(id) {
|
|
440
|
+
return `ui://sentientui/${id}`;
|
|
441
|
+
}
|
|
442
|
+
function uiMeta(id) {
|
|
443
|
+
const uri = uiResourceUri(id);
|
|
444
|
+
return {
|
|
445
|
+
ui: {
|
|
446
|
+
resourceUri: uri,
|
|
447
|
+
preferredFrameSize: ["720px", "480px"]
|
|
448
|
+
},
|
|
449
|
+
"openai/outputTemplate": uri
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
function registerUiResources(server) {
|
|
453
|
+
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
454
|
+
server.registerResource(
|
|
455
|
+
id,
|
|
456
|
+
uiResourceUri(id),
|
|
457
|
+
{
|
|
458
|
+
title: `${VIZ_TITLES[id]} (UI)`,
|
|
459
|
+
description: `Interactive ${VIZ_TITLES[id]} view for agent hosts that support MCP UI.`,
|
|
460
|
+
mimeType: RESOURCE_MIME_TYPE
|
|
461
|
+
},
|
|
462
|
+
async (uri) => ({
|
|
463
|
+
contents: [
|
|
464
|
+
{
|
|
465
|
+
uri: uri.href,
|
|
466
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
467
|
+
text: buildTemplate(id)
|
|
468
|
+
}
|
|
469
|
+
]
|
|
470
|
+
})
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/tools/components.ts
|
|
218
476
|
var projectIdSchema2 = z2.string().uuid().describe("The project UUID");
|
|
219
477
|
function registerComponentTools(server, client) {
|
|
220
478
|
server.registerTool(
|
|
@@ -268,6 +526,7 @@ function registerComponentTools(server, client) {
|
|
|
268
526
|
title: "Variant performance",
|
|
269
527
|
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
|
|
270
528
|
inputSchema: { projectId: projectIdSchema2 },
|
|
529
|
+
_meta: uiMeta("variant-performance"),
|
|
271
530
|
outputSchema: {
|
|
272
531
|
variants: z2.array(
|
|
273
532
|
z2.object({
|
|
@@ -301,13 +560,14 @@ function registerComponentTools(server, client) {
|
|
|
301
560
|
if (!data.cvr?.length) {
|
|
302
561
|
return {
|
|
303
562
|
content: [{ type: "text", text: "No variant data available yet." }],
|
|
304
|
-
structuredContent
|
|
563
|
+
structuredContent,
|
|
564
|
+
_meta: uiMeta("variant-performance")
|
|
305
565
|
};
|
|
306
566
|
}
|
|
307
567
|
const text = data.cvr.map(
|
|
308
568
|
(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
569
|
).join("\n");
|
|
310
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
570
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
311
571
|
}
|
|
312
572
|
);
|
|
313
573
|
}
|
|
@@ -387,6 +647,7 @@ function registerPersonaTools(server, client) {
|
|
|
387
647
|
title: "Persona breakdown",
|
|
388
648
|
description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
|
|
389
649
|
inputSchema: { projectId: projectIdSchema4 },
|
|
650
|
+
_meta: uiMeta("persona-breakdown"),
|
|
390
651
|
outputSchema: {
|
|
391
652
|
totalSessions: z4.number().describe("Total sessions across all clusters"),
|
|
392
653
|
clusters: z4.array(
|
|
@@ -419,7 +680,8 @@ function registerPersonaTools(server, client) {
|
|
|
419
680
|
if (!data.clusters.length) {
|
|
420
681
|
return {
|
|
421
682
|
content: [{ type: "text", text: "No persona clusters yet. More visitor data is needed." }],
|
|
422
|
-
structuredContent
|
|
683
|
+
structuredContent,
|
|
684
|
+
_meta: uiMeta("persona-breakdown")
|
|
423
685
|
};
|
|
424
686
|
}
|
|
425
687
|
const lines = [
|
|
@@ -431,7 +693,7 @@ function registerPersonaTools(server, client) {
|
|
|
431
693
|
return `- ${c.label}: ${c.sessionCount} sessions (${pct.toFixed(1)}% of traffic, reliability ${(c.avgReliability * 100).toFixed(0)}%)`;
|
|
432
694
|
})
|
|
433
695
|
];
|
|
434
|
-
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
|
|
696
|
+
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
|
|
435
697
|
}
|
|
436
698
|
);
|
|
437
699
|
}
|
|
@@ -446,6 +708,7 @@ function registerGoalTools(server, client) {
|
|
|
446
708
|
title: "Goal funnel",
|
|
447
709
|
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
|
|
448
710
|
inputSchema: { projectId: projectIdSchema5 },
|
|
711
|
+
_meta: uiMeta("goal-funnel"),
|
|
449
712
|
outputSchema: {
|
|
450
713
|
goals: z5.array(
|
|
451
714
|
z5.object({
|
|
@@ -488,7 +751,8 @@ function registerGoalTools(server, client) {
|
|
|
488
751
|
if (!data.goals.length) {
|
|
489
752
|
return {
|
|
490
753
|
content: [{ type: "text", text: "No goals configured for this project." }],
|
|
491
|
-
structuredContent
|
|
754
|
+
structuredContent,
|
|
755
|
+
_meta: uiMeta("goal-funnel")
|
|
492
756
|
};
|
|
493
757
|
}
|
|
494
758
|
const lines = data.goals.flatMap((g) => [
|
|
@@ -496,7 +760,7 @@ function registerGoalTools(server, client) {
|
|
|
496
760
|
...g.variants.map((v) => ` ${v.componentId}/${v.variantId}: ${(v.completionRate * 100).toFixed(1)}% per assigned session`),
|
|
497
761
|
""
|
|
498
762
|
]);
|
|
499
|
-
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent };
|
|
763
|
+
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
500
764
|
}
|
|
501
765
|
);
|
|
502
766
|
}
|
|
@@ -560,6 +824,7 @@ function registerLayoutTools(server, client) {
|
|
|
560
824
|
title: "Layout stats",
|
|
561
825
|
description: "Get per-persona section layout rankings and bandit reward weights.",
|
|
562
826
|
inputSchema: { projectId: projectIdSchema7 },
|
|
827
|
+
_meta: uiMeta("layout-stats"),
|
|
563
828
|
outputSchema: {
|
|
564
829
|
layouts: z7.array(
|
|
565
830
|
z7.object({
|
|
@@ -590,13 +855,14 @@ function registerLayoutTools(server, client) {
|
|
|
590
855
|
if (!stats.length) {
|
|
591
856
|
return {
|
|
592
857
|
content: [{ type: "text", text: "No layout data yet. More visitor sessions are needed." }],
|
|
593
|
-
structuredContent
|
|
858
|
+
structuredContent,
|
|
859
|
+
_meta: uiMeta("layout-stats")
|
|
594
860
|
};
|
|
595
861
|
}
|
|
596
862
|
const text = stats.map(
|
|
597
863
|
(s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
|
|
598
864
|
).join("\n");
|
|
599
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
865
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
|
|
600
866
|
}
|
|
601
867
|
);
|
|
602
868
|
}
|
|
@@ -1113,10 +1379,26 @@ function registerIntegrationGuideTools(server) {
|
|
|
1113
1379
|
// src/server.ts
|
|
1114
1380
|
var { version: PKG_VERSION } = createRequire(import.meta.url)("../package.json");
|
|
1115
1381
|
function createMcpServer(client) {
|
|
1116
|
-
const server = new McpServer(
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1382
|
+
const server = new McpServer(
|
|
1383
|
+
{
|
|
1384
|
+
name: "@sentientui/mcp",
|
|
1385
|
+
version: PKG_VERSION
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
// MCP Apps (SEP-1865): advertise the `io.modelcontextprotocol/ui` extension
|
|
1389
|
+
// in the initialize handshake so UI-capable hosts and agent-readiness
|
|
1390
|
+
// scanners negotiate it. Merged with the tools/resources capabilities the
|
|
1391
|
+
// SDK adds as they're registered below.
|
|
1392
|
+
capabilities: {
|
|
1393
|
+
extensions: {
|
|
1394
|
+
"io.modelcontextprotocol/ui": {
|
|
1395
|
+
mimeTypes: [RESOURCE_MIME_TYPE]
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
);
|
|
1401
|
+
registerUiResources(server);
|
|
1120
1402
|
registerProjectTools(server, client);
|
|
1121
1403
|
registerComponentTools(server, client);
|
|
1122
1404
|
registerInsightTools(server, client);
|
package/dist/index.cjs
CHANGED
|
@@ -223,6 +223,264 @@ 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 RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
441
|
+
var UI_TOOL_VIZ = {
|
|
442
|
+
get_persona_breakdown: "persona-breakdown",
|
|
443
|
+
get_variant_performance: "variant-performance",
|
|
444
|
+
get_goal_funnel: "goal-funnel",
|
|
445
|
+
get_layout_stats: "layout-stats"
|
|
446
|
+
};
|
|
447
|
+
function uiResourceUri(id) {
|
|
448
|
+
return `ui://sentientui/${id}`;
|
|
449
|
+
}
|
|
450
|
+
function uiMeta(id) {
|
|
451
|
+
const uri = uiResourceUri(id);
|
|
452
|
+
return {
|
|
453
|
+
ui: {
|
|
454
|
+
resourceUri: uri,
|
|
455
|
+
preferredFrameSize: ["720px", "480px"]
|
|
456
|
+
},
|
|
457
|
+
"openai/outputTemplate": uri
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function registerUiResources(server) {
|
|
461
|
+
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
462
|
+
server.registerResource(
|
|
463
|
+
id,
|
|
464
|
+
uiResourceUri(id),
|
|
465
|
+
{
|
|
466
|
+
title: `${VIZ_TITLES[id]} (UI)`,
|
|
467
|
+
description: `Interactive ${VIZ_TITLES[id]} view for agent hosts that support MCP UI.`,
|
|
468
|
+
mimeType: RESOURCE_MIME_TYPE
|
|
469
|
+
},
|
|
470
|
+
async (uri) => ({
|
|
471
|
+
contents: [
|
|
472
|
+
{
|
|
473
|
+
uri: uri.href,
|
|
474
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
475
|
+
text: buildTemplate(id)
|
|
476
|
+
}
|
|
477
|
+
]
|
|
478
|
+
})
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/tools/components.ts
|
|
226
484
|
var projectIdSchema2 = import_zod2.z.string().uuid().describe("The project UUID");
|
|
227
485
|
function registerComponentTools(server, client) {
|
|
228
486
|
server.registerTool(
|
|
@@ -276,6 +534,7 @@ function registerComponentTools(server, client) {
|
|
|
276
534
|
title: "Variant performance",
|
|
277
535
|
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
|
|
278
536
|
inputSchema: { projectId: projectIdSchema2 },
|
|
537
|
+
_meta: uiMeta("variant-performance"),
|
|
279
538
|
outputSchema: {
|
|
280
539
|
variants: import_zod2.z.array(
|
|
281
540
|
import_zod2.z.object({
|
|
@@ -309,13 +568,14 @@ function registerComponentTools(server, client) {
|
|
|
309
568
|
if (!data.cvr?.length) {
|
|
310
569
|
return {
|
|
311
570
|
content: [{ type: "text", text: "No variant data available yet." }],
|
|
312
|
-
structuredContent
|
|
571
|
+
structuredContent,
|
|
572
|
+
_meta: uiMeta("variant-performance")
|
|
313
573
|
};
|
|
314
574
|
}
|
|
315
575
|
const text = data.cvr.map(
|
|
316
576
|
(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
577
|
).join("\n");
|
|
318
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
578
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
319
579
|
}
|
|
320
580
|
);
|
|
321
581
|
}
|
|
@@ -395,6 +655,7 @@ function registerPersonaTools(server, client) {
|
|
|
395
655
|
title: "Persona breakdown",
|
|
396
656
|
description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
|
|
397
657
|
inputSchema: { projectId: projectIdSchema4 },
|
|
658
|
+
_meta: uiMeta("persona-breakdown"),
|
|
398
659
|
outputSchema: {
|
|
399
660
|
totalSessions: import_zod4.z.number().describe("Total sessions across all clusters"),
|
|
400
661
|
clusters: import_zod4.z.array(
|
|
@@ -427,7 +688,8 @@ function registerPersonaTools(server, client) {
|
|
|
427
688
|
if (!data.clusters.length) {
|
|
428
689
|
return {
|
|
429
690
|
content: [{ type: "text", text: "No persona clusters yet. More visitor data is needed." }],
|
|
430
|
-
structuredContent
|
|
691
|
+
structuredContent,
|
|
692
|
+
_meta: uiMeta("persona-breakdown")
|
|
431
693
|
};
|
|
432
694
|
}
|
|
433
695
|
const lines = [
|
|
@@ -439,7 +701,7 @@ function registerPersonaTools(server, client) {
|
|
|
439
701
|
return `- ${c.label}: ${c.sessionCount} sessions (${pct.toFixed(1)}% of traffic, reliability ${(c.avgReliability * 100).toFixed(0)}%)`;
|
|
440
702
|
})
|
|
441
703
|
];
|
|
442
|
-
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
|
|
704
|
+
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
|
|
443
705
|
}
|
|
444
706
|
);
|
|
445
707
|
}
|
|
@@ -454,6 +716,7 @@ function registerGoalTools(server, client) {
|
|
|
454
716
|
title: "Goal funnel",
|
|
455
717
|
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
|
|
456
718
|
inputSchema: { projectId: projectIdSchema5 },
|
|
719
|
+
_meta: uiMeta("goal-funnel"),
|
|
457
720
|
outputSchema: {
|
|
458
721
|
goals: import_zod5.z.array(
|
|
459
722
|
import_zod5.z.object({
|
|
@@ -496,7 +759,8 @@ function registerGoalTools(server, client) {
|
|
|
496
759
|
if (!data.goals.length) {
|
|
497
760
|
return {
|
|
498
761
|
content: [{ type: "text", text: "No goals configured for this project." }],
|
|
499
|
-
structuredContent
|
|
762
|
+
structuredContent,
|
|
763
|
+
_meta: uiMeta("goal-funnel")
|
|
500
764
|
};
|
|
501
765
|
}
|
|
502
766
|
const lines = data.goals.flatMap((g) => [
|
|
@@ -504,7 +768,7 @@ function registerGoalTools(server, client) {
|
|
|
504
768
|
...g.variants.map((v) => ` ${v.componentId}/${v.variantId}: ${(v.completionRate * 100).toFixed(1)}% per assigned session`),
|
|
505
769
|
""
|
|
506
770
|
]);
|
|
507
|
-
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent };
|
|
771
|
+
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
508
772
|
}
|
|
509
773
|
);
|
|
510
774
|
}
|
|
@@ -568,6 +832,7 @@ function registerLayoutTools(server, client) {
|
|
|
568
832
|
title: "Layout stats",
|
|
569
833
|
description: "Get per-persona section layout rankings and bandit reward weights.",
|
|
570
834
|
inputSchema: { projectId: projectIdSchema7 },
|
|
835
|
+
_meta: uiMeta("layout-stats"),
|
|
571
836
|
outputSchema: {
|
|
572
837
|
layouts: import_zod7.z.array(
|
|
573
838
|
import_zod7.z.object({
|
|
@@ -598,13 +863,14 @@ function registerLayoutTools(server, client) {
|
|
|
598
863
|
if (!stats.length) {
|
|
599
864
|
return {
|
|
600
865
|
content: [{ type: "text", text: "No layout data yet. More visitor sessions are needed." }],
|
|
601
|
-
structuredContent
|
|
866
|
+
structuredContent,
|
|
867
|
+
_meta: uiMeta("layout-stats")
|
|
602
868
|
};
|
|
603
869
|
}
|
|
604
870
|
const text = stats.map(
|
|
605
871
|
(s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
|
|
606
872
|
).join("\n");
|
|
607
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
873
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
|
|
608
874
|
}
|
|
609
875
|
);
|
|
610
876
|
}
|
|
@@ -1121,10 +1387,26 @@ function registerIntegrationGuideTools(server) {
|
|
|
1121
1387
|
// src/server.ts
|
|
1122
1388
|
var { version: PKG_VERSION } = (0, import_node_module.createRequire)(importMetaUrl)("../package.json");
|
|
1123
1389
|
function createMcpServer(client) {
|
|
1124
|
-
const server = new import_mcp.McpServer(
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1390
|
+
const server = new import_mcp.McpServer(
|
|
1391
|
+
{
|
|
1392
|
+
name: "@sentientui/mcp",
|
|
1393
|
+
version: PKG_VERSION
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
// MCP Apps (SEP-1865): advertise the `io.modelcontextprotocol/ui` extension
|
|
1397
|
+
// in the initialize handshake so UI-capable hosts and agent-readiness
|
|
1398
|
+
// scanners negotiate it. Merged with the tools/resources capabilities the
|
|
1399
|
+
// SDK adds as they're registered below.
|
|
1400
|
+
capabilities: {
|
|
1401
|
+
extensions: {
|
|
1402
|
+
"io.modelcontextprotocol/ui": {
|
|
1403
|
+
mimeTypes: [RESOURCE_MIME_TYPE]
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
);
|
|
1409
|
+
registerUiResources(server);
|
|
1128
1410
|
registerProjectTools(server, client);
|
|
1129
1411
|
registerComponentTools(server, client);
|
|
1130
1412
|
registerInsightTools(server, client);
|
package/dist/index.js
CHANGED
package/dist/lib.cjs
CHANGED
|
@@ -248,6 +248,264 @@ 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 RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
466
|
+
var UI_TOOL_VIZ = {
|
|
467
|
+
get_persona_breakdown: "persona-breakdown",
|
|
468
|
+
get_variant_performance: "variant-performance",
|
|
469
|
+
get_goal_funnel: "goal-funnel",
|
|
470
|
+
get_layout_stats: "layout-stats"
|
|
471
|
+
};
|
|
472
|
+
function uiResourceUri(id) {
|
|
473
|
+
return `ui://sentientui/${id}`;
|
|
474
|
+
}
|
|
475
|
+
function uiMeta(id) {
|
|
476
|
+
const uri = uiResourceUri(id);
|
|
477
|
+
return {
|
|
478
|
+
ui: {
|
|
479
|
+
resourceUri: uri,
|
|
480
|
+
preferredFrameSize: ["720px", "480px"]
|
|
481
|
+
},
|
|
482
|
+
"openai/outputTemplate": uri
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function registerUiResources(server) {
|
|
486
|
+
for (const id of Object.values(UI_TOOL_VIZ)) {
|
|
487
|
+
server.registerResource(
|
|
488
|
+
id,
|
|
489
|
+
uiResourceUri(id),
|
|
490
|
+
{
|
|
491
|
+
title: `${VIZ_TITLES[id]} (UI)`,
|
|
492
|
+
description: `Interactive ${VIZ_TITLES[id]} view for agent hosts that support MCP UI.`,
|
|
493
|
+
mimeType: RESOURCE_MIME_TYPE
|
|
494
|
+
},
|
|
495
|
+
async (uri) => ({
|
|
496
|
+
contents: [
|
|
497
|
+
{
|
|
498
|
+
uri: uri.href,
|
|
499
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
500
|
+
text: buildTemplate(id)
|
|
501
|
+
}
|
|
502
|
+
]
|
|
503
|
+
})
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/tools/components.ts
|
|
251
509
|
var projectIdSchema2 = import_zod2.z.string().uuid().describe("The project UUID");
|
|
252
510
|
function registerComponentTools(server, client) {
|
|
253
511
|
server.registerTool(
|
|
@@ -301,6 +559,7 @@ function registerComponentTools(server, client) {
|
|
|
301
559
|
title: "Variant performance",
|
|
302
560
|
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7 days.",
|
|
303
561
|
inputSchema: { projectId: projectIdSchema2 },
|
|
562
|
+
_meta: uiMeta("variant-performance"),
|
|
304
563
|
outputSchema: {
|
|
305
564
|
variants: import_zod2.z.array(
|
|
306
565
|
import_zod2.z.object({
|
|
@@ -334,13 +593,14 @@ function registerComponentTools(server, client) {
|
|
|
334
593
|
if (!data.cvr?.length) {
|
|
335
594
|
return {
|
|
336
595
|
content: [{ type: "text", text: "No variant data available yet." }],
|
|
337
|
-
structuredContent
|
|
596
|
+
structuredContent,
|
|
597
|
+
_meta: uiMeta("variant-performance")
|
|
338
598
|
};
|
|
339
599
|
}
|
|
340
600
|
const text = data.cvr.map(
|
|
341
601
|
(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
602
|
).join("\n");
|
|
343
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
603
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
344
604
|
}
|
|
345
605
|
);
|
|
346
606
|
}
|
|
@@ -420,6 +680,7 @@ function registerPersonaTools(server, client) {
|
|
|
420
680
|
title: "Persona breakdown",
|
|
421
681
|
description: "Get the distribution of visitor persona clusters with session counts and reliability scores.",
|
|
422
682
|
inputSchema: { projectId: projectIdSchema4 },
|
|
683
|
+
_meta: uiMeta("persona-breakdown"),
|
|
423
684
|
outputSchema: {
|
|
424
685
|
totalSessions: import_zod4.z.number().describe("Total sessions across all clusters"),
|
|
425
686
|
clusters: import_zod4.z.array(
|
|
@@ -452,7 +713,8 @@ function registerPersonaTools(server, client) {
|
|
|
452
713
|
if (!data.clusters.length) {
|
|
453
714
|
return {
|
|
454
715
|
content: [{ type: "text", text: "No persona clusters yet. More visitor data is needed." }],
|
|
455
|
-
structuredContent
|
|
716
|
+
structuredContent,
|
|
717
|
+
_meta: uiMeta("persona-breakdown")
|
|
456
718
|
};
|
|
457
719
|
}
|
|
458
720
|
const lines = [
|
|
@@ -464,7 +726,7 @@ function registerPersonaTools(server, client) {
|
|
|
464
726
|
return `- ${c.label}: ${c.sessionCount} sessions (${pct.toFixed(1)}% of traffic, reliability ${(c.avgReliability * 100).toFixed(0)}%)`;
|
|
465
727
|
})
|
|
466
728
|
];
|
|
467
|
-
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
|
|
729
|
+
return { content: [{ type: "text", text: lines.join("\n") }], structuredContent, _meta: uiMeta("persona-breakdown") };
|
|
468
730
|
}
|
|
469
731
|
);
|
|
470
732
|
}
|
|
@@ -479,6 +741,7 @@ function registerGoalTools(server, client) {
|
|
|
479
741
|
title: "Goal funnel",
|
|
480
742
|
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
|
|
481
743
|
inputSchema: { projectId: projectIdSchema5 },
|
|
744
|
+
_meta: uiMeta("goal-funnel"),
|
|
482
745
|
outputSchema: {
|
|
483
746
|
goals: import_zod5.z.array(
|
|
484
747
|
import_zod5.z.object({
|
|
@@ -521,7 +784,8 @@ function registerGoalTools(server, client) {
|
|
|
521
784
|
if (!data.goals.length) {
|
|
522
785
|
return {
|
|
523
786
|
content: [{ type: "text", text: "No goals configured for this project." }],
|
|
524
|
-
structuredContent
|
|
787
|
+
structuredContent,
|
|
788
|
+
_meta: uiMeta("goal-funnel")
|
|
525
789
|
};
|
|
526
790
|
}
|
|
527
791
|
const lines = data.goals.flatMap((g) => [
|
|
@@ -529,7 +793,7 @@ function registerGoalTools(server, client) {
|
|
|
529
793
|
...g.variants.map((v) => ` ${v.componentId}/${v.variantId}: ${(v.completionRate * 100).toFixed(1)}% per assigned session`),
|
|
530
794
|
""
|
|
531
795
|
]);
|
|
532
|
-
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent };
|
|
796
|
+
return { content: [{ type: "text", text: lines.join("\n").trim() }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
533
797
|
}
|
|
534
798
|
);
|
|
535
799
|
}
|
|
@@ -593,6 +857,7 @@ function registerLayoutTools(server, client) {
|
|
|
593
857
|
title: "Layout stats",
|
|
594
858
|
description: "Get per-persona section layout rankings and bandit reward weights.",
|
|
595
859
|
inputSchema: { projectId: projectIdSchema7 },
|
|
860
|
+
_meta: uiMeta("layout-stats"),
|
|
596
861
|
outputSchema: {
|
|
597
862
|
layouts: import_zod7.z.array(
|
|
598
863
|
import_zod7.z.object({
|
|
@@ -623,13 +888,14 @@ function registerLayoutTools(server, client) {
|
|
|
623
888
|
if (!stats.length) {
|
|
624
889
|
return {
|
|
625
890
|
content: [{ type: "text", text: "No layout data yet. More visitor sessions are needed." }],
|
|
626
|
-
structuredContent
|
|
891
|
+
structuredContent,
|
|
892
|
+
_meta: uiMeta("layout-stats")
|
|
627
893
|
};
|
|
628
894
|
}
|
|
629
895
|
const text = stats.map(
|
|
630
896
|
(s) => `- ${s.persona}: [${s.layoutOrder.join(" \u2192 ")}] (avg reward: ${s.avgReward.toFixed(2)}, ${s.pulls} pulls)`
|
|
631
897
|
).join("\n");
|
|
632
|
-
return { content: [{ type: "text", text }], structuredContent };
|
|
898
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("layout-stats") };
|
|
633
899
|
}
|
|
634
900
|
);
|
|
635
901
|
}
|
|
@@ -1146,10 +1412,26 @@ function registerIntegrationGuideTools(server) {
|
|
|
1146
1412
|
// src/server.ts
|
|
1147
1413
|
var { version: PKG_VERSION } = (0, import_node_module.createRequire)(importMetaUrl)("../package.json");
|
|
1148
1414
|
function createMcpServer(client) {
|
|
1149
|
-
const server = new import_mcp.McpServer(
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1415
|
+
const server = new import_mcp.McpServer(
|
|
1416
|
+
{
|
|
1417
|
+
name: "@sentientui/mcp",
|
|
1418
|
+
version: PKG_VERSION
|
|
1419
|
+
},
|
|
1420
|
+
{
|
|
1421
|
+
// MCP Apps (SEP-1865): advertise the `io.modelcontextprotocol/ui` extension
|
|
1422
|
+
// in the initialize handshake so UI-capable hosts and agent-readiness
|
|
1423
|
+
// scanners negotiate it. Merged with the tools/resources capabilities the
|
|
1424
|
+
// SDK adds as they're registered below.
|
|
1425
|
+
capabilities: {
|
|
1426
|
+
extensions: {
|
|
1427
|
+
"io.modelcontextprotocol/ui": {
|
|
1428
|
+
mimeTypes: [RESOURCE_MIME_TYPE]
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
);
|
|
1434
|
+
registerUiResources(server);
|
|
1153
1435
|
registerProjectTools(server, client);
|
|
1154
1436
|
registerComponentTools(server, client);
|
|
1155
1437
|
registerInsightTools(server, client);
|
package/dist/lib.js
CHANGED