@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.
package/dist/lib.cjs CHANGED
@@ -1,9 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
7
  var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
9
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __spreadValues = (a, b) => {
13
+ for (var prop in b || (b = {}))
14
+ if (__hasOwnProp.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ if (__getOwnPropSymbols)
17
+ for (var prop of __getOwnPropSymbols(b)) {
18
+ if (__propIsEnum.call(b, prop))
19
+ __defNormalProp(a, prop, b[prop]);
20
+ }
21
+ return a;
22
+ };
23
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
7
24
  var __export = (target, all) => {
8
25
  for (var name in all)
9
26
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -759,7 +776,7 @@ function registerGoalTools(server, client) {
759
776
  "get_goal_funnel",
760
777
  {
761
778
  title: "Goal funnel",
762
- description: "Get goal hit counts, unique-session conversion rates, and per-variant breakdown.",
779
+ 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.",
763
780
  inputSchema: { projectId: projectIdSchema },
764
781
  _meta: uiMeta("goal-funnel"),
765
782
  outputSchema: {
@@ -849,7 +866,11 @@ function registerGoalTools(server, client) {
849
866
  status: import_zod6.z.string().describe("active | archived"),
850
867
  defaultValue: import_zod6.z.number().nullable().describe("Fixed worth applied when a conversion carries no explicit value (project currency); null when unset")
851
868
  })
852
- ).describe("Defined goals (empty if none)")
869
+ ).describe("Defined goals (empty if none)"),
870
+ warnings: import_zod6.z.array(import_zod6.z.object({
871
+ goalName: import_zod6.z.string().describe("The suspicious (probably typo) goal name"),
872
+ suggestion: import_zod6.z.string().describe("The existing goal it likely meant")
873
+ })).describe("Recent goal names that look like typos of existing goals \u2014 verify before firing a new name")
853
874
  },
854
875
  annotations: {
855
876
  readOnlyHint: true,
@@ -858,23 +879,33 @@ function registerGoalTools(server, client) {
858
879
  }
859
880
  },
860
881
  withApiErrorGuidance(async ({ projectId }) => {
882
+ var _a;
861
883
  const id = encodeURIComponent(projectId);
862
884
  const data = await client.get(`/projects/${id}/goal-definitions`);
885
+ let warnings = [];
886
+ try {
887
+ const w = await client.get(
888
+ `/projects/${id}/goal-warnings`
889
+ );
890
+ warnings = ((_a = w.warnings) != null ? _a : []).map((x) => ({ goalName: x.goalName, suggestion: x.suggestion }));
891
+ } catch (e) {
892
+ }
863
893
  const structuredContent = {
864
894
  goals: data.goals.map((g) => {
865
- var _a;
895
+ var _a2;
866
896
  return {
867
897
  goalId: g.goal_id,
868
898
  displayName: g.display_name,
869
899
  role: g.role,
870
900
  event: g.event,
871
- urlPattern: (_a = g.url_pattern) != null ? _a : null,
901
+ urlPattern: (_a2 = g.url_pattern) != null ? _a2 : null,
872
902
  status: g.status,
873
903
  // NUMERIC arrives serialized as a string; coerce and tolerate its
874
904
  // absence from an older API deploy.
875
905
  defaultValue: g.default_value != null ? Number(g.default_value) : null
876
906
  };
877
- })
907
+ }),
908
+ warnings
878
909
  };
879
910
  if (!structuredContent.goals.length) {
880
911
  return {
@@ -888,14 +919,152 @@ function registerGoalTools(server, client) {
888
919
  const lines = structuredContent.goals.map(
889
920
  (g) => `${g.goalId} (${g.role}, ${g.event}${g.status === "archived" ? ", archived" : ""}) \u2014 ${g.displayName}`
890
921
  );
922
+ for (const w of warnings) {
923
+ lines.push(`\u26A0 "${w.goalName}" looks like a typo of "${w.suggestion}" \u2014 check before using it.`);
924
+ }
891
925
  lines.push("", `Reference a goalId verbatim from code: client.goal('<goalId>') or <Adaptive goal="<goalId>">.`);
892
926
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
893
927
  })
894
928
  );
895
929
  }
