@sentientui/mcp 0.16.0 → 0.17.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/AGENTS.md +1 -1
- package/README.md +2 -2
- package/dist/{chunk-SUMKFRQP.js → chunk-KT2ZKW7I.js} +106 -32
- package/dist/index.cjs +106 -32
- package/dist/index.js +1 -1
- package/dist/lib.cjs +106 -32
- package/dist/lib.js +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -33,7 +33,7 @@ Server keys start with `sk_` — required for the management API. Public keys (`
|
|
|
33
33
|
| `create_project` | Onboard a new user: creates a project + returns its `pk_` key. Needs an account login (OAuth) — refuses `sk_` project keys and demo tokens. Follow with `get_integration_guide` |
|
|
34
34
|
| `get_project_stats` | Health status + 24h event/session volume |
|
|
35
35
|
| `list_components` | Components + variant counts + impression totals |
|
|
36
|
-
| `get_variant_performance` | CVR
|
|
36
|
+
| `get_variant_performance` | CVR current vs prior window + momentum (range/from/to params; default 7d) |
|
|
37
37
|
| `get_persona_breakdown` | Cluster distribution + avg reliability per cluster |
|
|
38
38
|
| `get_goal_funnel` | Goal hit counts + per-variant completion rates |
|
|
39
39
|
| `list_guardrail_events` | Auto-paused variants (last 24h) |
|
package/README.md
CHANGED
|
@@ -88,11 +88,11 @@ A sandboxed demo token is provisioned automatically — 10 calls/month, read-onl
|
|
|
88
88
|
| `create_project` | Create a new project and return its `pk_` public key (account login required — not usable with an `sk_` project key or demo token) |
|
|
89
89
|
| `get_project_stats` | Events, sessions, agent calls, and health status |
|
|
90
90
|
| `list_components` | All adaptive components with variant counts |
|
|
91
|
-
| `get_variant_performance` | CVR, momentum, and impressions per variant (7d vs prior 7d) |
|
|
91
|
+
| `get_variant_performance` | CVR, momentum, and impressions per variant (windowed: range 7d/30d/90d/all or from/to; default 7d vs prior 7d) |
|
|
92
92
|
| `get_insights` | AI-generated narrator observations and advisor recommendations |
|
|
93
93
|
| `refresh_insights` | Trigger fresh AI insight generation |
|
|
94
94
|
| `get_persona_breakdown` | Visitor cluster distribution with reliability scores |
|
|
95
|
-
| `get_goal_funnel` | Goal hit counts and conversion rates per variant |
|
|
95
|
+
| `get_goal_funnel` | Goal hit counts and conversion rates per variant (windowed; default 30d) |
|
|
96
96
|
| `list_goals` | Defined goals (id, role, event, status) — includes goals with no conversions yet, so agents can wire a dashboard-defined goal into code |
|
|
97
97
|
| `list_guardrail_events` | Variants auto-paused by the guardrail (last 24h) |
|
|
98
98
|
| `get_layout_stats` | Per-persona section layout rankings and reward weights |
|
|
@@ -199,7 +199,11 @@ var RENDER_JS = {
|
|
|
199
199
|
"variant-performance": `
|
|
200
200
|
window.__render = function(data){
|
|
201
201
|
var variants = (data && data.variants) || [];
|
|
202
|
-
|
|
202
|
+
var winText = 'current vs prior period';
|
|
203
|
+
if (data && data.window && data.window.start && data.window.end) {
|
|
204
|
+
winText = String(data.window.start).slice(0, 10) + ' to ' + String(data.window.end).slice(0, 10) + ' vs prior period';
|
|
205
|
+
}
|
|
206
|
+
el('sub').textContent = variants.length + ' variant' + (variants.length === 1 ? '' : 's') + ' \xB7 conversion, ' + winText;
|
|
203
207
|
if (!variants.length) { showEmpty('No variant data available yet.'); return; }
|
|
204
208
|
var max = variants.reduce(function(m,v){ return Math.max(m, v.currentCvr || 0); }, 0) || 1;
|
|
205
209
|
var sorted = variants.slice().sort(function(a,b){ return (b.currentCvr||0) - (a.currentCvr||0); });
|
|
@@ -331,6 +335,44 @@ import { z as z2 } from "zod";
|
|
|
331
335
|
// src/tools/common.ts
|
|
332
336
|
import { z } from "zod";
|
|
333
337
|
var projectIdSchema = z.string().uuid().describe("The project UUID");
|
|
338
|
+
function rangeInputSchema(defaultRange) {
|
|
339
|
+
return {
|
|
340
|
+
range: z.enum(["7d", "30d", "90d", "all"]).optional().describe(
|
|
341
|
+
`Calendar window in the project's reporting timezone (default ${defaultRange}). 'all' means all retained data \u2014 the plan's retention window bounds every lookback.`
|
|
342
|
+
),
|
|
343
|
+
from: z.string().optional().describe(
|
|
344
|
+
"Custom window start (YYYY-MM-DD; overrides range). Must be within the plan retention window."
|
|
345
|
+
),
|
|
346
|
+
to: z.string().optional().describe("Custom window end (YYYY-MM-DD, inclusive; default today).")
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function rangeQuery(args) {
|
|
350
|
+
const p = new URLSearchParams();
|
|
351
|
+
if (args.from) {
|
|
352
|
+
p.set("from", args.from);
|
|
353
|
+
if (args.to) p.set("to", args.to);
|
|
354
|
+
} else if (args.range) {
|
|
355
|
+
p.set("range", args.range);
|
|
356
|
+
}
|
|
357
|
+
const s = p.toString();
|
|
358
|
+
return s ? `?${s}` : "";
|
|
359
|
+
}
|
|
360
|
+
var windowOutputSchema = z.object({
|
|
361
|
+
range: z.string(),
|
|
362
|
+
start: z.string().nullable(),
|
|
363
|
+
end: z.string().nullable(),
|
|
364
|
+
timezone: z.string(),
|
|
365
|
+
bucketUnit: z.string(),
|
|
366
|
+
retentionDays: z.number().describe("The plan's effective data retention in days"),
|
|
367
|
+
earliestAvailable: z.string().describe("First date retention still holds data for (YYYY-MM-DD)")
|
|
368
|
+
}).optional().describe("The window the server actually used for every count in this response");
|
|
369
|
+
function windowLine(window) {
|
|
370
|
+
if (!window) return "";
|
|
371
|
+
if (window.start && window.end) {
|
|
372
|
+
return `Window: ${window.start.slice(0, 10)} to ${window.end.slice(0, 10)} (${window.timezone}, exclusive end)`;
|
|
373
|
+
}
|
|
374
|
+
return `Window: all retained data (${window.retentionDays}-day retention)`;
|
|
375
|
+
}
|
|
334
376
|
function apiErrorGuidance(err, extra) {
|
|
335
377
|
if (extra && Object.prototype.hasOwnProperty.call(extra, err.message)) {
|
|
336
378
|
return extra[err.message];
|
|
@@ -345,6 +387,12 @@ function apiErrorGuidance(err, extra) {
|
|
|
345
387
|
default:
|
|
346
388
|
break;
|
|
347
389
|
}
|
|
390
|
+
if (err.message === "range_out_of_retention") {
|
|
391
|
+
return "The requested window starts before this plan retains data \u2014 older events have been deleted by the retention purge and cannot be recovered. Ask for a more recent window, or upgrade the SentientUI plan for longer history (Growth keeps 180 days, Scale 365).";
|
|
392
|
+
}
|
|
393
|
+
if (err.message === "invalid_range") {
|
|
394
|
+
return "Invalid time window. Use range '7d', '30d', '90d' or 'all', or from/to as YYYY-MM-DD dates.";
|
|
395
|
+
}
|
|
348
396
|
if (err.status === 402) {
|
|
349
397
|
return `This feature requires a higher plan (${err.message}). Upgrade your SentientUI plan, then try again.`;
|
|
350
398
|
}
|
|
@@ -516,8 +564,8 @@ function registerComponentTools(server, client) {
|
|
|
516
564
|
"list_components",
|
|
517
565
|
{
|
|
518
566
|
title: "List components",
|
|
519
|
-
description: "List all adaptive components in a project with variant counts and impression totals.",
|
|
520
|
-
inputSchema: { projectId: projectIdSchema },
|
|
567
|
+
description: "List all adaptive components in a project with variant counts and impression totals. Counts cover all retained data by default; pass range or from/to for a window.",
|
|
568
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("all")),
|
|
521
569
|
outputSchema: {
|
|
522
570
|
components: z3.array(
|
|
523
571
|
z3.object({
|
|
@@ -526,7 +574,8 @@ function registerComponentTools(server, client) {
|
|
|
526
574
|
impressions: z3.number(),
|
|
527
575
|
conversions: z3.number()
|
|
528
576
|
})
|
|
529
|
-
).describe("Adaptive components in the project (empty if none)")
|
|
577
|
+
).describe("Adaptive components in the project (empty if none)"),
|
|
578
|
+
window: windowOutputSchema
|
|
530
579
|
},
|
|
531
580
|
annotations: {
|
|
532
581
|
readOnlyHint: true,
|
|
@@ -534,16 +583,17 @@ function registerComponentTools(server, client) {
|
|
|
534
583
|
openWorldHint: false
|
|
535
584
|
}
|
|
536
585
|
},
|
|
537
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
586
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
538
587
|
const id = encodeURIComponent(projectId);
|
|
539
|
-
const { components } = await client.get(`/projects/${id}/components`);
|
|
588
|
+
const { components, window } = await client.get(`/projects/${id}/components${rangeQuery({ range, from, to })}`);
|
|
540
589
|
const structuredContent = {
|
|
541
590
|
components: components.map((c) => ({
|
|
542
591
|
componentId: c.component_id,
|
|
543
592
|
variantCount: c.variants.length,
|
|
544
593
|
impressions: c.total_impressions,
|
|
545
594
|
conversions: c.total_conversions
|
|
546
|
-
}))
|
|
595
|
+
})),
|
|
596
|
+
window
|
|
547
597
|
};
|
|
548
598
|
if (!components.length) {
|
|
549
599
|
return {
|
|
@@ -561,19 +611,20 @@ function registerComponentTools(server, client) {
|
|
|
561
611
|
"get_variant_performance",
|
|
562
612
|
{
|
|
563
613
|
title: "Variant performance",
|
|
564
|
-
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7
|
|
565
|
-
inputSchema: { projectId: projectIdSchema },
|
|
614
|
+
description: "Get CVR and momentum for all variants in a project over the selected window vs the immediately-preceding window of equal length (default: last 7 calendar days vs prior 7).",
|
|
615
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("7d")),
|
|
566
616
|
_meta: uiMeta("variant-performance"),
|
|
567
617
|
outputSchema: {
|
|
568
618
|
variants: z3.array(
|
|
569
619
|
z3.object({
|
|
570
620
|
variantId: z3.string(),
|
|
571
|
-
currentCvr: z3.number().describe("Conversion rate over the
|
|
572
|
-
priorCvr: z3.number().describe("Conversion rate over the
|
|
621
|
+
currentCvr: z3.number().describe("Conversion rate over the selected window (0-1)"),
|
|
622
|
+
priorCvr: z3.number().describe("Conversion rate over the preceding window (0-1)"),
|
|
573
623
|
deltaPp: z3.number().describe("Change in percentage points"),
|
|
574
624
|
momentum: z3.string().describe("Momentum direction: gaining, losing, or stable")
|
|
575
625
|
})
|
|
576
|
-
).describe("Per-variant performance (empty if no data yet)")
|
|
626
|
+
).describe("Per-variant performance (empty if no data yet)"),
|
|
627
|
+
window: windowOutputSchema
|
|
577
628
|
},
|
|
578
629
|
annotations: {
|
|
579
630
|
readOnlyHint: true,
|
|
@@ -581,10 +632,10 @@ function registerComponentTools(server, client) {
|
|
|
581
632
|
openWorldHint: false
|
|
582
633
|
}
|
|
583
634
|
},
|
|
584
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
635
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
585
636
|
var _a, _b, _c;
|
|
586
637
|
const id = encodeURIComponent(projectId);
|
|
587
|
-
const data = await client.get(`/projects/${id}/trends`);
|
|
638
|
+
const data = await client.get(`/projects/${id}/trends${rangeQuery({ range, from, to })}`);
|
|
588
639
|
const momentumMap = new Map(((_a = data.momentum) != null ? _a : []).map((m) => [m.variantId, m.direction]));
|
|
589
640
|
const structuredContent = {
|
|
590
641
|
variants: ((_b = data.cvr) != null ? _b : []).map((v) => {
|
|
@@ -596,7 +647,8 @@ function registerComponentTools(server, client) {
|
|
|
596
647
|
deltaPp: v.deltaPp,
|
|
597
648
|
momentum: (_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"
|
|
598
649
|
};
|
|
599
|
-
})
|
|
650
|
+
}),
|
|
651
|
+
window: data.window
|
|
600
652
|
};
|
|
601
653
|
if (!((_c = data.cvr) == null ? void 0 : _c.length)) {
|
|
602
654
|
return {
|
|
@@ -605,12 +657,14 @@ function registerComponentTools(server, client) {
|
|
|
605
657
|
_meta: uiMeta("variant-performance")
|
|
606
658
|
};
|
|
607
659
|
}
|
|
608
|
-
const
|
|
660
|
+
const lines = data.cvr.map(
|
|
609
661
|
(v) => {
|
|
610
662
|
var _a2;
|
|
611
663
|
return `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${(_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"})`;
|
|
612
664
|
}
|
|
613
|
-
)
|
|
665
|
+
);
|
|
666
|
+
const win = windowLine(data.window);
|
|
667
|
+
const text = (win ? [win, ...lines] : lines).join("\n");
|
|
614
668
|
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
615
669
|
})
|
|
616
670
|
);
|
|
@@ -796,8 +850,8 @@ function registerGoalTools(server, client) {
|
|
|
796
850
|
"get_goal_funnel",
|
|
797
851
|
{
|
|
798
852
|
title: "Goal funnel",
|
|
799
|
-
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown. This is a flat per-goal list \u2014 for multi-step funnel drop-off, use get_funnel_report.",
|
|
800
|
-
inputSchema: { projectId: projectIdSchema },
|
|
853
|
+
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown (default window: last 30 calendar days). This is a flat per-goal list \u2014 for multi-step funnel drop-off, use get_funnel_report.",
|
|
854
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("30d")),
|
|
801
855
|
_meta: uiMeta("goal-funnel"),
|
|
802
856
|
outputSchema: {
|
|
803
857
|
currency: z6.string().describe("Project display currency (ISO-4217) for the revenue fields"),
|
|
@@ -818,7 +872,8 @@ function registerGoalTools(server, client) {
|
|
|
818
872
|
})
|
|
819
873
|
).describe("Per-variant breakdown")
|
|
820
874
|
})
|
|
821
|
-
).describe("Configured goals (empty if none)")
|
|
875
|
+
).describe("Configured goals (empty if none)"),
|
|
876
|
+
window: windowOutputSchema
|
|
822
877
|
},
|
|
823
878
|
annotations: {
|
|
824
879
|
readOnlyHint: true,
|
|
@@ -826,11 +881,12 @@ function registerGoalTools(server, client) {
|
|
|
826
881
|
openWorldHint: false
|
|
827
882
|
}
|
|
828
883
|
},
|
|
829
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
884
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
830
885
|
var _a, _b;
|
|
831
886
|
const id = encodeURIComponent(projectId);
|
|
832
|
-
const data = await client.get(`/projects/${id}/goals`);
|
|
887
|
+
const data = await client.get(`/projects/${id}/goals${rangeQuery({ range, from, to })}`);
|
|
833
888
|
const structuredContent = {
|
|
889
|
+
window: data.window,
|
|
834
890
|
currency: (_a = data.currency) != null ? _a : "USD",
|
|
835
891
|
goals: data.goals.map((g) => {
|
|
836
892
|
var _a2, _b2, _c;
|
|
@@ -858,6 +914,7 @@ function registerGoalTools(server, client) {
|
|
|
858
914
|
};
|
|
859
915
|
}
|
|
860
916
|
const currency = (_b = data.currency) != null ? _b : "USD";
|
|
917
|
+
const win = windowLine(data.window);
|
|
861
918
|
const lines = data.goals.flatMap((g) => {
|
|
862
919
|
var _a2;
|
|
863
920
|
return [
|
|
@@ -866,7 +923,8 @@ function registerGoalTools(server, client) {
|
|
|
866
923
|
""
|
|
867
924
|
];
|
|
868
925
|
});
|
|
869
|
-
|
|
926
|
+
const text = (win ? [win, "", ...lines] : lines).join("\n").trim();
|
|
927
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
870
928
|
})
|
|
871
929
|
);
|
|
872
930
|
server.registerTool(
|
|
@@ -1613,9 +1671,15 @@ function registerTestBriefTools(server, client) {
|
|
|
1613
1671
|
import { z as z13 } from "zod";
|
|
1614
1672
|
var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
|
|
1615
1673
|
|
|
1616
|
-
SentientUI adapts a site per visitor type (personas
|
|
1617
|
-
|
|
1618
|
-
|
|
1674
|
+
SentientUI adapts a site per visitor type (personas), learning from real conversions. Each
|
|
1675
|
+
project has its own persona vocabulary (dashboard -> Settings -> Personas; the default is
|
|
1676
|
+
buyer, researcher, deal_seeker, browser + unknown). Personas are inferred from behavior \u2014 or
|
|
1677
|
+
DECLARED by the app when it already knows the visitor's role: init({ persona: 'admin' }) /
|
|
1678
|
+
<AdaptiveProvider persona=...> / window.sentient.persona. Declared beats inferred and serves
|
|
1679
|
+
at full confidence; unrecognized values are ignored server-side and surfaced in the dashboard
|
|
1680
|
+
so the operator can add them. Keep persona a low-cardinality role slug \u2014 never a user id.
|
|
1681
|
+
Decisions are locked per session: Visit 1 learns, Visit 2 converts. Integrate one rung at a
|
|
1682
|
+
time.
|
|
1619
1683
|
|
|
1620
1684
|
## Setup (60 seconds, no account)
|
|
1621
1685
|
|
|
@@ -1633,7 +1697,8 @@ Visit 2 converts. Integrate one rung at a time.
|
|
|
1633
1697
|
|
|
1634
1698
|
## Rung 1 \u2014 Style (CSS only)
|
|
1635
1699
|
|
|
1636
|
-
Persona attributes on <html> (zero declaration
|
|
1700
|
+
Persona attributes on <html> (zero declaration; the attribute carries the project's own
|
|
1701
|
+
vocabulary keys \u2014 declared or inferred):
|
|
1637
1702
|
|
|
1638
1703
|
html[data-sentient-persona='deal_seeker'] .discount-banner { display: block; }
|
|
1639
1704
|
html[data-sentient-confidence='low'] .discount-banner { display: none; }
|
|
@@ -1710,8 +1775,12 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1710
1775
|
"get_agent_traffic",
|
|
1711
1776
|
{
|
|
1712
1777
|
title: "Agent traffic",
|
|
1713
|
-
description: "Which AI agents and crawlers are reading this site: totals by type (passive crawlers, agentic browsers, agent API calls), engine breakdown, and the paths they fetch most. Agent traffic is tracked separately and never counted in conversion rate.",
|
|
1714
|
-
inputSchema: {
|
|
1778
|
+
description: "Which AI agents and crawlers are reading this site: totals by type (passive crawlers, agentic browsers, agent API calls), engine breakdown, and the paths they fetch most. Defaults to the last 30 days; pass from/to for a custom period (agent logs are retained 30 days on Free/Starter, 90 on Growth+). Agent traffic is tracked separately and never counted in conversion rate.",
|
|
1779
|
+
inputSchema: {
|
|
1780
|
+
projectId: projectIdSchema,
|
|
1781
|
+
from: z14.string().optional().describe("Period start (ISO 8601 date or timestamp). Defaults to 30 days ago."),
|
|
1782
|
+
to: z14.string().optional().describe("Period end (ISO 8601 date or timestamp). Defaults to now.")
|
|
1783
|
+
},
|
|
1715
1784
|
outputSchema: {
|
|
1716
1785
|
totals: z14.object({ crawler: z14.number(), api: z14.number(), browser: z14.number() }),
|
|
1717
1786
|
engines: z14.array(
|
|
@@ -1729,9 +1798,14 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1729
1798
|
},
|
|
1730
1799
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
1731
1800
|
},
|
|
1732
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
1801
|
+
withApiErrorGuidance(async ({ projectId, from, to }) => {
|
|
1733
1802
|
const id = encodeURIComponent(projectId);
|
|
1734
|
-
const
|
|
1803
|
+
const qs = new URLSearchParams();
|
|
1804
|
+
if (from) qs.set("from", from);
|
|
1805
|
+
if (to) qs.set("to", to);
|
|
1806
|
+
const s = await client.get(
|
|
1807
|
+
`/projects/${id}/agent-activity/summary${qs.size > 0 ? `?${qs.toString()}` : ""}`
|
|
1808
|
+
);
|
|
1735
1809
|
const structuredContent = { totals: s.totals, engines: s.engines, intents: s.intents, topPaths: s.topPaths };
|
|
1736
1810
|
const total = s.totals.crawler + s.totals.api + s.totals.browser;
|
|
1737
1811
|
if (total === 0) {
|
|
@@ -1819,7 +1893,7 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1819
1893
|
}
|
|
1820
1894
|
|
|
1821
1895
|
// src/server.ts
|
|
1822
|
-
var PKG_VERSION = true ? "0.
|
|
1896
|
+
var PKG_VERSION = true ? "0.17.1" : "0.0.0-dev";
|
|
1823
1897
|
function createMcpServer(client) {
|
|
1824
1898
|
const server = new McpServer(
|
|
1825
1899
|
{
|
package/dist/index.cjs
CHANGED
|
@@ -78,6 +78,44 @@ var import_zod2 = require("zod");
|
|
|
78
78
|
// src/tools/common.ts
|
|
79
79
|
var import_zod = require("zod");
|
|
80
80
|
var projectIdSchema = import_zod.z.string().uuid().describe("The project UUID");
|
|
81
|
+
function rangeInputSchema(defaultRange) {
|
|
82
|
+
return {
|
|
83
|
+
range: import_zod.z.enum(["7d", "30d", "90d", "all"]).optional().describe(
|
|
84
|
+
`Calendar window in the project's reporting timezone (default ${defaultRange}). 'all' means all retained data \u2014 the plan's retention window bounds every lookback.`
|
|
85
|
+
),
|
|
86
|
+
from: import_zod.z.string().optional().describe(
|
|
87
|
+
"Custom window start (YYYY-MM-DD; overrides range). Must be within the plan retention window."
|
|
88
|
+
),
|
|
89
|
+
to: import_zod.z.string().optional().describe("Custom window end (YYYY-MM-DD, inclusive; default today).")
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function rangeQuery(args) {
|
|
93
|
+
const p = new URLSearchParams();
|
|
94
|
+
if (args.from) {
|
|
95
|
+
p.set("from", args.from);
|
|
96
|
+
if (args.to) p.set("to", args.to);
|
|
97
|
+
} else if (args.range) {
|
|
98
|
+
p.set("range", args.range);
|
|
99
|
+
}
|
|
100
|
+
const s = p.toString();
|
|
101
|
+
return s ? `?${s}` : "";
|
|
102
|
+
}
|
|
103
|
+
var windowOutputSchema = import_zod.z.object({
|
|
104
|
+
range: import_zod.z.string(),
|
|
105
|
+
start: import_zod.z.string().nullable(),
|
|
106
|
+
end: import_zod.z.string().nullable(),
|
|
107
|
+
timezone: import_zod.z.string(),
|
|
108
|
+
bucketUnit: import_zod.z.string(),
|
|
109
|
+
retentionDays: import_zod.z.number().describe("The plan's effective data retention in days"),
|
|
110
|
+
earliestAvailable: import_zod.z.string().describe("First date retention still holds data for (YYYY-MM-DD)")
|
|
111
|
+
}).optional().describe("The window the server actually used for every count in this response");
|
|
112
|
+
function windowLine(window) {
|
|
113
|
+
if (!window) return "";
|
|
114
|
+
if (window.start && window.end) {
|
|
115
|
+
return `Window: ${window.start.slice(0, 10)} to ${window.end.slice(0, 10)} (${window.timezone}, exclusive end)`;
|
|
116
|
+
}
|
|
117
|
+
return `Window: all retained data (${window.retentionDays}-day retention)`;
|
|
118
|
+
}
|
|
81
119
|
function apiErrorGuidance(err, extra) {
|
|
82
120
|
if (extra && Object.prototype.hasOwnProperty.call(extra, err.message)) {
|
|
83
121
|
return extra[err.message];
|
|
@@ -92,6 +130,12 @@ function apiErrorGuidance(err, extra) {
|
|
|
92
130
|
default:
|
|
93
131
|
break;
|
|
94
132
|
}
|
|
133
|
+
if (err.message === "range_out_of_retention") {
|
|
134
|
+
return "The requested window starts before this plan retains data \u2014 older events have been deleted by the retention purge and cannot be recovered. Ask for a more recent window, or upgrade the SentientUI plan for longer history (Growth keeps 180 days, Scale 365).";
|
|
135
|
+
}
|
|
136
|
+
if (err.message === "invalid_range") {
|
|
137
|
+
return "Invalid time window. Use range '7d', '30d', '90d' or 'all', or from/to as YYYY-MM-DD dates.";
|
|
138
|
+
}
|
|
95
139
|
if (err.status === 402) {
|
|
96
140
|
return `This feature requires a higher plan (${err.message}). Upgrade your SentientUI plan, then try again.`;
|
|
97
141
|
}
|
|
@@ -393,7 +437,11 @@ var RENDER_JS = {
|
|
|
393
437
|
"variant-performance": `
|
|
394
438
|
window.__render = function(data){
|
|
395
439
|
var variants = (data && data.variants) || [];
|
|
396
|
-
|
|
440
|
+
var winText = 'current vs prior period';
|
|
441
|
+
if (data && data.window && data.window.start && data.window.end) {
|
|
442
|
+
winText = String(data.window.start).slice(0, 10) + ' to ' + String(data.window.end).slice(0, 10) + ' vs prior period';
|
|
443
|
+
}
|
|
444
|
+
el('sub').textContent = variants.length + ' variant' + (variants.length === 1 ? '' : 's') + ' \xB7 conversion, ' + winText;
|
|
397
445
|
if (!variants.length) { showEmpty('No variant data available yet.'); return; }
|
|
398
446
|
var max = variants.reduce(function(m,v){ return Math.max(m, v.currentCvr || 0); }, 0) || 1;
|
|
399
447
|
var sorted = variants.slice().sort(function(a,b){ return (b.currentCvr||0) - (a.currentCvr||0); });
|
|
@@ -522,8 +570,8 @@ function registerComponentTools(server, client) {
|
|
|
522
570
|
"list_components",
|
|
523
571
|
{
|
|
524
572
|
title: "List components",
|
|
525
|
-
description: "List all adaptive components in a project with variant counts and impression totals.",
|
|
526
|
-
inputSchema: { projectId: projectIdSchema },
|
|
573
|
+
description: "List all adaptive components in a project with variant counts and impression totals. Counts cover all retained data by default; pass range or from/to for a window.",
|
|
574
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("all")),
|
|
527
575
|
outputSchema: {
|
|
528
576
|
components: import_zod3.z.array(
|
|
529
577
|
import_zod3.z.object({
|
|
@@ -532,7 +580,8 @@ function registerComponentTools(server, client) {
|
|
|
532
580
|
impressions: import_zod3.z.number(),
|
|
533
581
|
conversions: import_zod3.z.number()
|
|
534
582
|
})
|
|
535
|
-
).describe("Adaptive components in the project (empty if none)")
|
|
583
|
+
).describe("Adaptive components in the project (empty if none)"),
|
|
584
|
+
window: windowOutputSchema
|
|
536
585
|
},
|
|
537
586
|
annotations: {
|
|
538
587
|
readOnlyHint: true,
|
|
@@ -540,16 +589,17 @@ function registerComponentTools(server, client) {
|
|
|
540
589
|
openWorldHint: false
|
|
541
590
|
}
|
|
542
591
|
},
|
|
543
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
592
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
544
593
|
const id = encodeURIComponent(projectId);
|
|
545
|
-
const { components } = await client.get(`/projects/${id}/components`);
|
|
594
|
+
const { components, window } = await client.get(`/projects/${id}/components${rangeQuery({ range, from, to })}`);
|
|
546
595
|
const structuredContent = {
|
|
547
596
|
components: components.map((c) => ({
|
|
548
597
|
componentId: c.component_id,
|
|
549
598
|
variantCount: c.variants.length,
|
|
550
599
|
impressions: c.total_impressions,
|
|
551
600
|
conversions: c.total_conversions
|
|
552
|
-
}))
|
|
601
|
+
})),
|
|
602
|
+
window
|
|
553
603
|
};
|
|
554
604
|
if (!components.length) {
|
|
555
605
|
return {
|
|
@@ -567,19 +617,20 @@ function registerComponentTools(server, client) {
|
|
|
567
617
|
"get_variant_performance",
|
|
568
618
|
{
|
|
569
619
|
title: "Variant performance",
|
|
570
|
-
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7
|
|
571
|
-
inputSchema: { projectId: projectIdSchema },
|
|
620
|
+
description: "Get CVR and momentum for all variants in a project over the selected window vs the immediately-preceding window of equal length (default: last 7 calendar days vs prior 7).",
|
|
621
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("7d")),
|
|
572
622
|
_meta: uiMeta("variant-performance"),
|
|
573
623
|
outputSchema: {
|
|
574
624
|
variants: import_zod3.z.array(
|
|
575
625
|
import_zod3.z.object({
|
|
576
626
|
variantId: import_zod3.z.string(),
|
|
577
|
-
currentCvr: import_zod3.z.number().describe("Conversion rate over the
|
|
578
|
-
priorCvr: import_zod3.z.number().describe("Conversion rate over the
|
|
627
|
+
currentCvr: import_zod3.z.number().describe("Conversion rate over the selected window (0-1)"),
|
|
628
|
+
priorCvr: import_zod3.z.number().describe("Conversion rate over the preceding window (0-1)"),
|
|
579
629
|
deltaPp: import_zod3.z.number().describe("Change in percentage points"),
|
|
580
630
|
momentum: import_zod3.z.string().describe("Momentum direction: gaining, losing, or stable")
|
|
581
631
|
})
|
|
582
|
-
).describe("Per-variant performance (empty if no data yet)")
|
|
632
|
+
).describe("Per-variant performance (empty if no data yet)"),
|
|
633
|
+
window: windowOutputSchema
|
|
583
634
|
},
|
|
584
635
|
annotations: {
|
|
585
636
|
readOnlyHint: true,
|
|
@@ -587,10 +638,10 @@ function registerComponentTools(server, client) {
|
|
|
587
638
|
openWorldHint: false
|
|
588
639
|
}
|
|
589
640
|
},
|
|
590
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
641
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
591
642
|
var _a2, _b, _c;
|
|
592
643
|
const id = encodeURIComponent(projectId);
|
|
593
|
-
const data = await client.get(`/projects/${id}/trends`);
|
|
644
|
+
const data = await client.get(`/projects/${id}/trends${rangeQuery({ range, from, to })}`);
|
|
594
645
|
const momentumMap = new Map(((_a2 = data.momentum) != null ? _a2 : []).map((m) => [m.variantId, m.direction]));
|
|
595
646
|
const structuredContent = {
|
|
596
647
|
variants: ((_b = data.cvr) != null ? _b : []).map((v) => {
|
|
@@ -602,7 +653,8 @@ function registerComponentTools(server, client) {
|
|
|
602
653
|
deltaPp: v.deltaPp,
|
|
603
654
|
momentum: (_a3 = momentumMap.get(v.variantId)) != null ? _a3 : "stable"
|
|
604
655
|
};
|
|
605
|
-
})
|
|
656
|
+
}),
|
|
657
|
+
window: data.window
|
|
606
658
|
};
|
|
607
659
|
if (!((_c = data.cvr) == null ? void 0 : _c.length)) {
|
|
608
660
|
return {
|
|
@@ -611,12 +663,14 @@ function registerComponentTools(server, client) {
|
|
|
611
663
|
_meta: uiMeta("variant-performance")
|
|
612
664
|
};
|
|
613
665
|
}
|
|
614
|
-
const
|
|
666
|
+
const lines = data.cvr.map(
|
|
615
667
|
(v) => {
|
|
616
668
|
var _a3;
|
|
617
669
|
return `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${(_a3 = momentumMap.get(v.variantId)) != null ? _a3 : "stable"})`;
|
|
618
670
|
}
|
|
619
|
-
)
|
|
671
|
+
);
|
|
672
|
+
const win = windowLine(data.window);
|
|
673
|
+
const text = (win ? [win, ...lines] : lines).join("\n");
|
|
620
674
|
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
621
675
|
})
|
|
622
676
|
);
|
|
@@ -802,8 +856,8 @@ function registerGoalTools(server, client) {
|
|
|
802
856
|
"get_goal_funnel",
|
|
803
857
|
{
|
|
804
858
|
title: "Goal funnel",
|
|
805
|
-
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown. This is a flat per-goal list \u2014 for multi-step funnel drop-off, use get_funnel_report.",
|
|
806
|
-
inputSchema: { projectId: projectIdSchema },
|
|
859
|
+
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown (default window: last 30 calendar days). This is a flat per-goal list \u2014 for multi-step funnel drop-off, use get_funnel_report.",
|
|
860
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("30d")),
|
|
807
861
|
_meta: uiMeta("goal-funnel"),
|
|
808
862
|
outputSchema: {
|
|
809
863
|
currency: import_zod6.z.string().describe("Project display currency (ISO-4217) for the revenue fields"),
|
|
@@ -824,7 +878,8 @@ function registerGoalTools(server, client) {
|
|
|
824
878
|
})
|
|
825
879
|
).describe("Per-variant breakdown")
|
|
826
880
|
})
|
|
827
|
-
).describe("Configured goals (empty if none)")
|
|
881
|
+
).describe("Configured goals (empty if none)"),
|
|
882
|
+
window: windowOutputSchema
|
|
828
883
|
},
|
|
829
884
|
annotations: {
|
|
830
885
|
readOnlyHint: true,
|
|
@@ -832,11 +887,12 @@ function registerGoalTools(server, client) {
|
|
|
832
887
|
openWorldHint: false
|
|
833
888
|
}
|
|
834
889
|
},
|
|
835
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
890
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
836
891
|
var _a2, _b;
|
|
837
892
|
const id = encodeURIComponent(projectId);
|
|
838
|
-
const data = await client.get(`/projects/${id}/goals`);
|
|
893
|
+
const data = await client.get(`/projects/${id}/goals${rangeQuery({ range, from, to })}`);
|
|
839
894
|
const structuredContent = {
|
|
895
|
+
window: data.window,
|
|
840
896
|
currency: (_a2 = data.currency) != null ? _a2 : "USD",
|
|
841
897
|
goals: data.goals.map((g) => {
|
|
842
898
|
var _a3, _b2, _c;
|
|
@@ -864,6 +920,7 @@ function registerGoalTools(server, client) {
|
|
|
864
920
|
};
|
|
865
921
|
}
|
|
866
922
|
const currency = (_b = data.currency) != null ? _b : "USD";
|
|
923
|
+
const win = windowLine(data.window);
|
|
867
924
|
const lines = data.goals.flatMap((g) => {
|
|
868
925
|
var _a3;
|
|
869
926
|
return [
|
|
@@ -872,7 +929,8 @@ function registerGoalTools(server, client) {
|
|
|
872
929
|
""
|
|
873
930
|
];
|
|
874
931
|
});
|
|
875
|
-
|
|
932
|
+
const text = (win ? [win, "", ...lines] : lines).join("\n").trim();
|
|
933
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
876
934
|
})
|
|
877
935
|
);
|
|
878
936
|
server.registerTool(
|
|
@@ -1619,9 +1677,15 @@ function registerTestBriefTools(server, client) {
|
|
|
1619
1677
|
var import_zod13 = require("zod");
|
|
1620
1678
|
var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
|
|
1621
1679
|
|
|
1622
|
-
SentientUI adapts a site per visitor type (personas
|
|
1623
|
-
|
|
1624
|
-
|
|
1680
|
+
SentientUI adapts a site per visitor type (personas), learning from real conversions. Each
|
|
1681
|
+
project has its own persona vocabulary (dashboard -> Settings -> Personas; the default is
|
|
1682
|
+
buyer, researcher, deal_seeker, browser + unknown). Personas are inferred from behavior \u2014 or
|
|
1683
|
+
DECLARED by the app when it already knows the visitor's role: init({ persona: 'admin' }) /
|
|
1684
|
+
<AdaptiveProvider persona=...> / window.sentient.persona. Declared beats inferred and serves
|
|
1685
|
+
at full confidence; unrecognized values are ignored server-side and surfaced in the dashboard
|
|
1686
|
+
so the operator can add them. Keep persona a low-cardinality role slug \u2014 never a user id.
|
|
1687
|
+
Decisions are locked per session: Visit 1 learns, Visit 2 converts. Integrate one rung at a
|
|
1688
|
+
time.
|
|
1625
1689
|
|
|
1626
1690
|
## Setup (60 seconds, no account)
|
|
1627
1691
|
|
|
@@ -1639,7 +1703,8 @@ Visit 2 converts. Integrate one rung at a time.
|
|
|
1639
1703
|
|
|
1640
1704
|
## Rung 1 \u2014 Style (CSS only)
|
|
1641
1705
|
|
|
1642
|
-
Persona attributes on <html> (zero declaration
|
|
1706
|
+
Persona attributes on <html> (zero declaration; the attribute carries the project's own
|
|
1707
|
+
vocabulary keys \u2014 declared or inferred):
|
|
1643
1708
|
|
|
1644
1709
|
html[data-sentient-persona='deal_seeker'] .discount-banner { display: block; }
|
|
1645
1710
|
html[data-sentient-confidence='low'] .discount-banner { display: none; }
|
|
@@ -1716,8 +1781,12 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1716
1781
|
"get_agent_traffic",
|
|
1717
1782
|
{
|
|
1718
1783
|
title: "Agent traffic",
|
|
1719
|
-
description: "Which AI agents and crawlers are reading this site: totals by type (passive crawlers, agentic browsers, agent API calls), engine breakdown, and the paths they fetch most. Agent traffic is tracked separately and never counted in conversion rate.",
|
|
1720
|
-
inputSchema: {
|
|
1784
|
+
description: "Which AI agents and crawlers are reading this site: totals by type (passive crawlers, agentic browsers, agent API calls), engine breakdown, and the paths they fetch most. Defaults to the last 30 days; pass from/to for a custom period (agent logs are retained 30 days on Free/Starter, 90 on Growth+). Agent traffic is tracked separately and never counted in conversion rate.",
|
|
1785
|
+
inputSchema: {
|
|
1786
|
+
projectId: projectIdSchema,
|
|
1787
|
+
from: import_zod14.z.string().optional().describe("Period start (ISO 8601 date or timestamp). Defaults to 30 days ago."),
|
|
1788
|
+
to: import_zod14.z.string().optional().describe("Period end (ISO 8601 date or timestamp). Defaults to now.")
|
|
1789
|
+
},
|
|
1721
1790
|
outputSchema: {
|
|
1722
1791
|
totals: import_zod14.z.object({ crawler: import_zod14.z.number(), api: import_zod14.z.number(), browser: import_zod14.z.number() }),
|
|
1723
1792
|
engines: import_zod14.z.array(
|
|
@@ -1735,9 +1804,14 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1735
1804
|
},
|
|
1736
1805
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
1737
1806
|
},
|
|
1738
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
1807
|
+
withApiErrorGuidance(async ({ projectId, from, to }) => {
|
|
1739
1808
|
const id = encodeURIComponent(projectId);
|
|
1740
|
-
const
|
|
1809
|
+
const qs = new URLSearchParams();
|
|
1810
|
+
if (from) qs.set("from", from);
|
|
1811
|
+
if (to) qs.set("to", to);
|
|
1812
|
+
const s = await client.get(
|
|
1813
|
+
`/projects/${id}/agent-activity/summary${qs.size > 0 ? `?${qs.toString()}` : ""}`
|
|
1814
|
+
);
|
|
1741
1815
|
const structuredContent = { totals: s.totals, engines: s.engines, intents: s.intents, topPaths: s.topPaths };
|
|
1742
1816
|
const total = s.totals.crawler + s.totals.api + s.totals.browser;
|
|
1743
1817
|
if (total === 0) {
|
|
@@ -1825,7 +1899,7 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1825
1899
|
}
|
|
1826
1900
|
|
|
1827
1901
|
// src/server.ts
|
|
1828
|
-
var PKG_VERSION = true ? "0.
|
|
1902
|
+
var PKG_VERSION = true ? "0.17.1" : "0.0.0-dev";
|
|
1829
1903
|
function createMcpServer(client) {
|
|
1830
1904
|
const server = new import_mcp.McpServer(
|
|
1831
1905
|
{
|
package/dist/index.js
CHANGED
package/dist/lib.cjs
CHANGED
|
@@ -102,6 +102,44 @@ var ApiClient = class {
|
|
|
102
102
|
|
|
103
103
|
// src/tools/common.ts
|
|
104
104
|
var projectIdSchema = import_zod.z.string().uuid().describe("The project UUID");
|
|
105
|
+
function rangeInputSchema(defaultRange) {
|
|
106
|
+
return {
|
|
107
|
+
range: import_zod.z.enum(["7d", "30d", "90d", "all"]).optional().describe(
|
|
108
|
+
`Calendar window in the project's reporting timezone (default ${defaultRange}). 'all' means all retained data \u2014 the plan's retention window bounds every lookback.`
|
|
109
|
+
),
|
|
110
|
+
from: import_zod.z.string().optional().describe(
|
|
111
|
+
"Custom window start (YYYY-MM-DD; overrides range). Must be within the plan retention window."
|
|
112
|
+
),
|
|
113
|
+
to: import_zod.z.string().optional().describe("Custom window end (YYYY-MM-DD, inclusive; default today).")
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function rangeQuery(args) {
|
|
117
|
+
const p = new URLSearchParams();
|
|
118
|
+
if (args.from) {
|
|
119
|
+
p.set("from", args.from);
|
|
120
|
+
if (args.to) p.set("to", args.to);
|
|
121
|
+
} else if (args.range) {
|
|
122
|
+
p.set("range", args.range);
|
|
123
|
+
}
|
|
124
|
+
const s = p.toString();
|
|
125
|
+
return s ? `?${s}` : "";
|
|
126
|
+
}
|
|
127
|
+
var windowOutputSchema = import_zod.z.object({
|
|
128
|
+
range: import_zod.z.string(),
|
|
129
|
+
start: import_zod.z.string().nullable(),
|
|
130
|
+
end: import_zod.z.string().nullable(),
|
|
131
|
+
timezone: import_zod.z.string(),
|
|
132
|
+
bucketUnit: import_zod.z.string(),
|
|
133
|
+
retentionDays: import_zod.z.number().describe("The plan's effective data retention in days"),
|
|
134
|
+
earliestAvailable: import_zod.z.string().describe("First date retention still holds data for (YYYY-MM-DD)")
|
|
135
|
+
}).optional().describe("The window the server actually used for every count in this response");
|
|
136
|
+
function windowLine(window) {
|
|
137
|
+
if (!window) return "";
|
|
138
|
+
if (window.start && window.end) {
|
|
139
|
+
return `Window: ${window.start.slice(0, 10)} to ${window.end.slice(0, 10)} (${window.timezone}, exclusive end)`;
|
|
140
|
+
}
|
|
141
|
+
return `Window: all retained data (${window.retentionDays}-day retention)`;
|
|
142
|
+
}
|
|
105
143
|
function apiErrorGuidance(err, extra) {
|
|
106
144
|
if (extra && Object.prototype.hasOwnProperty.call(extra, err.message)) {
|
|
107
145
|
return extra[err.message];
|
|
@@ -116,6 +154,12 @@ function apiErrorGuidance(err, extra) {
|
|
|
116
154
|
default:
|
|
117
155
|
break;
|
|
118
156
|
}
|
|
157
|
+
if (err.message === "range_out_of_retention") {
|
|
158
|
+
return "The requested window starts before this plan retains data \u2014 older events have been deleted by the retention purge and cannot be recovered. Ask for a more recent window, or upgrade the SentientUI plan for longer history (Growth keeps 180 days, Scale 365).";
|
|
159
|
+
}
|
|
160
|
+
if (err.message === "invalid_range") {
|
|
161
|
+
return "Invalid time window. Use range '7d', '30d', '90d' or 'all', or from/to as YYYY-MM-DD dates.";
|
|
162
|
+
}
|
|
119
163
|
if (err.status === 402) {
|
|
120
164
|
return `This feature requires a higher plan (${err.message}). Upgrade your SentientUI plan, then try again.`;
|
|
121
165
|
}
|
|
@@ -417,7 +461,11 @@ var RENDER_JS = {
|
|
|
417
461
|
"variant-performance": `
|
|
418
462
|
window.__render = function(data){
|
|
419
463
|
var variants = (data && data.variants) || [];
|
|
420
|
-
|
|
464
|
+
var winText = 'current vs prior period';
|
|
465
|
+
if (data && data.window && data.window.start && data.window.end) {
|
|
466
|
+
winText = String(data.window.start).slice(0, 10) + ' to ' + String(data.window.end).slice(0, 10) + ' vs prior period';
|
|
467
|
+
}
|
|
468
|
+
el('sub').textContent = variants.length + ' variant' + (variants.length === 1 ? '' : 's') + ' \xB7 conversion, ' + winText;
|
|
421
469
|
if (!variants.length) { showEmpty('No variant data available yet.'); return; }
|
|
422
470
|
var max = variants.reduce(function(m,v){ return Math.max(m, v.currentCvr || 0); }, 0) || 1;
|
|
423
471
|
var sorted = variants.slice().sort(function(a,b){ return (b.currentCvr||0) - (a.currentCvr||0); });
|
|
@@ -546,8 +594,8 @@ function registerComponentTools(server, client) {
|
|
|
546
594
|
"list_components",
|
|
547
595
|
{
|
|
548
596
|
title: "List components",
|
|
549
|
-
description: "List all adaptive components in a project with variant counts and impression totals.",
|
|
550
|
-
inputSchema: { projectId: projectIdSchema },
|
|
597
|
+
description: "List all adaptive components in a project with variant counts and impression totals. Counts cover all retained data by default; pass range or from/to for a window.",
|
|
598
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("all")),
|
|
551
599
|
outputSchema: {
|
|
552
600
|
components: import_zod3.z.array(
|
|
553
601
|
import_zod3.z.object({
|
|
@@ -556,7 +604,8 @@ function registerComponentTools(server, client) {
|
|
|
556
604
|
impressions: import_zod3.z.number(),
|
|
557
605
|
conversions: import_zod3.z.number()
|
|
558
606
|
})
|
|
559
|
-
).describe("Adaptive components in the project (empty if none)")
|
|
607
|
+
).describe("Adaptive components in the project (empty if none)"),
|
|
608
|
+
window: windowOutputSchema
|
|
560
609
|
},
|
|
561
610
|
annotations: {
|
|
562
611
|
readOnlyHint: true,
|
|
@@ -564,16 +613,17 @@ function registerComponentTools(server, client) {
|
|
|
564
613
|
openWorldHint: false
|
|
565
614
|
}
|
|
566
615
|
},
|
|
567
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
616
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
568
617
|
const id = encodeURIComponent(projectId);
|
|
569
|
-
const { components } = await client.get(`/projects/${id}/components`);
|
|
618
|
+
const { components, window } = await client.get(`/projects/${id}/components${rangeQuery({ range, from, to })}`);
|
|
570
619
|
const structuredContent = {
|
|
571
620
|
components: components.map((c) => ({
|
|
572
621
|
componentId: c.component_id,
|
|
573
622
|
variantCount: c.variants.length,
|
|
574
623
|
impressions: c.total_impressions,
|
|
575
624
|
conversions: c.total_conversions
|
|
576
|
-
}))
|
|
625
|
+
})),
|
|
626
|
+
window
|
|
577
627
|
};
|
|
578
628
|
if (!components.length) {
|
|
579
629
|
return {
|
|
@@ -591,19 +641,20 @@ function registerComponentTools(server, client) {
|
|
|
591
641
|
"get_variant_performance",
|
|
592
642
|
{
|
|
593
643
|
title: "Variant performance",
|
|
594
|
-
description: "Get CVR and momentum for all variants in a project over the last 7 days vs prior 7
|
|
595
|
-
inputSchema: { projectId: projectIdSchema },
|
|
644
|
+
description: "Get CVR and momentum for all variants in a project over the selected window vs the immediately-preceding window of equal length (default: last 7 calendar days vs prior 7).",
|
|
645
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("7d")),
|
|
596
646
|
_meta: uiMeta("variant-performance"),
|
|
597
647
|
outputSchema: {
|
|
598
648
|
variants: import_zod3.z.array(
|
|
599
649
|
import_zod3.z.object({
|
|
600
650
|
variantId: import_zod3.z.string(),
|
|
601
|
-
currentCvr: import_zod3.z.number().describe("Conversion rate over the
|
|
602
|
-
priorCvr: import_zod3.z.number().describe("Conversion rate over the
|
|
651
|
+
currentCvr: import_zod3.z.number().describe("Conversion rate over the selected window (0-1)"),
|
|
652
|
+
priorCvr: import_zod3.z.number().describe("Conversion rate over the preceding window (0-1)"),
|
|
603
653
|
deltaPp: import_zod3.z.number().describe("Change in percentage points"),
|
|
604
654
|
momentum: import_zod3.z.string().describe("Momentum direction: gaining, losing, or stable")
|
|
605
655
|
})
|
|
606
|
-
).describe("Per-variant performance (empty if no data yet)")
|
|
656
|
+
).describe("Per-variant performance (empty if no data yet)"),
|
|
657
|
+
window: windowOutputSchema
|
|
607
658
|
},
|
|
608
659
|
annotations: {
|
|
609
660
|
readOnlyHint: true,
|
|
@@ -611,10 +662,10 @@ function registerComponentTools(server, client) {
|
|
|
611
662
|
openWorldHint: false
|
|
612
663
|
}
|
|
613
664
|
},
|
|
614
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
665
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
615
666
|
var _a, _b, _c;
|
|
616
667
|
const id = encodeURIComponent(projectId);
|
|
617
|
-
const data = await client.get(`/projects/${id}/trends`);
|
|
668
|
+
const data = await client.get(`/projects/${id}/trends${rangeQuery({ range, from, to })}`);
|
|
618
669
|
const momentumMap = new Map(((_a = data.momentum) != null ? _a : []).map((m) => [m.variantId, m.direction]));
|
|
619
670
|
const structuredContent = {
|
|
620
671
|
variants: ((_b = data.cvr) != null ? _b : []).map((v) => {
|
|
@@ -626,7 +677,8 @@ function registerComponentTools(server, client) {
|
|
|
626
677
|
deltaPp: v.deltaPp,
|
|
627
678
|
momentum: (_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"
|
|
628
679
|
};
|
|
629
|
-
})
|
|
680
|
+
}),
|
|
681
|
+
window: data.window
|
|
630
682
|
};
|
|
631
683
|
if (!((_c = data.cvr) == null ? void 0 : _c.length)) {
|
|
632
684
|
return {
|
|
@@ -635,12 +687,14 @@ function registerComponentTools(server, client) {
|
|
|
635
687
|
_meta: uiMeta("variant-performance")
|
|
636
688
|
};
|
|
637
689
|
}
|
|
638
|
-
const
|
|
690
|
+
const lines = data.cvr.map(
|
|
639
691
|
(v) => {
|
|
640
692
|
var _a2;
|
|
641
693
|
return `- ${v.variantId}: CVR ${(v.currentCvr * 100).toFixed(2)}% (prior ${(v.priorCvr * 100).toFixed(2)}%, ${v.deltaPp > 0 ? "+" : ""}${v.deltaPp.toFixed(1)} pp, ${(_a2 = momentumMap.get(v.variantId)) != null ? _a2 : "stable"})`;
|
|
642
694
|
}
|
|
643
|
-
)
|
|
695
|
+
);
|
|
696
|
+
const win = windowLine(data.window);
|
|
697
|
+
const text = (win ? [win, ...lines] : lines).join("\n");
|
|
644
698
|
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("variant-performance") };
|
|
645
699
|
})
|
|
646
700
|
);
|
|
@@ -826,8 +880,8 @@ function registerGoalTools(server, client) {
|
|
|
826
880
|
"get_goal_funnel",
|
|
827
881
|
{
|
|
828
882
|
title: "Goal funnel",
|
|
829
|
-
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown. This is a flat per-goal list \u2014 for multi-step funnel drop-off, use get_funnel_report.",
|
|
830
|
-
inputSchema: { projectId: projectIdSchema },
|
|
883
|
+
description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown (default window: last 30 calendar days). This is a flat per-goal list \u2014 for multi-step funnel drop-off, use get_funnel_report.",
|
|
884
|
+
inputSchema: __spreadValues({ projectId: projectIdSchema }, rangeInputSchema("30d")),
|
|
831
885
|
_meta: uiMeta("goal-funnel"),
|
|
832
886
|
outputSchema: {
|
|
833
887
|
currency: import_zod6.z.string().describe("Project display currency (ISO-4217) for the revenue fields"),
|
|
@@ -848,7 +902,8 @@ function registerGoalTools(server, client) {
|
|
|
848
902
|
})
|
|
849
903
|
).describe("Per-variant breakdown")
|
|
850
904
|
})
|
|
851
|
-
).describe("Configured goals (empty if none)")
|
|
905
|
+
).describe("Configured goals (empty if none)"),
|
|
906
|
+
window: windowOutputSchema
|
|
852
907
|
},
|
|
853
908
|
annotations: {
|
|
854
909
|
readOnlyHint: true,
|
|
@@ -856,11 +911,12 @@ function registerGoalTools(server, client) {
|
|
|
856
911
|
openWorldHint: false
|
|
857
912
|
}
|
|
858
913
|
},
|
|
859
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
914
|
+
withApiErrorGuidance(async ({ projectId, range, from, to }) => {
|
|
860
915
|
var _a, _b;
|
|
861
916
|
const id = encodeURIComponent(projectId);
|
|
862
|
-
const data = await client.get(`/projects/${id}/goals`);
|
|
917
|
+
const data = await client.get(`/projects/${id}/goals${rangeQuery({ range, from, to })}`);
|
|
863
918
|
const structuredContent = {
|
|
919
|
+
window: data.window,
|
|
864
920
|
currency: (_a = data.currency) != null ? _a : "USD",
|
|
865
921
|
goals: data.goals.map((g) => {
|
|
866
922
|
var _a2, _b2, _c;
|
|
@@ -888,6 +944,7 @@ function registerGoalTools(server, client) {
|
|
|
888
944
|
};
|
|
889
945
|
}
|
|
890
946
|
const currency = (_b = data.currency) != null ? _b : "USD";
|
|
947
|
+
const win = windowLine(data.window);
|
|
891
948
|
const lines = data.goals.flatMap((g) => {
|
|
892
949
|
var _a2;
|
|
893
950
|
return [
|
|
@@ -896,7 +953,8 @@ function registerGoalTools(server, client) {
|
|
|
896
953
|
""
|
|
897
954
|
];
|
|
898
955
|
});
|
|
899
|
-
|
|
956
|
+
const text = (win ? [win, "", ...lines] : lines).join("\n").trim();
|
|
957
|
+
return { content: [{ type: "text", text }], structuredContent, _meta: uiMeta("goal-funnel") };
|
|
900
958
|
})
|
|
901
959
|
);
|
|
902
960
|
server.registerTool(
|
|
@@ -1643,9 +1701,15 @@ function registerTestBriefTools(server, client) {
|
|
|
1643
1701
|
var import_zod13 = require("zod");
|
|
1644
1702
|
var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
|
|
1645
1703
|
|
|
1646
|
-
SentientUI adapts a site per visitor type (personas
|
|
1647
|
-
|
|
1648
|
-
|
|
1704
|
+
SentientUI adapts a site per visitor type (personas), learning from real conversions. Each
|
|
1705
|
+
project has its own persona vocabulary (dashboard -> Settings -> Personas; the default is
|
|
1706
|
+
buyer, researcher, deal_seeker, browser + unknown). Personas are inferred from behavior \u2014 or
|
|
1707
|
+
DECLARED by the app when it already knows the visitor's role: init({ persona: 'admin' }) /
|
|
1708
|
+
<AdaptiveProvider persona=...> / window.sentient.persona. Declared beats inferred and serves
|
|
1709
|
+
at full confidence; unrecognized values are ignored server-side and surfaced in the dashboard
|
|
1710
|
+
so the operator can add them. Keep persona a low-cardinality role slug \u2014 never a user id.
|
|
1711
|
+
Decisions are locked per session: Visit 1 learns, Visit 2 converts. Integrate one rung at a
|
|
1712
|
+
time.
|
|
1649
1713
|
|
|
1650
1714
|
## Setup (60 seconds, no account)
|
|
1651
1715
|
|
|
@@ -1663,7 +1727,8 @@ Visit 2 converts. Integrate one rung at a time.
|
|
|
1663
1727
|
|
|
1664
1728
|
## Rung 1 \u2014 Style (CSS only)
|
|
1665
1729
|
|
|
1666
|
-
Persona attributes on <html> (zero declaration
|
|
1730
|
+
Persona attributes on <html> (zero declaration; the attribute carries the project's own
|
|
1731
|
+
vocabulary keys \u2014 declared or inferred):
|
|
1667
1732
|
|
|
1668
1733
|
html[data-sentient-persona='deal_seeker'] .discount-banner { display: block; }
|
|
1669
1734
|
html[data-sentient-confidence='low'] .discount-banner { display: none; }
|
|
@@ -1740,8 +1805,12 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1740
1805
|
"get_agent_traffic",
|
|
1741
1806
|
{
|
|
1742
1807
|
title: "Agent traffic",
|
|
1743
|
-
description: "Which AI agents and crawlers are reading this site: totals by type (passive crawlers, agentic browsers, agent API calls), engine breakdown, and the paths they fetch most. Agent traffic is tracked separately and never counted in conversion rate.",
|
|
1744
|
-
inputSchema: {
|
|
1808
|
+
description: "Which AI agents and crawlers are reading this site: totals by type (passive crawlers, agentic browsers, agent API calls), engine breakdown, and the paths they fetch most. Defaults to the last 30 days; pass from/to for a custom period (agent logs are retained 30 days on Free/Starter, 90 on Growth+). Agent traffic is tracked separately and never counted in conversion rate.",
|
|
1809
|
+
inputSchema: {
|
|
1810
|
+
projectId: projectIdSchema,
|
|
1811
|
+
from: import_zod14.z.string().optional().describe("Period start (ISO 8601 date or timestamp). Defaults to 30 days ago."),
|
|
1812
|
+
to: import_zod14.z.string().optional().describe("Period end (ISO 8601 date or timestamp). Defaults to now.")
|
|
1813
|
+
},
|
|
1745
1814
|
outputSchema: {
|
|
1746
1815
|
totals: import_zod14.z.object({ crawler: import_zod14.z.number(), api: import_zod14.z.number(), browser: import_zod14.z.number() }),
|
|
1747
1816
|
engines: import_zod14.z.array(
|
|
@@ -1759,9 +1828,14 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1759
1828
|
},
|
|
1760
1829
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
1761
1830
|
},
|
|
1762
|
-
withApiErrorGuidance(async ({ projectId }) => {
|
|
1831
|
+
withApiErrorGuidance(async ({ projectId, from, to }) => {
|
|
1763
1832
|
const id = encodeURIComponent(projectId);
|
|
1764
|
-
const
|
|
1833
|
+
const qs = new URLSearchParams();
|
|
1834
|
+
if (from) qs.set("from", from);
|
|
1835
|
+
if (to) qs.set("to", to);
|
|
1836
|
+
const s = await client.get(
|
|
1837
|
+
`/projects/${id}/agent-activity/summary${qs.size > 0 ? `?${qs.toString()}` : ""}`
|
|
1838
|
+
);
|
|
1765
1839
|
const structuredContent = { totals: s.totals, engines: s.engines, intents: s.intents, topPaths: s.topPaths };
|
|
1766
1840
|
const total = s.totals.crawler + s.totals.api + s.totals.browser;
|
|
1767
1841
|
if (total === 0) {
|
|
@@ -1849,7 +1923,7 @@ function registerAgentTrafficTools(server, client) {
|
|
|
1849
1923
|
}
|
|
1850
1924
|
|
|
1851
1925
|
// src/server.ts
|
|
1852
|
-
var PKG_VERSION = true ? "0.
|
|
1926
|
+
var PKG_VERSION = true ? "0.17.1" : "0.0.0-dev";
|
|
1853
1927
|
function createMcpServer(client) {
|
|
1854
1928
|
const server = new import_mcp.McpServer(
|
|
1855
1929
|
{
|
package/dist/lib.js
CHANGED