@sentientui/mcp 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,23 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
2
21
 
3
22
  // src/api-client.ts
4
23
  var ApiError = class extends Error {
@@ -730,7 +749,7 @@ function registerGoalTools(server, client) {
730
749
  "get_goal_funnel",
731
750
  {
732
751
  title: "Goal funnel",
733
- description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
752
+ 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.",
734
753
  inputSchema: { projectId: projectIdSchema },
735
754
  _meta: uiMeta("goal-funnel"),
736
755
  outputSchema: {
@@ -820,7 +839,11 @@ function registerGoalTools(server, client) {
820
839
  status: z6.string().describe("active | archived"),
821
840
  defaultValue: z6.number().nullable().describe("Fixed worth applied when a conversion carries no explicit value (project currency); null when unset")
822
841
  })
823
- ).describe("Defined goals (empty if none)")
842
+ ).describe("Defined goals (empty if none)"),
843
+ warnings: z6.array(z6.object({
844
+ goalName: z6.string().describe("The suspicious (probably typo) goal name"),
845
+ suggestion: z6.string().describe("The existing goal it likely meant")
846
+ })).describe("Recent goal names that look like typos of existing goals \u2014 verify before firing a new name")
824
847
  },
825
848
  annotations: {
826
849
  readOnlyHint: true,
@@ -829,23 +852,33 @@ function registerGoalTools(server, client) {
829
852
  }
830
853
  },
831
854
  withApiErrorGuidance(async ({ projectId }) => {
855
+ var _a;
832
856
  const id = encodeURIComponent(projectId);
833
857
  const data = await client.get(`/projects/${id}/goal-definitions`);
858
+ let warnings = [];
859
+ try {
860
+ const w = await client.get(
861
+ `/projects/${id}/goal-warnings`
862
+ );
863
+ warnings = ((_a = w.warnings) != null ? _a : []).map((x) => ({ goalName: x.goalName, suggestion: x.suggestion }));
864
+ } catch (e) {
865
+ }
834
866
  const structuredContent = {
835
867
  goals: data.goals.map((g) => {
836
- var _a;
868
+ var _a2;
837
869
  return {
838
870
  goalId: g.goal_id,
839
871
  displayName: g.display_name,
840
872
  role: g.role,
841
873
  event: g.event,
842
- urlPattern: (_a = g.url_pattern) != null ? _a : null,
874
+ urlPattern: (_a2 = g.url_pattern) != null ? _a2 : null,
843
875
  status: g.status,
844
876
  // NUMERIC arrives serialized as a string; coerce and tolerate its
845
877
  // absence from an older API deploy.
846
878
  defaultValue: g.default_value != null ? Number(g.default_value) : null
847
879
  };
848
- })
880
+ }),
881
+ warnings
849
882
  };
850
883
  if (!structuredContent.goals.length) {
851
884
  return {
@@ -859,14 +892,152 @@ function registerGoalTools(server, client) {
859
892
  const lines = structuredContent.goals.map(
860
893
  (g) => `${g.goalId} (${g.role}, ${g.event}${g.status === "archived" ? ", archived" : ""}) \u2014 ${g.displayName}`
861
894
  );
895
+ for (const w of warnings) {
896
+ lines.push(`\u26A0 "${w.goalName}" looks like a typo of "${w.suggestion}" \u2014 check before using it.`);
897
+ }
862
898
  lines.push("", `Reference a goalId verbatim from code: client.goal('<goalId>') or <Adaptive goal="<goalId>">.`);
863
899
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
864
900
  })
865
901
  );
866
902
  }
867
903
 
868
- // src/tools/guardrails.ts
904
+ // src/tools/funnels.ts
869
905
  import { z as z7 } from "zod";