896
930
 
897
- // src/tools/guardrails.ts
931
+ // src/tools/funnels.ts
898
932
  var import_zod7 = require("zod");
933
+ var funnelIdSchema = import_zod7.z.string().describe('Funnel slug (from list_funnels), e.g. "checkout"');
934
+ function registerFunnelTools(server, client) {
935
+ server.registerTool(
936
+ "list_funnels",
937
+ {
938
+ title: "List funnels",
939
+ 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>">.`,
940
+ inputSchema: { projectId: projectIdSchema },
941
+ outputSchema: {
942
+ funnels: import_zod7.z.array(
943
+ import_zod7.z.object({
944
+ funnelId: import_zod7.z.string().describe("Stable slug \u2014 use this exact string in code and in get_funnel_report"),
945
+ displayName: import_zod7.z.string(),
946
+ status: import_zod7.z.string().describe("draft | active | archived"),
947
+ windowDays: import_zod7.z.number().describe("Conversion window in days"),
948
+ source: import_zod7.z.string().describe("user | chat | editor | sdk"),
949
+ steps: import_zod7.z.array(
950
+ import_zod7.z.object({
951
+ stepIndex: import_zod7.z.number(),
952
+ goalId: import_zod7.z.string(),
953
+ weight: import_zod7.z.number().nullable().describe("Manual optimizer credit for reaching this step (null = automatic end-weighted)")
954
+ })
955
+ ).describe("Ordered steps"),
956
+ components: import_zod7.z.array(import_zod7.z.object({ componentId: import_zod7.z.string(), stepIndex: import_zod7.z.number().nullable() })).describe("Components serving this funnel (stepIndex null = whole funnel)")
957
+ })
958
+ ).describe("Defined funnels (empty if none)")
959
+ },
960
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
961
+ },
962
+ withApiErrorGuidance(async ({ projectId }) => {
963
+ var _a;
964
+ const id = encodeURIComponent(projectId);
965
+ const data = await client.get(`/projects/${id}/funnels`);
966
+ const structuredContent = {
967
+ funnels: ((_a = data.funnels) != null ? _a : []).map((f) => ({
968
+ funnelId: f.funnel_id,
969
+ displayName: f.display_name,
970
+ status: f.status,
971
+ windowDays: f.window_days,
972
+ source: f.source,
973
+ // NUMERIC arrives serialized as a string; coerce.
974
+ steps: f.steps.map((s) => ({
975
+ stepIndex: s.step_index,
976
+ goalId: s.goal_id,
977
+ weight: s.weight == null ? null : Number(s.weight)
978
+ })),
979
+ components: f.components.map((c) => {
980
+ var _a2;
981
+ return { componentId: c.component_id, stepIndex: (_a2 = c.step_index) != null ? _a2 : null };
982
+ })
983
+ }))
984
+ };
985
+ if (structuredContent.funnels.length === 0) {
986
+ return {
987
+ content: [{
988
+ type: "text",
989
+ 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."
990
+ }],
991
+ structuredContent
992
+ };
993
+ }
994
+ const lines = structuredContent.funnels.map(
995
+ (f) => `${f.funnelId} (${f.status}) \u2014 ${f.displayName}: ${f.steps.map((s) => s.goalId).join(" \u2192 ")}`
996
+ );
997
+ lines.push("", 'Reference a funnelId verbatim from code: <Adaptive funnel="<funnelId>">. Use get_funnel_report for drop-off numbers.');
998
+ return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
999
+ })
1000
+ );
1001
+ server.registerTool(
1002
+ "get_funnel_report",
1003
+ {
1004
+ title: "Funnel drop-off report",
1005
+ 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.',
1006
+ inputSchema: { projectId: projectIdSchema, funnelId: funnelIdSchema },
1007
+ outputSchema: {
1008
+ funnelId: import_zod7.z.string(),
1009
+ displayName: import_zod7.z.string(),
1010
+ windowDays: import_zod7.z.number(),
1011
+ strictOrder: import_zod7.z.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)"),
1012
+ currency: import_zod7.z.string().describe("Project display currency (ISO-4217) for the revenue fields"),
1013
+ steps: import_zod7.z.array(
1014
+ import_zod7.z.object({
1015
+ stepIndex: import_zod7.z.number(),
1016
+ goalId: import_zod7.z.string(),
1017
+ displayName: import_zod7.z.string(),
1018
+ reached: import_zod7.z.number().describe("Distinct visitors reaching this step in-window"),
1019
+ dropOffFromPrevious: import_zod7.z.number().nullable().describe("1 - reached/previousReached (null on the first step)"),
1020
+ neverFired: import_zod7.z.boolean().describe("True when the step goal has never been recorded anywhere \u2014 likely a typo"),
1021
+ variants: import_zod7.z.array(import_zod7.z.object({
1022
+ componentId: import_zod7.z.string(),
1023
+ variantId: import_zod7.z.string(),
1024
+ reached: import_zod7.z.number(),
1025
+ assigned: import_zod7.z.number().describe("Distinct sessions served this variant in-window (the rate denominator)")
1026
+ })),
1027
+ personas: import_zod7.z.array(import_zod7.z.object({ label: import_zod7.z.string(), reached: import_zod7.z.number() }))
1028
+ })
1029
+ ),
1030
+ revenue: import_zod7.z.number().nullable().describe("Final-step revenue in the project currency (null when no valued conversions)"),
1031
+ avgOrderValue: import_zod7.z.number().nullable(),
1032
+ revenuePerEnteringVisitor: import_zod7.z.number().nullable(),
1033
+ holdoutCompletion: import_zod7.z.object({ entered: import_zod7.z.number(), reached: import_zod7.z.number() }).nullable().describe('Holdout visitors entering vs finishing \u2014 the "without optimization" line')
1034
+ },
1035
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
1036
+ },
1037
+ withApiErrorGuidance(async ({ projectId, funnelId }) => {
1038
+ var _a;
1039
+ const data = await client.get(`/projects/${encodeURIComponent(projectId)}/funnels/${encodeURIComponent(funnelId)}/report`);
1040
+ const lines = [`${data.displayName} \u2014 last ${data.windowDays} days`];
1041
+ for (const s of data.steps) {
1042
+ lines.push(
1043
+ `${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]" : "")
1044
+ );
1045
+ for (const v of s.variants) {
1046
+ lines.push(` ${v.componentId}/${v.variantId}: ${v.reached}/${v.assigned} assigned sessions reached this step`);
1047
+ }
1048
+ }
1049
+ if (data.revenue != null) {
1050
+ lines.push(
1051
+ `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` : "")
1052
+ );
1053
+ }
1054
+ if (data.holdoutCompletion && data.holdoutCompletion.entered > 0) {
1055
+ lines.push(`Without optimization: ${data.holdoutCompletion.reached} of ${data.holdoutCompletion.entered} holdout visitors finished.`);
1056
+ }
1057
+ return {
1058
+ content: [{ type: "text", text: lines.join("\n") }],
1059
+ // Tolerate an API deployed before strict funnels existed.
1060
+ structuredContent: __spreadProps(__spreadValues({}, data), { strictOrder: (_a = data.strictOrder) != null ? _a : false })
1061
+ };
1062
+ })
1063
+ );
1064
+ }
1065
+
1066
+ // src/tools/guardrails.ts
1067
+ var import_zod8 = require("zod");
899
1068
  function registerGuardrailTools(server, client) {
900
1069
  server.registerTool(
901
1070
  "list_guardrail_events",
@@ -904,11 +1073,12 @@ function registerGuardrailTools(server, client) {
904
1073
  description: "List variants currently paused by the guardrail in the last 24 hours.",
905
1074
  inputSchema: { projectId: projectIdSchema },
906
1075
  outputSchema: {
907
- events: import_zod7.z.array(
908
- import_zod7.z.object({
909
- componentId: import_zod7.z.string(),
910
- variantIds: import_zod7.z.array(import_zod7.z.string()).describe("Variants paused by the guardrail"),
911
- pausedAt: import_zod7.z.string().nullable().describe("ISO timestamp the pause fired, or null")
1076
+ events: import_zod8.z.array(
1077
+ import_zod8.z.object({
1078
+ componentId: import_zod8.z.string(),
1079
+ variantIds: import_zod8.z.array(import_zod8.z.string()).describe("Variants paused by the guardrail"),
1080
+ pausedAt: import_zod8.z.string().nullable().describe("ISO timestamp the pause fired, or null"),
1081
+ funnelId: import_zod8.z.string().nullable().describe("Set when the pause came from a funnel guardrail")
912
1082
  })
913
1083
  ).describe("Guardrail events in the last 24h (empty if none)")
914
1084
  },
@@ -922,11 +1092,15 @@ function registerGuardrailTools(server, client) {
922
1092
  const id = encodeURIComponent(projectId);
923
1093
  const data = await client.get(`/projects/${id}/guardrail-events`);
924
1094
  const structuredContent = {
925
- events: data.guardrailEvents.map((e) => ({
926
- componentId: e.componentId,
927
- variantIds: e.variantIds,
928
- pausedAt: e.pausedAt
929
- }))
1095
+ events: data.guardrailEvents.map((e) => {
1096
+ var _a;
1097
+ return {
1098
+ componentId: e.componentId,
1099
+ variantIds: e.variantIds,
1100
+ pausedAt: e.pausedAt,
1101
+ funnelId: (_a = e.funnelId) != null ? _a : null
1102
+ };
1103
+ })
930
1104
  };
931
1105
  if (!data.guardrailEvents.length) {
932
1106
  return {
@@ -935,7 +1109,7 @@ function registerGuardrailTools(server, client) {
935
1109
  };
936
1110
  }
937
1111
  const lines = data.guardrailEvents.map(
938
- (e) => `- ${e.componentId}: variants [${e.variantIds.join(", ")}] paused${e.pausedAt ? ` at ${e.pausedAt}` : ""}`
1112
+ (e) => `- ${e.componentId}: variants [${e.variantIds.join(", ")}] paused${e.pausedAt ? ` at ${e.pausedAt}` : ""}${e.funnelId ? ` (protecting the "${e.funnelId}" funnel)` : ""}`
939
1113
  );
940
1114
  return { content: [{ type: "text", text: lines.join("\n") }], structuredContent };
941
1115
  })
@@ -943,7 +1117,7 @@ function registerGuardrailTools(server, client) {
943
1117
  }
944
1118
 
945
1119
  // src/tools/layout.ts
946
- var import_zod8 = require("zod");
1120
+ var import_zod9 = require("zod");
947
1121
  function registerLayoutTools(server, client) {
948
1122
  server.registerTool(
949
1123
  "get_layout_stats",
@@ -953,12 +1127,12 @@ function registerLayoutTools(server, client) {
953
1127
  inputSchema: { projectId: projectIdSchema },
954
1128
  _meta: uiMeta("layout-stats"),
955
1129
  outputSchema: {
956
- layouts: import_zod8.z.array(
957
- import_zod8.z.object({
958
- persona: import_zod8.z.string(),
959
- layoutOrder: import_zod8.z.array(import_zod8.z.string()).describe("Ranked section order for this persona"),
960
- pulls: import_zod8.z.number().describe("Number of times this arm was served"),
961
- avgReward: import_zod8.z.number().describe("Average bandit reward weight")
1130
+ layouts: import_zod9.z.array(
1131
+ import_zod9.z.object({
1132
+ persona: import_zod9.z.string(),
1133
+ layoutOrder: import_zod9.z.array(import_zod9.z.string()).describe("Ranked section order for this persona"),
1134
+ pulls: import_zod9.z.number().describe("Number of times this arm was served"),
1135
+ avgReward: import_zod9.z.number().describe("Average bandit reward weight")
962
1136
  })
963
1137
  ).describe("Per-persona layout rankings (empty until enough sessions)")
964
1138
  },
@@ -995,7 +1169,7 @@ function registerLayoutTools(server, client) {
995
1169
  }
996
1170
 
997
1171
  // src/tools/variants.ts
998
- var import_zod9 = require("zod");
1172
+ var import_zod10 = require("zod");
999
1173
  function registerVariantWriteTools(server, client) {
1000
1174
  server.registerTool(
1001
1175
  "create_variant",
@@ -1004,19 +1178,19 @@ function registerVariantWriteTools(server, client) {
1004
1178
  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).",
1005
1179
  inputSchema: {
1006
1180
  projectId: projectIdSchema,
1007
- componentId: import_zod9.z.string().min(1).max(200).describe("The component ID to add a variant to"),
1008
- displayName: import_zod9.z.string().min(1).max(200).describe("Human-readable name for the new variant"),
1009
- content: import_zod9.z.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.")
1181
+ componentId: import_zod10.z.string().min(1).max(200).describe("The component ID to add a variant to"),
1182
+ displayName: import_zod10.z.string().min(1).max(200).describe("Human-readable name for the new variant"),
1183
+ content: import_zod10.z.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.")
1010
1184
  },
1011
1185
  outputSchema: {
1012
- variantId: import_zod9.z.string().describe("The new variant ID"),
1186
+ variantId: import_zod10.z.string().describe("The new variant ID"),
1013
1187
  // API returns `body.displayName ?? null`, so a successful create can
1014
1188
  // carry a null name — match that contract or outputSchema validation
1015
1189
  // would reject an otherwise-successful response.
1016
- displayName: import_zod9.z.string().nullable(),
1017
- componentId: import_zod9.z.string(),
1018
- state: import_zod9.z.literal("draft").describe("New managed variants start in draft state"),
1019
- hasContent: import_zod9.z.boolean().describe("Whether text content was provided at creation")
1190
+ displayName: import_zod10.z.string().nullable(),
1191
+ componentId: import_zod10.z.string(),
1192
+ state: import_zod10.z.literal("draft").describe("New managed variants start in draft state"),
1193
+ hasContent: import_zod10.z.boolean().describe("Whether text content was provided at creation")
1020
1194
  },
1021
1195
  annotations: {
1022
1196
  readOnlyHint: false,
@@ -1054,13 +1228,13 @@ function registerVariantWriteTools(server, client) {
1054
1228
  description: "Pause a variant, stopping traffic from being assigned to it.",
1055
1229
  inputSchema: {
1056
1230
  projectId: projectIdSchema,
1057
- componentId: import_zod9.z.string().describe("The component ID"),
1058
- variantId: import_zod9.z.string().describe("The variant ID to pause")
1231
+ componentId: import_zod10.z.string().describe("The component ID"),
1232
+ variantId: import_zod10.z.string().describe("The variant ID to pause")
1059
1233
  },
1060
1234
  outputSchema: {
1061
- variantId: import_zod9.z.string(),
1062
- componentId: import_zod9.z.string(),
1063
- paused: import_zod9.z.literal(true).describe("The variant is now paused")
1235
+ variantId: import_zod10.z.string(),
1236
+ componentId: import_zod10.z.string(),
1237
+ paused: import_zod10.z.literal(true).describe("The variant is now paused")
1064
1238
  },
1065
1239
  annotations: {
1066
1240
  readOnlyHint: false,
@@ -1088,8 +1262,8 @@ function registerVariantWriteTools(server, client) {
1088
1262
  description: "Trigger fresh AI insight generation for a project. Returns immediately; use get_insights in ~15 seconds to see results.",
1089
1263
  inputSchema: { projectId: projectIdSchema },
1090
1264
  outputSchema: {
1091
- projectId: import_zod9.z.string(),
1092
- status: import_zod9.z.literal("generating").describe("Generation has been triggered")
1265
+ projectId: import_zod10.z.string(),
1266
+ status: import_zod10.z.literal("generating").describe("Generation has been triggered")
1093
1267
  },
1094
1268
  annotations: {
1095
1269
  readOnlyHint: false,
@@ -1113,7 +1287,7 @@ function registerVariantWriteTools(server, client) {
1113
1287
  }
1114
1288
 
1115
1289
  // src/tools/variant-brief.ts
1116
- var import_zod10 = require("zod");
1290
+ var import_zod11 = require("zod");
1117
1291
  var GOAL_TARGET = 500;
1118
1292
  var BEST_PRACTICE_PRIORS = {
1119
1293
  ecommerce: [
@@ -1186,15 +1360,15 @@ function registerVariantBriefTools(server, client) {
1186
1360
  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.",
1187
1361
  inputSchema: {
1188
1362
  projectId: projectIdSchema,
1189
- componentId: import_zod10.z.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1363
+ componentId: import_zod11.z.string().describe('The component ID to write a new variant for (matches <Adaptive id="...">).')
1190
1364
  },
1191
1365
  outputSchema: {
1192
- componentId: import_zod10.z.string(),
1193
- contextType: import_zod10.z.string().describe("The project's context type (or 'unknown')"),
1194
- dataState: import_zod10.z.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1195
- existingVariantIds: import_zod10.z.array(import_zod10.z.string()).describe("Variant IDs already in use (do not reuse)"),
1196
- priors: import_zod10.z.array(import_zod10.z.string()).describe("Best-practice priors applied for this context type"),
1197
- markdown: import_zod10.z.string().describe("The full variant brief in Markdown")
1366
+ componentId: import_zod11.z.string(),
1367
+ contextType: import_zod11.z.string().describe("The project's context type (or 'unknown')"),
1368
+ dataState: import_zod11.z.enum(["sufficient", "collecting", "empty"]).describe("Data-sufficiency assessment"),
1369
+ existingVariantIds: import_zod11.z.array(import_zod11.z.string()).describe("Variant IDs already in use (do not reuse)"),
1370
+ priors: import_zod11.z.array(import_zod11.z.string()).describe("Best-practice priors applied for this context type"),
1371
+ markdown: import_zod11.z.string().describe("The full variant brief in Markdown")
1198
1372
  },
1199
1373
  annotations: {
1200
1374
  readOnlyHint: true,
@@ -1311,7 +1485,7 @@ function registerVariantBriefTools(server, client) {
1311
1485
  }
1312
1486
 
1313
1487
  // src/tools/test-brief.ts
1314
- var import_zod11 = require("zod");
1488
+ var import_zod12 = require("zod");
1315
1489
  async function settled2(p) {
1316
1490
  try {
1317
1491
  return await p;
@@ -1327,13 +1501,13 @@ function registerTestBriefTools(server, client) {
1327
1501
  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).",
1328
1502
  inputSchema: {
1329
1503
  projectId: projectIdSchema,
1330
- componentId: import_zod11.z.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1504
+ componentId: import_zod12.z.string().describe('The component ID to write a test for (matches <Adaptive id="...">).')
1331
1505
  },
1332
1506
  outputSchema: {
1333
- componentId: import_zod11.z.string(),
1334
- forcedVariantId: import_zod11.z.string().describe("The non-control variant the example forces"),
1335
- goalName: import_zod11.z.string().describe("The goal the example asserts fires"),
1336
- markdown: import_zod11.z.string().describe("The full test brief in Markdown")
1507
+ componentId: import_zod12.z.string(),
1508
+ forcedVariantId: import_zod12.z.string().describe("The non-control variant the example forces"),
1509
+ goalName: import_zod12.z.string().describe("The goal the example asserts fires"),
1510
+ markdown: import_zod12.z.string().describe("The full test brief in Markdown")
1337
1511
  },
1338
1512
  annotations: {
1339
1513
  readOnlyHint: true,
@@ -1416,7 +1590,7 @@ function registerTestBriefTools(server, client) {
1416
1590
  }
1417
1591
 
1418
1592
  // src/tools/integration-guide.ts
1419
- var import_zod12 = require("zod");
1593
+ var import_zod13 = require("zod");
1420
1594
  var GUIDE = `# SentientUI integration guide \u2014 the adaptive ladder
1421
1595
 
1422
1596
  SentientUI adapts a site per visitor type (personas: buyer, researcher, deal_seeker, browser,
@@ -1491,7 +1665,7 @@ function registerIntegrationGuideTools(server) {
1491
1665
  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.",
1492
1666
  inputSchema: {},
1493
1667
  outputSchema: {
1494
- guide: import_zod12.z.string().describe("The full integration guide in Markdown")
1668
+ guide: import_zod13.z.string().describe("The full integration guide in Markdown")
1495
1669
  },
1496
1670
  annotations: {
1497
1671
  readOnlyHint: true,
@@ -1507,7 +1681,7 @@ function registerIntegrationGuideTools(server) {
1507
1681
  }
1508
1682
 
1509
1683
  // src/tools/agent-traffic.ts
1510
- var import_zod13 = require("zod");
1684
+ var import_zod14 = require("zod");
1511
1685
  var PLAN_GATE_GUIDANCE = {
1512
1686
  agent_analytics_requires_paid_plan: "Agent analytics requires a paid SentientUI plan (Starter or above). Upgrade at https://sentient-ui.com, then try again."
1513
1687
  };
@@ -1519,19 +1693,19 @@ function registerAgentTrafficTools(server, client) {
1519
1693
  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.",
1520
1694
  inputSchema: { projectId: projectIdSchema },
1521
1695
  outputSchema: {
1522
- totals: import_zod13.z.object({ crawler: import_zod13.z.number(), api: import_zod13.z.number(), browser: import_zod13.z.number() }),
1523
- engines: import_zod13.z.array(
1524
- import_zod13.z.object({
1525
- engine: import_zod13.z.string(),
1526
- intent: import_zod13.z.string().describe("user | search | training | other"),
1527
- count: import_zod13.z.number(),
1528
- sharePct: import_zod13.z.number(),
1529
- lastSeen: import_zod13.z.string(),
1530
- firstSeenInRange: import_zod13.z.boolean().describe("First observed within the queried period")
1696
+ totals: import_zod14.z.object({ crawler: import_zod14.z.number(), api: import_zod14.z.number(), browser: import_zod14.z.number() }),
1697
+ engines: import_zod14.z.array(
1698
+ import_zod14.z.object({
1699
+ engine: import_zod14.z.string(),
1700
+ intent: import_zod14.z.string().describe("user | search | training | other"),
1701
+ count: import_zod14.z.number(),
1702
+ sharePct: import_zod14.z.number(),
1703
+ lastSeen: import_zod14.z.string(),
1704
+ firstSeenInRange: import_zod14.z.boolean().describe("First observed within the queried period")
1531
1705
  })
1532
1706
  ),
1533
- intents: import_zod13.z.object({ user: import_zod13.z.number(), search: import_zod13.z.number(), training: import_zod13.z.number(), other: import_zod13.z.number() }).describe("Crawler fetches by purpose: user = an assistant answering a real person live"),
1534
- topPaths: import_zod13.z.array(import_zod13.z.object({ path: import_zod13.z.string(), count: import_zod13.z.number(), engines: import_zod13.z.number() }))
1707
+ intents: import_zod14.z.object({ user: import_zod14.z.number(), search: import_zod14.z.number(), training: import_zod14.z.number(), other: import_zod14.z.number() }).describe("Crawler fetches by purpose: user = an assistant answering a real person live"),
1708
+ topPaths: import_zod14.z.array(import_zod14.z.object({ path: import_zod14.z.string(), count: import_zod14.z.number(), engines: import_zod14.z.number() }))
1535
1709
  },
1536
1710
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
1537
1711
  },
@@ -1569,26 +1743,26 @@ function registerAgentTrafficTools(server, client) {
1569
1743
  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.",
1570
1744
  inputSchema: { projectId: projectIdSchema },
1571
1745
  outputSchema: {
1572
- paths: import_zod13.z.array(
1573
- import_zod13.z.object({
1574
- path: import_zod13.z.string(),
1575
- score: import_zod13.z.number().describe("0\u2013100, 25 per passing check"),
1576
- checks: import_zod13.z.object({
1577
- price: import_zod13.z.boolean(),
1578
- name: import_zod13.z.boolean(),
1579
- positioning: import_zod13.z.boolean(),
1580
- cta: import_zod13.z.boolean(),
1581
- notes: import_zod13.z.array(import_zod13.z.string())
1746
+ paths: import_zod14.z.array(
1747
+ import_zod14.z.object({
1748
+ path: import_zod14.z.string(),
1749
+ score: import_zod14.z.number().describe("0\u2013100, 25 per passing check"),
1750
+ checks: import_zod14.z.object({
1751
+ price: import_zod14.z.boolean(),
1752
+ name: import_zod14.z.boolean(),
1753
+ positioning: import_zod14.z.boolean(),
1754
+ cta: import_zod14.z.boolean(),
1755
+ notes: import_zod14.z.array(import_zod14.z.string())
1582
1756
  }),
1583
- fixes: import_zod13.z.array(import_zod13.z.object({
1584
- check: import_zod13.z.string(),
1585
- advice: import_zod13.z.string(),
1586
- snippet: import_zod13.z.string().optional()
1757
+ fixes: import_zod14.z.array(import_zod14.z.object({
1758
+ check: import_zod14.z.string(),
1759
+ advice: import_zod14.z.string(),
1760
+ snippet: import_zod14.z.string().optional()
1587
1761
  })).optional().describe("Concrete Next.js remediation per failing check"),
1588
- lastChecked: import_zod13.z.string()
1762
+ lastChecked: import_zod14.z.string()
1589
1763
  })
1590
1764
  ),
1591
- emptyBlocks: import_zod13.z.array(import_zod13.z.object({ block: import_zod13.z.string(), variant: import_zod13.z.string(), occurrences: import_zod13.z.number() }))
1765
+ emptyBlocks: import_zod14.z.array(import_zod14.z.object({ block: import_zod14.z.string(), variant: import_zod14.z.string(), occurrences: import_zod14.z.number() }))
1592
1766
  },
1593
1767
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
1594
1768
  },
@@ -1625,7 +1799,7 @@ function registerAgentTrafficTools(server, client) {
1625
1799
  }
1626
1800
 
1627
1801
  // src/server.ts
1628
- var PKG_VERSION = true ? "0.12.0" : "0.0.0-dev";
1802
+ var PKG_VERSION = true ? "0.14.0" : "0.0.0-dev";
1629
1803
  function createMcpServer(client) {
1630
1804
  const server = new import_mcp.McpServer(
1631
1805
  {
@@ -1652,6 +1826,7 @@ function createMcpServer(client) {
1652
1826
  registerInsightTools(server, client);
1653
1827
  registerPersonaTools(server, client);
1654
1828
  registerGoalTools(server, client);
1829
+ registerFunnelTools(server, client);
1655
1830
  registerGuardrailTools(server, client);
1656
1831
  registerLayoutTools(server, client);
1657
1832
  registerVariantBriefTools(server, client);
package/dist/lib.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  ApiClient,
4
4
  ApiError,
5
5
  createMcpServer
6
- } from "./chunk-BMOKDBGH.js";
6
+ } from "./chunk-DZLODBXR.js";
7
7
  export {
8
8
  ApiClient,
9
9
  ApiError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentientui/mcp",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "MCP server for SentientUI — exposes project data and actions to AI agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://sentient-ui.com",