906
+ var funnelIdSchema = z7.string().describe('Funnel slug (from list_funnels), e.g. "checkout"');
907
+ function registerFunnelTools(server, client) {
908
+ server.registerTool(
909
+ "list_funnels",
910
+ {
911
+ title: "List funnels",
912
+ description: `List the project's multi-step funnels \u2014 ordered goal steps plus the components serving them. Use get_funnel_report for a funnel's drop-off numbers. Reference a funnelId verbatim from code: <Adaptive funnel="<funnelId>">.`,
913
+ inputSchema: { projectId: projectIdSchema },
914
+ outputSchema: {
915
+ funnels: z7.array(
916
+ z7.object({
917
+ funnelId: z7.string().describe("Stable slug \u2014 use this exact string in code and in get_funnel_report"),
918
+ displayName: z7.string(),
919
+ status: z7.string().describe("draft | active | archived"),
920
+ windowDays: z7.number().describe("Conversion window in days"),
921
+ source: z7.string().describe("user | chat | editor | sdk"),
922
+ steps: z7.array(
923
+ z7.object({
924
+ stepIndex: z7.number(),
925
+ goalId: z7.string(),
926
+ weight: z7.number().nullable().describe("Manual optimizer credit for reaching this step (null = automatic end-weighted)")
927
+ })
928
+ ).describe("Ordered steps"),
929
+ components: z7.array(z7.object({ componentId: z7.string(), stepIndex: z7.number().nullable() })).describe("Components serving this funnel (stepIndex null = whole funnel)")
930
+ })
931
+ ).describe("Defined funnels (empty if none)")
932
+ },
933
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
934
+ },
935
+ withApiErrorGuidance(async ({ projectId }) => {
936
+ var _a;
937
+ const id = encodeURIComponent(projectId);
938
+ const data = await client.get(`/projects/${id}/funnels`);
939
+ const structuredContent = {
940
+ funnels: ((_a = data.funnels) != null ? _a : []).map((f) => ({
941
+ funnelId: f.funnel_id,
942
+ displayName: f.display_name,
943
+ status: f.status,
944
+ windowDays: f.window_days,
945
+ source: f.source,
946
+ // NUMERIC arrives serialized as a string; coerce.
947
+ steps: f.steps.map((s) => ({
948
+ stepIndex: s.step_index,
949
+ goalId: s.goal_id,
950
+ weight: s.weight == null ? null : Number(s.weight)
951
+ })),
952
+ components: f.components.map((c) => {
953
+ var _a2;
954
+ return { componentId: c.component_id, stepIndex: (_a2 = c.step_index) != null ? _a2 : null };
955
+ })
956
+ }))
957
+ };
958
+ if (structuredContent.funnels.length === 0) {
959
+ return {
960
+ content: [{
961
+ type: "text",
962
+ text: "No funnels defined yet. Build one in the dashboard (Goals \u2192 Funnels tab) or via the goal chat \u2014 a funnel is 2-12 ordered goal steps, e.g. add_to_cart \u2192 checkout \u2192 purchase."
963
+ }],
964
+ structuredContent
965
+ };
966
+ }
967
+ const lines = structuredContent.funnels.map(
968
+ (f) => `${f.funnelId} (${f.status}) \u2014 ${f.displayName}: ${f.steps.map((s) => s.goalId).join(" \u2192 ")}`
969
+ );
970
+ lines.push("", 'Reference a funnelId verbatim from code: <Adaptive funnel="<funnelId>">. Use get_funnel_report for drop-off numbers.');
971
+ return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
972
+ })
973
+ );
974
+ server.registerTool(
975
+ "get_funnel_report",
976
+ {
977
+ title: "Funnel drop-off report",
978
+ description: 'Per-step reach and drop-off for one funnel over its conversion window, with per-variant and audience splits per step, final-step revenue, and the holdout ("without optimization") comparison.',
979
+ inputSchema: { projectId: projectIdSchema, funnelId: funnelIdSchema },
980
+ outputSchema: {
981
+ funnelId: z7.string(),
982
+ displayName: z7.string(),
983
+ windowDays: z7.number(),
984
+ strictOrder: z7.boolean().describe("True when the chart counts a step only if the previous step happened first (reporting only \u2014 the optimizer always credits max progress)"),
985
+ currency: z7.string().describe("Project display currency (ISO-4217) for the revenue fields"),
986
+ steps: z7.array(
987
+ z7.object({
988
+ stepIndex: z7.number(),
989
+ goalId: z7.string(),
990
+ displayName: z7.string(),
991
+ reached: z7.number().describe("Distinct visitors reaching this step in-window"),
992
+ dropOffFromPrevious: z7.number().nullable().describe("1 - reached/previousReached (null on the first step)"),
993
+ neverFired: z7.boolean().describe("True when the step goal has never been recorded anywhere \u2014 likely a typo"),
994
+ variants: z7.array(z7.object({
995
+ componentId: z7.string(),
996
+ variantId: z7.string(),
997
+ reached: z7.number(),
998
+ assigned: z7.number().describe("Distinct sessions served this variant in-window (the rate denominator)")
999
+ })),
1000
+ personas: z7.array(z7.object({ label: z7.string(), reached: z7.number() }))
1001
+ })
1002
+ ),
1003
+ revenue: z7.number().nullable().describe("Final-step revenue in the project currency (null when no valued conversions)"),
1004
+ avgOrderValue: z7.number().nullable(),
1005
+ revenuePerEnteringVisitor: z7.number().nullable(),
1006
+ holdoutCompletion: z7.object({ entered: z7.number(), reached: z7.number() }).nullable().describe('Holdout visitors entering vs finishing \u2014 the "without optimization" line')
1007
+ },
1008
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
1009
+ },
1010
+ withApiErrorGuidance(async ({ projectId, funnelId }) => {
1011
+ var _a;
1012
+ const data = await client.get(`/projects/${encodeURIComponent(projectId)}/funnels/${encodeURIComponent(funnelId)}/report`);
1013
+ const lines = [`${data.displayName} \u2014 last ${data.windowDays} days`];
1014
+ for (const s of data.steps) {
1015
+ lines.push(
1016
+ `${s.stepIndex + 1}. ${s.displayName}: ${s.reached} reached` + (s.dropOffFromPrevious != null ? ` (${Math.round(s.dropOffFromPrevious * 100)}% drop-off from previous)` : "") + (s.neverFired ? " [never recorded \u2014 check the goal name]" : "")
1017
+ );
1018
+ for (const v of s.variants) {
1019
+ lines.push(` ${v.componentId}/${v.variantId}: ${v.reached}/${v.assigned} assigned sessions reached this step`);
1020
+ }
1021
+ }
1022
+ if (data.revenue != null) {
1023
+ lines.push(
1024
+ `Revenue: ${data.revenue.toFixed(2)} ${data.currency}` + (data.avgOrderValue != null ? ` (${data.avgOrderValue.toFixed(2)} ${data.currency} avg order)` : "") + (data.revenuePerEnteringVisitor != null ? `, ${data.revenuePerEnteringVisitor.toFixed(2)} ${data.currency} per entering visitor` : "")
1025
+ );
1026
+ }
1027
+ if (data.holdoutCompletion && data.holdoutCompletion.entered > 0) {
1028
+ lines.push(`Without optimization: ${data.holdoutCompletion.reached} of ${data.holdoutCompletion.entered} holdout visitors finished.`);
1029
+ }
1030
+ return {
1031
+ content: [{ type: "text", text: lines.join("\n") }],
1032
+ // Tolerate an API deployed before strict funnels existed.
1033
+ structuredContent: __spreadProps(__spreadValues({}, data), { strictOrder: (_a = data.strictOrder) != null ? _a : false })
1034
+ };
1035
+ })
1036
+ );
1037
+ }
1038
+
1039
+ // src/tools/guardrails.ts
1040
+ import { z as z8 } from "zod";
870
1041
  function registerGuardrailTools(server, client) {
871
1042
  server.registerTool(
872
1043
  "list_guardrail_events",
@@ -875,11 +1046,12 @@ function registerGuardrailTools(server, client) {
875
1046
  description: "List variants currently paused by the guardrail in the last 24 hours.",
876
1047
  inputSchema: { projectId: projectIdSchema },
877
1048
  outputSchema: {
878
- events: z7.array(
879
- z7.object({
880
- componentId: z7.string(),
881
- variantIds: z7.array(z7.string()).describe("Variants paused by the guardrail"),
882
- pausedAt: z7.string().nullable().describe("ISO timestamp the pause fired, or null")
1049
+ events: z8.array(
1050
+ z8.object({
1051
+ componentId: z8.string(),
1052
+ variantIds: z8.array(z8.string()).describe("Variants paused by the guardrail"),
1053
+ pausedAt: z8.string().nullable().describe("ISO timestamp the pause fired, or null"),
1054
+ funnelId: z8.string().nullable().describe("Set when the pause came from a funnel guardrail")
883
1055
  })
884
1056
  ).describe("Guardrail events in the last 24h (empty if none)")
885
1057
  },
@@ -893,11 +1065,15 @@ function registerGuardrailTools(server, client) {
893
1065
  const id = encodeURIComponent(projectId);
894
1066
  const data = await client.get(`/projects/${id}/guardrail-events`);
895
1067
  const structuredContent = {
896
- events: data.guardrailEvents.map((e) => ({
897
- componentId: e.componentId,
898
- variantIds: e.variantIds,
899
- pausedAt: e.pausedAt
900
- }))
1068
+ events: data.guardrailEvents.map((e) => {
1069
+ var _a;
1070
+ return {
1071
+ componentId: e.componentId,
1072
+ variantIds: e.variantIds,
1073
+ pausedAt: e.pausedAt,
1074
+ funnelId: (_a = e.funnelId) != null ? _a : null
1075
+ };
1076
+ })
901
1077
  };
902
1078
  if (!data.guardrailEvents.length) {
903
1079
  return {
@@ -906,7 +1082,7 @@ function registerGuardrailTools(server, client) {
906
1082
  };
907
1083
  }
908
1084
  const lines = data.guardrailEvents.map(
909
- (e) => `- ${e.componentId}: variants [${e.variantIds.join(", ")}] paused${e.pausedAt ? ` at ${e.pausedAt}` : ""}`
1085
+ (e) => `- ${e.componentId}: variants [${e.variantIds.join(", ")}] paused${e.pausedAt ? ` at ${e.pausedAt}` : ""}${e.funnelId ? ` (protecting the "${e.funnelId}" funnel)` : ""}`
910
1086
  );
911
1087
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
912
1088
  })
@@ -914,7 +1090,7 @@ function registerGuardrailTools(server, client) {
914
1090
  }
915
1091
 
916
1092
  // src/tools/layout.ts
917
- import { z as z8 } from "zod";
1093
+ import { z as z9 } from "zod";
918
1094
  function registerLayoutTools(server, client) {
919
1095
  server.registerTool(
920
1096
  "get_layout_stats",
@@ -924,12 +1100,12 @@ function registerLayoutTools(server, client) {
924
1100
  inputSchema: { projectId: projectIdSchema },
925
1101
  _meta: uiMeta("layout-stats"),
926
1102
  outputSchema: {
927
- layouts: z8.array(
928
- z8.object({
929
- persona: z8.string(),
930
- layoutOrder: z8.array(z8.string()).describe("Ranked section order for this persona"),
931
- pulls: z8.number().describe("Number of times this arm was served"),
932
- avgReward: z8.number().describe("Average bandit reward weight")
1103
+ layouts: z9.array(
1104
+ z9.object({
1105
+ persona: z9.string(),
1106
+ layoutOrder: z9.array(z9.string()).describe("Ranked section order for this persona"),
1107
+ pulls: z9.number().describe("Number of times this arm was served"),
1108
+ avgReward: z9.number().describe("Average bandit reward weight")
933
1109
  })
934
1110
  ).describe("Per-persona layout rankings (empty until enough sessions)")
935
1111
  },
@@ -966,7 +1142,7 @@ function registerLayoutTools(server, client) {
966
1142
  }
967
1143
 
968
1144
  // src/tools/variants.ts
969
- import { z as z9 } from "zod";
1145
+ import { z as z10 } from "zod";
970
1146
  function registerVariantWriteTools(server, client) {
971
1147
  server.registerTool(
972
1148
  "create_variant",
@@ -975,19 +1151,19 @@ function registerVariantWriteTools(server, client) {
975
1151
  description: "Create a NO-CODE managed text variant for a component (content stored in SentientUI, rendered by <AdaptiveText>). Use this ONLY for text-only variants the user wants without a code change. For variants that will live in the codebase (full components \u2014 copy, markup, styling), use get_variant_brief and write the variant in code instead; those auto-register on deploy and do not need create_variant. Requires a paid plan (server keys are Starter+; anonymous demo tokens are read-only).",
976
1152
  inputSchema: {
977
1153
  projectId: projectIdSchema,
978
- componentId: z9.string().min(1).max(200).describe("The component ID to add a variant to"),
979
- displayName: z9.string().min(1).max(200).describe("Human-readable name for the new variant"),
980
- content: z9.string().max(1e4).optional().describe("The text content for this managed variant (rendered by <AdaptiveText>). Generate it from get_variant_brief context; omit only to create an empty placeholder to fill in from the dashboard.")
1154
+ componentId: z10.string().min(1).max(200).describe("The component ID to add a variant to"),
1155
+ displayName: z10.string().min(1).max(200).describe("Human-readable name for the new variant"),
1156
+ content: z10.string().max(1e4).optional().describe("The text content for this managed variant (rendered by <AdaptiveText>). Generate it from get_variant_brief context; omit only to create an empty placeholder to fill in from the dashboard.")
981
1157
  },
982
1158
  outputSchema: {
983
- variantId: z9.string().describe("The new variant ID"),
1159
+ variantId: z10.string().describe("The new variant ID"),
984
1160
  // API returns `body.displayName ?? null`, so a successful create can
985
1161
  // carry a null name — match that contract or outputSchema validation
986
1162
  // would reject an otherwise-successful response.
987
- displayName: z9.string().nullable(),
988
- componentId: z9.string(),
989
- state: z9.literal("draft").describe("New managed variants start in draft state"),
990
- hasContent: z9.boolean().describe("Whether text content was provided at creation")
1163
+ displayName: z10.string().nullable(),
1164
+ componentId: z10.string(),
1165
+ state: z10.literal("draft").describe("New managed variants start in draft state"),
1166
+ hasContent: z10.boolean().describe("Whether text content was provided at creation")
991
1167
  },
992
1168
  annotations: {
993
1169
  readOnlyHint: false,
@@ -1025,13 +1201,13 @@ function registerVariantWriteTools(server, client) {
1025
1201
  description: "Pause a variant, stopping traffic from being assigned to it.",
1026
1202
  inputSchema: {
1027
1203
  projectId: projectIdSchema,
1028
- componentId: z9.string().describe("The component ID"),
1029
- variantId: z9.string().describe("The variant ID to pause")
1204
+ componentId: z10.string().describe("The component ID"),
1205
+ variantId: z10.string().describe("The variant ID to pause")
1030
1206
  },
1031
1207
  outputSchema: {
1032
- variantId: z9.string(),
1033
- componentId: z9.string(),
1034
- paused: z9.literal(true).describe("The variant is now paused")
1208
+ variantId: z10.string(),
1209
+ componentId: z10.string(),
1210
+ paused: z10.literal(true).describe("The variant is now paused")
1035
1211
  },
1036
1212
  annotations: {
1037
1213
  readOnlyHint: false,
@@ -1059,8 +1235,8 @@ function registerVariantWriteTools(server, client) {
1059
1235
  description: "Trigger fresh AI insight generation for a project. Returns immediately; use get_insights in ~15 seconds to see results.",
1060
1236
  inputSchema: { projectId: projectIdSchema },
1061
1237
  outputSchema: {
1062
- projectId: z9.string(),
1063
- status: z9.literal("generating").describe("Generation has been triggered")
1238
+ projectId: z10.string(),
1239
+ status: z10.literal("generating").describe("Generation has been triggered")
1064
1240
  },
1065
1241
  annotations: {
1066
1242
  readOnlyHint: false,
@@ -1084,7 +1260,7 @@ function registerVariantWriteTools(server, client) {
1084
1260
  }
1085
1261
 
1086
1262
  // src/tools/variant-brief.ts
1087
- import { z as z10 } from "zod";
1263
+ import { z as z11 } from "zod";
1088
1264
  var GOAL_TARGET = 500;
1089
1265
  var BEST_PRACTICE_PRIORS = {
1090
1266
  ecommerce: [
@@ -1157,15 +1333,15 @@ function registerVariantBriefTools(server, client) {
1157
1333
  description: "Get an insight-driven brief for creating a new CODE-NATIVE variant of a component. Returns current variant performance, audience, insights, a data-sufficiency assessment (with a best-practice fallback when there is no data yet), and step-by-step instructions for writing the variant in the customer's code. Use this instead of create_variant when the variant will live in the codebase.",
1158
1334
  inputSchema: {
1159
1335
  projectId: projectIdSchema,
1160
- componentId: z10.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1336
+ componentId: z11.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1161
1337
  },
1162
1338
  outputSchema: {
1163
- componentId: z10.string(),
1164
- contextType: z10.string().describe("The project's context type (or 'unknown')"),
1165
- dataState: z10.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1166
- existingVariantIds: z10.array(z10.string()).describe("Variant IDs already in use (do not reuse)"),
1167
- priors: z10.array(z10.string()).describe("Best-practice priors applied for this context type"),
1168
- markdown: z10.string().describe("The full variant brief in Markdown")
1339
+ componentId: z11.string(),
1340
+ contextType: z11.string().describe("The project's context type (or 'unknown')"),
1341
+ dataState: z11.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1342
+ existingVariantIds: z11.array(z11.string()).describe("Variant IDs already in use (do not reuse)"),
1343
+ priors: z11.array(z11.string()).describe("Best-practice priors applied for this context type"),
1344
+ markdown: z11.string().describe("The full variant brief in Markdown")
1169
1345
  },
1170
1346
  annotations: {
1171
1347
  readOnlyHint: true,
@@ -1282,7 +1458,7 @@ function registerVariantBriefTools(server, client) {
1282
1458
  }
1283
1459
 
1284
1460
  // src/tools/test-brief.ts
1285
- import { z as z11 } from "zod";
1461
+ import { z as z12 } from "zod";
1286
1462
  async function settled2(p) {
1287
1463
  try {
1288
1464
  return await p;
@@ -1298,13 +1474,13 @@ function registerTestBriefTools(server, client) {
1298
1474
  description: "Get a ready-to-paste test for a SentientUI-wrapped component, populated with the component's real variants and goals. This project uses @sentientui/react/testing. Use this so your tests force a specific variant/layout deterministically and never break when the optimizer serves a different version. Returns a React Testing Library example plus the URL-param recipe for E2E (Playwright/Cypress).",
1299
1475
  inputSchema: {
1300
1476
  projectId: projectIdSchema,
1301
- componentId: z11.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1477
+ componentId: z12.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1302
1478
  },
1303
1479
  outputSchema: {
1304
- componentId: z11.string(),
1305
- forcedVariantId: z11.string().describe("The non-control variant the example forces"),
1306
- goalName: z11.string().describe("The goal the example asserts fires"),
1307
- markdown: z11.string().describe("The full test brief in Markdown")
1480
+ componentId: z12.string(),
1481
+ forcedVariantId: z12.string().describe("The non-control variant the example forces"),
1482
+ goalName: z12.string().describe("The goal the example asserts fires"),
1483
+ markdown: z12.string().describe("The full test brief in Markdown")
1308
1484
  },
1309
1485
  annotations: {
1310
1486
  readOnlyHint: true,
@@ -1387,7 +1563,7 @@ function registerTestBriefTools(server, client) {
1387
1563
  }
1388
1564
 
1389
1565
  // src/tools/integration-guide.ts
1390
- import { z as z12 } from "zod";
1566
+ import { z as z13 } from "zod";
1391
1567
  var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
1392
1568
 
1393
1569
  SentientUI adapts a site per visitor type (personas: buyer, researcher, deal_seeker, browser,
@@ -1462,7 +1638,7 @@ function registerIntegrationGuideTools(server) {
1462
1638
  description: "Get the SentientUI adaptive-ladder integration guide: setup (keyless and keyed) plus copy-pasteable examples for every rung (Style, Swap, Reorder). Use this to integrate SentientUI into a codebase.",
1463
1639
  inputSchema: {},
1464
1640
  outputSchema: {
1465
- guide: z12.string().describe("The full integration guide in Markdown")
1641
+ guide: z13.string().describe("The full integration guide in Markdown")
1466
1642
  },
1467
1643
  annotations: {
1468
1644
  readOnlyHint: true,
@@ -1478,7 +1654,7 @@ function registerIntegrationGuideTools(server) {
1478
1654
  }
1479
1655
 
1480
1656
  // src/tools/agent-traffic.ts
1481
- import { z as z13 } from "zod";
1657
+ import { z as z14 } from "zod";
1482
1658
  var PLAN_GATE_GUIDANCE = {
1483
1659
  agent_analytics_requires_paid_plan: "Agent analytics requires a paid SentientUI plan (Starter or above). Upgrade at https://sentient-ui.com, then try again."
1484
1660
  };
@@ -1490,19 +1666,19 @@ function registerAgentTrafficTools(server, client) {
1490
1666
  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.",
1491
1667
  inputSchema: { projectId: projectIdSchema },
1492
1668
  outputSchema: {
1493
- totals: z13.object({ crawler: z13.number(), api: z13.number(), browser: z13.number() }),
1494
- engines: z13.array(
1495
- z13.object({
1496
- engine: z13.string(),
1497
- intent: z13.string().describe("user | search | training | other"),
1498
- count: z13.number(),
1499
- sharePct: z13.number(),
1500
- lastSeen: z13.string(),
1501
- firstSeenInRange: z13.boolean().describe("First observed within the queried period")
1669
+ totals: z14.object({ crawler: z14.number(), api: z14.number(), browser: z14.number() }),
1670
+ engines: z14.array(
1671
+ z14.object({
1672
+ engine: z14.string(),
1673
+ intent: z14.string().describe("user | search | training | other"),
1674
+ count: z14.number(),
1675
+ sharePct: z14.number(),
1676
+ lastSeen: z14.string(),
1677
+ firstSeenInRange: z14.boolean().describe("First observed within the queried period")
1502
1678
  })
1503
1679
  ),
1504
- intents: z13.object({ user: z13.number(), search: z13.number(), training: z13.number(), other: z13.number() }).describe("Crawler fetches by purpose: user = an assistant answering a real person live"),
1505
- topPaths: z13.array(z13.object({ path: z13.string(), count: z13.number(), engines: z13.number() }))
1680
+ intents: z14.object({ user: z14.number(), search: z14.number(), training: z14.number(), other: z14.number() }).describe("Crawler fetches by purpose: user = an assistant answering a real person live"),
1681
+ topPaths: z14.array(z14.object({ path: z14.string(), count: z14.number(), engines: z14.number() }))
1506
1682
  },
1507
1683
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
1508
1684
  },
@@ -1540,26 +1716,26 @@ function registerAgentTrafficTools(server, client) {
1540
1716
  description: "Whether the pages AI agents actually read are machine-legible: per-path checks for price, product name, positioning, and CTA in the server HTML, plus agent API blocks served without agent data. Each failure comes with a concrete fix.",
1541
1717
  inputSchema: { projectId: projectIdSchema },
1542
1718
  outputSchema: {
1543
- paths: z13.array(
1544
- z13.object({
1545
- path: z13.string(),
1546
- score: z13.number().describe("0\u2013100, 25 per passing check"),
1547
- checks: z13.object({
1548
- price: z13.boolean(),
1549
- name: z13.boolean(),
1550
- positioning: z13.boolean(),
1551
- cta: z13.boolean(),
1552
- notes: z13.array(z13.string())
1719
+ paths: z14.array(
1720
+ z14.object({
1721
+ path: z14.string(),
1722
+ score: z14.number().describe("0\u2013100, 25 per passing check"),
1723
+ checks: z14.object({
1724
+ price: z14.boolean(),
1725
+ name: z14.boolean(),
1726
+ positioning: z14.boolean(),
1727
+ cta: z14.boolean(),
1728
+ notes: z14.array(z14.string())
1553
1729
  }),
1554
- fixes: z13.array(z13.object({
1555
- check: z13.string(),
1556
- advice: z13.string(),
1557
- snippet: z13.string().optional()
1730
+ fixes: z14.array(z14.object({
1731
+ check: z14.string(),
1732
+ advice: z14.string(),
1733
+ snippet: z14.string().optional()
1558
1734
  })).optional().describe("Concrete Next.js remediation per failing check"),
1559
- lastChecked: z13.string()
1735
+ lastChecked: z14.string()
1560
1736
  })
1561
1737
  ),
1562
- emptyBlocks: z13.array(z13.object({ block: z13.string(), variant: z13.string(), occurrences: z13.number() }))
1738
+ emptyBlocks: z14.array(z14.object({ block: z14.string(), variant: z14.string(), occurrences: z14.number() }))
1563
1739
  },
1564
1740
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
1565
1741
  },
@@ -1596,7 +1772,7 @@ function registerAgentTrafficTools(server, client) {
1596
1772
  }
1597
1773
 
1598
1774
  // src/server.ts
1599
- var PKG_VERSION = true ? "0.12.0" : "0.0.0-dev";
1775
+ var PKG_VERSION = true ? "0.14.0" : "0.0.0-dev";
1600
1776
  function createMcpServer(client) {
1601
1777
  const server = new McpServer(
1602
1778
  {
@@ -1623,6 +1799,7 @@ function createMcpServer(client) {
1623
1799
  registerInsightTools(server, client);
1624
1800
  registerPersonaTools(server, client);
1625
1801
  registerGoalTools(server, client);
1802
+ registerFunnelTools(server, client);
1626
1803
  registerGuardrailTools(server, client);
1627
1804
  registerLayoutTools(server, client);
1628
1805
  registerVariantBriefTools(server, client);