@recapt/mcp 0.0.19-beta → 0.0.20

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.
Files changed (93) hide show
  1. package/dist/cli/index.d.ts +0 -11
  2. package/dist/cli/index.js +1059 -21
  3. package/dist/index.d.ts +0 -19
  4. package/dist/index.js +3210 -89
  5. package/package.json +5 -3
  6. package/dist/api/client.d.ts +0 -6
  7. package/dist/api/client.js +0 -6
  8. package/dist/cli/commands/setup-self-improvement-gh.d.ts +0 -7
  9. package/dist/cli/commands/setup-self-improvement-gh.js +0 -310
  10. package/dist/cli/commands/setup.d.ts +0 -7
  11. package/dist/cli/commands/setup.js +0 -178
  12. package/dist/cli/commands/skill.d.ts +0 -24
  13. package/dist/cli/commands/skill.js +0 -264
  14. package/dist/cli/utils/ide-config.d.ts +0 -31
  15. package/dist/cli/utils/ide-config.js +0 -294
  16. package/dist/cli/utils/prompts.d.ts +0 -22
  17. package/dist/cli/utils/prompts.js +0 -71
  18. package/dist/tools/analyzeFlow.d.ts +0 -7
  19. package/dist/tools/analyzeFlow.js +0 -68
  20. package/dist/tools/analyzeFunnel.d.ts +0 -7
  21. package/dist/tools/analyzeFunnel.js +0 -63
  22. package/dist/tools/catalog/callTool.d.ts +0 -22
  23. package/dist/tools/catalog/callTool.js +0 -92
  24. package/dist/tools/catalog/index.d.ts +0 -11
  25. package/dist/tools/catalog/index.js +0 -11
  26. package/dist/tools/catalog/searchTools.d.ts +0 -22
  27. package/dist/tools/catalog/searchTools.js +0 -194
  28. package/dist/tools/compareCohorts.d.ts +0 -6
  29. package/dist/tools/compareCohorts.js +0 -84
  30. package/dist/tools/comparePeriods.d.ts +0 -6
  31. package/dist/tools/comparePeriods.js +0 -54
  32. package/dist/tools/detectDrift.d.ts +0 -6
  33. package/dist/tools/detectDrift.js +0 -55
  34. package/dist/tools/detectRegressions.d.ts +0 -6
  35. package/dist/tools/detectRegressions.js +0 -63
  36. package/dist/tools/diagnostic.d.ts +0 -6
  37. package/dist/tools/diagnostic.js +0 -109
  38. package/dist/tools/discoverPersonas.d.ts +0 -6
  39. package/dist/tools/discoverPersonas.js +0 -50
  40. package/dist/tools/getActionableIssues.d.ts +0 -7
  41. package/dist/tools/getActionableIssues.js +0 -55
  42. package/dist/tools/getAnomalies.d.ts +0 -6
  43. package/dist/tools/getAnomalies.js +0 -53
  44. package/dist/tools/getConsoleErrors.d.ts +0 -6
  45. package/dist/tools/getConsoleErrors.js +0 -61
  46. package/dist/tools/getDeadClicks.d.ts +0 -6
  47. package/dist/tools/getDeadClicks.js +0 -42
  48. package/dist/tools/getDomains.d.ts +0 -6
  49. package/dist/tools/getDomains.js +0 -34
  50. package/dist/tools/getElementFriction.d.ts +0 -6
  51. package/dist/tools/getElementFriction.js +0 -45
  52. package/dist/tools/getFlowFriction.d.ts +0 -7
  53. package/dist/tools/getFlowFriction.js +0 -57
  54. package/dist/tools/getFormFriction.d.ts +0 -6
  55. package/dist/tools/getFormFriction.js +0 -42
  56. package/dist/tools/getIssues.d.ts +0 -6
  57. package/dist/tools/getIssues.js +0 -82
  58. package/dist/tools/getJourneyPatterns.d.ts +0 -7
  59. package/dist/tools/getJourneyPatterns.js +0 -50
  60. package/dist/tools/getPageMetrics.d.ts +0 -6
  61. package/dist/tools/getPageMetrics.js +0 -47
  62. package/dist/tools/getPageTrends.d.ts +0 -6
  63. package/dist/tools/getPageTrends.js +0 -46
  64. package/dist/tools/getSessionDetails.d.ts +0 -6
  65. package/dist/tools/getSessionDetails.js +0 -70
  66. package/dist/tools/getSessionPages.d.ts +0 -7
  67. package/dist/tools/getSessionPages.js +0 -74
  68. package/dist/tools/getUxHealthReport.d.ts +0 -7
  69. package/dist/tools/getUxHealthReport.js +0 -50
  70. package/dist/tools/improvementRun.d.ts +0 -6
  71. package/dist/tools/improvementRun.js +0 -386
  72. package/dist/tools/knowledge.d.ts +0 -6
  73. package/dist/tools/knowledge.js +0 -186
  74. package/dist/tools/listPages.d.ts +0 -6
  75. package/dist/tools/listPages.js +0 -50
  76. package/dist/tools/listSessions.d.ts +0 -7
  77. package/dist/tools/listSessions.js +0 -67
  78. package/dist/tools/memory.d.ts +0 -7
  79. package/dist/tools/memory.js +0 -119
  80. package/dist/tools/predictOutcomes.d.ts +0 -6
  81. package/dist/tools/predictOutcomes.js +0 -66
  82. package/dist/tools/remediation.d.ts +0 -6
  83. package/dist/tools/remediation.js +0 -335
  84. package/dist/tools/scanSite.d.ts +0 -6
  85. package/dist/tools/scanSite.js +0 -51
  86. package/dist/tools/searchSessions.d.ts +0 -6
  87. package/dist/tools/searchSessions.js +0 -51
  88. package/dist/tools/triage.d.ts +0 -6
  89. package/dist/tools/triage.js +0 -114
  90. package/dist/tools/triageSessions.d.ts +0 -8
  91. package/dist/tools/triageSessions.js +0 -197
  92. package/dist/tools/upgradeOptions.d.ts +0 -7
  93. package/dist/tools/upgradeOptions.js +0 -67
@@ -1,68 +0,0 @@
1
- /**
2
- * analyze_flow tool
3
- *
4
- * Analyzes user navigation flows between pages.
5
- * Thin proxy to external-api /flows/analyze endpoint.
6
- */
7
- import { z } from "zod";
8
- import { apiPost, isApiConfigured } from "../api/client.js";
9
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
- export function registerAnalyzeFlow(server) {
11
- server.registerTool("analyze_flow", {
12
- description: "Analyze user navigation flows between pages. Returns paths with steps, " +
13
- "behavioral metrics (frustration, confusion), success rates, and bottlenecks. " +
14
- "Use this to understand how users navigate between specific pages.",
15
- inputSchema: z.object({
16
- start_page: z
17
- .string()
18
- .optional()
19
- .describe("Starting page path (e.g., /pricing). Partial match supported."),
20
- end_page: z
21
- .string()
22
- .optional()
23
- .describe("Ending page path (e.g., /checkout). Partial match supported."),
24
- days: z
25
- .number()
26
- .optional()
27
- .default(7)
28
- .describe("Number of days to analyze (default: 7)"),
29
- }),
30
- }, async ({ start_page, end_page, days, }) => {
31
- if (!isApiConfigured()) {
32
- return {
33
- content: [
34
- {
35
- type: "text",
36
- text: JSON.stringify({ error: "API not configured" }),
37
- },
38
- ],
39
- isError: true,
40
- };
41
- }
42
- if (!start_page && !end_page) {
43
- return {
44
- content: [
45
- {
46
- type: "text",
47
- text: JSON.stringify({
48
- error: "At least one of start_page or end_page is required",
49
- }),
50
- },
51
- ],
52
- isError: true,
53
- };
54
- }
55
- const { data, error } = await apiPost("/flows/analyze", {
56
- start_page,
57
- end_page,
58
- days: days ?? 7,
59
- });
60
- if (error) {
61
- return {
62
- content: [{ type: "text", text: JSON.stringify({ error }) }],
63
- isError: true,
64
- };
65
- }
66
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
67
- });
68
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * analyze_funnel tool
3
- *
4
- * Analyzes conversion funnels through a defined sequence of pages.
5
- * Thin proxy to external-api /flows/funnel endpoint.
6
- */
7
- export declare function registerAnalyzeFunnel(server: any): void;
@@ -1,63 +0,0 @@
1
- /**
2
- * analyze_funnel tool
3
- *
4
- * Analyzes conversion funnels through a defined sequence of pages.
5
- * Thin proxy to external-api /flows/funnel endpoint.
6
- */
7
- import { z } from "zod";
8
- import { apiPost, isApiConfigured } from "../api/client.js";
9
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
- export function registerAnalyzeFunnel(server) {
11
- server.registerTool("analyze_funnel", {
12
- description: "Analyze a conversion funnel through a sequence of pages. Returns per-step metrics " +
13
- "(entered, converted, dropped, dwell time, frustration, confusion) and dropoff analysis " +
14
- 'showing where users exit. Supports wildcards: "/checkout*" matches all checkout pages.',
15
- inputSchema: z.object({
16
- steps: z
17
- .array(z.string())
18
- .min(2)
19
- .describe('Ordered page paths forming the funnel (e.g., ["/cart", "/checkout", "/payment"])'),
20
- days: z
21
- .number()
22
- .optional()
23
- .default(7)
24
- .describe("Number of days to analyze (default: 7)"),
25
- }),
26
- }, async ({ steps, days }) => {
27
- if (!isApiConfigured()) {
28
- return {
29
- content: [
30
- {
31
- type: "text",
32
- text: JSON.stringify({ error: "API not configured" }),
33
- },
34
- ],
35
- isError: true,
36
- };
37
- }
38
- if (!steps || steps.length < 2) {
39
- return {
40
- content: [
41
- {
42
- type: "text",
43
- text: JSON.stringify({
44
- error: "At least 2 steps are required for funnel analysis",
45
- }),
46
- },
47
- ],
48
- isError: true,
49
- };
50
- }
51
- const { data, error } = await apiPost("/flows/funnel", {
52
- steps,
53
- days: days ?? 7,
54
- });
55
- if (error) {
56
- return {
57
- content: [{ type: "text", text: JSON.stringify({ error }) }],
58
- isError: true,
59
- };
60
- }
61
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
62
- });
63
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * Call Tool — Universal tool proxy for executing any tool by name.
3
- *
4
- * This tool allows the agent to invoke ANY tool by name without having
5
- * all tool descriptions in context. The agent discovers tools via search_tools,
6
- * then calls them through this proxy.
7
- *
8
- * Benefits:
9
- * - Minimal context: Only ~10 tools have descriptions in the prompt
10
- * - All 40+ analysis tools accessible on-demand
11
- * - Scales to any number of tools without context bloat
12
- */
13
- export type ToolHandler = (args: Record<string, unknown>) => Promise<{
14
- content: Array<{
15
- type: string;
16
- text: string;
17
- }>;
18
- isError?: boolean;
19
- }>;
20
- export declare function registerToolHandler(name: string, handler: ToolHandler): void;
21
- export declare function getToolHandler(name: string): ToolHandler | undefined;
22
- export declare function registerCallTool(server: any): void;
@@ -1,92 +0,0 @@
1
- /**
2
- * Call Tool — Universal tool proxy for executing any tool by name.
3
- *
4
- * This tool allows the agent to invoke ANY tool by name without having
5
- * all tool descriptions in context. The agent discovers tools via search_tools,
6
- * then calls them through this proxy.
7
- *
8
- * Benefits:
9
- * - Minimal context: Only ~10 tools have descriptions in the prompt
10
- * - All 40+ analysis tools accessible on-demand
11
- * - Scales to any number of tools without context bloat
12
- */
13
- import { z } from "zod";
14
- import { getToolByName } from "./searchTools.js";
15
- const toolRegistry = new Map();
16
- export function registerToolHandler(name, handler) {
17
- toolRegistry.set(name, handler);
18
- }
19
- export function getToolHandler(name) {
20
- return toolRegistry.get(name);
21
- }
22
- const callToolSchema = z.object({
23
- tool_name: z
24
- .string()
25
- .describe("The exact name of the tool to call (e.g., 'get_page_metrics', 'analyze_flow', 'compare_cohorts')"),
26
- arguments: z
27
- .record(z.string(), z.unknown())
28
- .describe("The arguments to pass to the tool as a JSON object. Check the tool description from search_tools for required parameters."),
29
- });
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- export function registerCallTool(server) {
32
- server.registerTool("call_tool", {
33
- description: "Execute any analysis tool by name. Use search_tools first to discover available tools, " +
34
- "then call them through this proxy. Pass the exact tool name and arguments as a JSON object. " +
35
- "Example: call_tool({ tool_name: 'get_page_metrics', arguments: { page_path: '/checkout' } })",
36
- inputSchema: callToolSchema,
37
- }, async ({ tool_name, arguments: args }) => {
38
- const handler = toolRegistry.get(tool_name);
39
- if (!handler) {
40
- const catalogEntry = getToolByName(tool_name);
41
- if (catalogEntry) {
42
- return {
43
- content: [
44
- {
45
- type: "text",
46
- text: JSON.stringify({
47
- error: `Tool "${tool_name}" exists in catalog but is not registered. This may be a server configuration issue.`,
48
- tool_info: {
49
- name: catalogEntry.name,
50
- description: catalogEntry.description,
51
- category: catalogEntry.category,
52
- },
53
- }),
54
- },
55
- ],
56
- isError: true,
57
- };
58
- }
59
- return {
60
- content: [
61
- {
62
- type: "text",
63
- text: JSON.stringify({
64
- error: `Unknown tool: ${tool_name}`,
65
- hint: "Use search_tools to discover available tools first.",
66
- }),
67
- },
68
- ],
69
- isError: true,
70
- };
71
- }
72
- try {
73
- return await handler(args);
74
- }
75
- catch (err) {
76
- const message = err instanceof Error ? err.message : String(err);
77
- return {
78
- content: [
79
- {
80
- type: "text",
81
- text: JSON.stringify({
82
- error: `Tool execution failed: ${message}`,
83
- tool_name,
84
- arguments: args,
85
- }),
86
- },
87
- ],
88
- isError: true,
89
- };
90
- }
91
- });
92
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Tool Catalog — Registry and discovery for MCP tools.
3
- *
4
- * Exports:
5
- * - searchTools: Find tools by natural language query
6
- * - registerSearchTools: Register the search_tools MCP tool
7
- * - registerCallTool: Register the call_tool MCP tool
8
- * - registerToolHandler: Register a tool handler for call_tool to invoke
9
- */
10
- export { searchTools, getToolByName, getAllTools, registerSearchTools, type ToolEntry, } from "./searchTools.js";
11
- export { registerCallTool, registerToolHandler, getToolHandler, type ToolHandler, } from "./callTool.js";
@@ -1,11 +0,0 @@
1
- /**
2
- * Tool Catalog — Registry and discovery for MCP tools.
3
- *
4
- * Exports:
5
- * - searchTools: Find tools by natural language query
6
- * - registerSearchTools: Register the search_tools MCP tool
7
- * - registerCallTool: Register the call_tool MCP tool
8
- * - registerToolHandler: Register a tool handler for call_tool to invoke
9
- */
10
- export { searchTools, getToolByName, getAllTools, registerSearchTools, } from "./searchTools.js";
11
- export { registerCallTool, registerToolHandler, getToolHandler, } from "./callTool.js";
@@ -1,22 +0,0 @@
1
- /**
2
- * Search Tools — Semantic and keyword search over the tool catalog.
3
- *
4
- * Allows the agent to discover specialized tools by describing what
5
- * it needs in natural language. Uses pre-computed embeddings for
6
- * fast, accurate matching with fallback to keyword search.
7
- */
8
- export interface ToolEntry {
9
- name: string;
10
- description: string;
11
- category: string;
12
- parameters: Record<string, {
13
- type: string;
14
- required?: boolean;
15
- description?: string;
16
- }>;
17
- embedding: number[];
18
- }
19
- export declare function searchTools(query: string, limit?: number, queryEmbedding?: number[]): Promise<ToolEntry[]>;
20
- export declare function getToolByName(name: string): ToolEntry | undefined;
21
- export declare function getAllTools(): ToolEntry[];
22
- export declare function registerSearchTools(server: any): void;
@@ -1,194 +0,0 @@
1
- /**
2
- * Search Tools — Semantic and keyword search over the tool catalog.
3
- *
4
- * Allows the agent to discover specialized tools by describing what
5
- * it needs in natural language. Uses pre-computed embeddings for
6
- * fast, accurate matching with fallback to keyword search.
7
- */
8
- import { z } from "zod";
9
- import { readFileSync } from "node:fs";
10
- import { fileURLToPath } from "node:url";
11
- import { dirname, join } from "node:path";
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = dirname(__filename);
14
- let _catalog = null;
15
- function loadCatalog() {
16
- if (_catalog)
17
- return _catalog;
18
- try {
19
- const catalogPath = join(__dirname, "toolCatalog.json");
20
- const raw = readFileSync(catalogPath, "utf-8");
21
- _catalog = JSON.parse(raw);
22
- return _catalog;
23
- }
24
- catch {
25
- console.warn("[searchTools] Failed to load toolCatalog.json, using empty catalog");
26
- _catalog = [];
27
- return _catalog;
28
- }
29
- }
30
- function cosineSimilarity(a, b) {
31
- if (a.length === 0 || b.length === 0 || a.length !== b.length)
32
- return 0;
33
- let dot = 0;
34
- for (let i = 0; i < a.length; i++) {
35
- dot += a[i] * b[i];
36
- }
37
- return dot;
38
- }
39
- function searchByKeyword(query, limit) {
40
- const catalog = loadCatalog();
41
- const normalizedQuery = query.toLowerCase();
42
- // Extract words, keeping short ones that might be meaningful (e.g., "ux", "js")
43
- const queryWords = normalizedQuery
44
- .split(/[\s_-]+/)
45
- .filter((w) => w.length >= 2);
46
- // Also check for the full query as a phrase
47
- const queryPhrases = [normalizedQuery];
48
- // Common synonyms and related terms
49
- const synonyms = {
50
- error: ["console", "js", "javascript", "bug", "crash", "exception"],
51
- page: ["pages", "route", "url", "path"],
52
- user: ["users", "session", "visitor"],
53
- click: ["clicks", "tap", "press", "rage"],
54
- form: ["forms", "input", "field", "submit"],
55
- flow: ["flows", "journey", "funnel", "navigation", "path"],
56
- issue: ["issues", "problem", "bug", "friction"],
57
- fix: ["fixes", "remediation", "repair", "resolve"],
58
- compare: ["comparison", "diff", "versus", "cohort"],
59
- health: ["score", "metrics", "ux"],
60
- dead: ["unresponsive", "broken", "stuck"],
61
- rage: ["angry", "frustrated", "frustration"],
62
- };
63
- // Expand query words with synonyms
64
- const expandedWords = new Set(queryWords);
65
- for (const word of queryWords) {
66
- if (synonyms[word]) {
67
- synonyms[word].forEach((syn) => expandedWords.add(syn));
68
- }
69
- // Also check if query word is a synonym value
70
- for (const [key, values] of Object.entries(synonyms)) {
71
- if (values.includes(word)) {
72
- expandedWords.add(key);
73
- }
74
- }
75
- }
76
- return catalog
77
- .map((tool) => {
78
- const toolName = tool.name.toLowerCase().replace(/_/g, " ");
79
- const toolNameParts = tool.name.toLowerCase().split("_");
80
- const text = `${toolName} ${tool.description} ${tool.category}`.toLowerCase();
81
- let score = 0;
82
- // Phrase match in description (highest value)
83
- for (const phrase of queryPhrases) {
84
- if (phrase.length > 3 && text.includes(phrase))
85
- score += 5;
86
- }
87
- // Word matches
88
- for (const word of expandedWords) {
89
- // Exact word in tool name parts (e.g., "page" matches "get_page_metrics")
90
- if (toolNameParts.includes(word))
91
- score += 4;
92
- // Word appears in tool name
93
- if (toolName.includes(word))
94
- score += 3;
95
- // Category match
96
- if (tool.category.toLowerCase() === word)
97
- score += 2;
98
- // Word in description
99
- if (text.includes(word))
100
- score += 1;
101
- }
102
- return { tool, score };
103
- })
104
- .filter((s) => s.score > 0)
105
- .sort((a, b) => b.score - a.score)
106
- .slice(0, limit)
107
- .map((s) => s.tool);
108
- }
109
- async function searchBySemantic(query, limit, queryEmbedding) {
110
- const catalog = loadCatalog();
111
- return catalog
112
- .filter((t) => t.embedding && t.embedding.length > 0)
113
- .map((tool) => ({
114
- tool,
115
- score: cosineSimilarity(queryEmbedding, tool.embedding),
116
- }))
117
- .sort((a, b) => b.score - a.score)
118
- .slice(0, limit)
119
- .map((s) => s.tool);
120
- }
121
- export async function searchTools(query, limit = 5, queryEmbedding) {
122
- if (queryEmbedding && queryEmbedding.length > 0) {
123
- return searchBySemantic(query, limit, queryEmbedding);
124
- }
125
- return searchByKeyword(query, limit);
126
- }
127
- export function getToolByName(name) {
128
- return loadCatalog().find((t) => t.name === name);
129
- }
130
- export function getAllTools() {
131
- return loadCatalog();
132
- }
133
- const DEFAULT_TOOL_LIMIT = 5;
134
- const searchToolsSchema = z.object({
135
- query: z
136
- .string()
137
- .describe("Natural language description of what data or analysis capability you need. " +
138
- "Describe what you want to learn or investigate."),
139
- limit: z
140
- .number()
141
- .optional()
142
- .describe("Maximum number of tools to return (default 5)"),
143
- });
144
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
145
- export function registerSearchTools(server) {
146
- server.registerTool("search_tools", {
147
- description: "Discover analysis tools by describing what data or capability you need. " +
148
- "You have access to 40+ specialized tools covering sessions, pages, behaviors, journeys, " +
149
- "forms, errors, performance, cohorts, issues, and remediation. Keyword search matches your intent to " +
150
- "relevant tools. Returns tool names, descriptions, categories, and parameters. " +
151
- "Use call_tool to execute discovered tools.",
152
- inputSchema: searchToolsSchema,
153
- }, async ({ query, limit }) => {
154
- const searchLimit = limit ?? DEFAULT_TOOL_LIMIT;
155
- const matches = await searchTools(query, searchLimit);
156
- if (matches.length === 0) {
157
- return {
158
- content: [
159
- {
160
- type: "text",
161
- text: JSON.stringify({
162
- tools: [],
163
- message: "No matching tools found. Try rephrasing your query or use broader terms like 'page', 'session', 'issue', 'flow', or 'form'.",
164
- }),
165
- },
166
- ],
167
- };
168
- }
169
- const tools = matches.map((tool) => ({
170
- name: tool.name,
171
- description: tool.description.length > 250
172
- ? tool.description.slice(0, 250) + "..."
173
- : tool.description,
174
- category: tool.category,
175
- parameters: Object.entries(tool.parameters).map(([name, prop]) => ({
176
- name,
177
- type: prop.type,
178
- required: prop.required ?? false,
179
- description: prop.description,
180
- })),
181
- }));
182
- return {
183
- content: [
184
- {
185
- type: "text",
186
- text: JSON.stringify({
187
- tools,
188
- usage: "Use call_tool with the tool name and arguments to execute. Example: call_tool({ tool_name: 'get_page_metrics', arguments: { page_path: '/checkout' } })",
189
- }),
190
- },
191
- ],
192
- };
193
- });
194
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * compare_cohorts tool
3
- *
4
- * Compare two user cohorts side by side.
5
- */
6
- export declare function registerCompareCohorts(server: any): void;
@@ -1,84 +0,0 @@
1
- /**
2
- * compare_cohorts tool
3
- *
4
- * Compare two user cohorts side by side.
5
- */
6
- import { z } from "zod";
7
- import { apiPost, isApiConfigured } from "../api/client.js";
8
- const cohortFilterSchema = z.object({
9
- device: z
10
- .enum(["desktop", "tablet", "mobile"])
11
- .optional()
12
- .describe("Filter by device type"),
13
- outcome: z
14
- .enum(["COMPLETED", "STRUGGLED", "BLOCKED", "DISENGAGED"])
15
- .optional()
16
- .describe("Filter by session outcome"),
17
- pattern: z.string().optional().describe("Filter by behavioral pattern"),
18
- page_path: z.string().optional().describe("Filter by page path"),
19
- has_friction: z
20
- .boolean()
21
- .optional()
22
- .describe("Filter for sessions with friction"),
23
- has_rage_clicks: z
24
- .boolean()
25
- .optional()
26
- .describe("Filter for sessions with rage clicks"),
27
- });
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
- export function registerCompareCohorts(server) {
30
- server.registerTool("compare_cohorts", {
31
- description: "Compare two user cohorts side by side. Each cohort is defined by filter criteria: " +
32
- "device (desktop/tablet/mobile), outcome (COMPLETED/STRUGGLED/BLOCKED/DISENGAGED), " +
33
- "pattern, has_friction, has_rage_clicks, or page_path. " +
34
- "Returns behavioral metrics for each cohort and statistically significant differences. " +
35
- 'Use this to answer "how do mobile users differ from desktop?", "what distinguishes ' +
36
- 'users who complete vs abandon?", or "do form users struggle more than non-form users?"',
37
- inputSchema: z.object({
38
- cohort_a: cohortFilterSchema.describe('Filters for cohort A, e.g. {"device": "mobile"} or {"outcome": "COMPLETED"}'),
39
- cohort_b: cohortFilterSchema.describe('Filters for cohort B, e.g. {"device": "desktop"} or {"outcome": "BLOCKED"}'),
40
- cohort_a_label: z
41
- .string()
42
- .optional()
43
- .describe("Human label for cohort A"),
44
- cohort_b_label: z
45
- .string()
46
- .optional()
47
- .describe("Human label for cohort B"),
48
- page_path: z
49
- .string()
50
- .optional()
51
- .describe("Scope comparison to a specific page"),
52
- date_from: z.string().optional().describe("Start date (ISO format)"),
53
- date_to: z.string().optional().describe("End date (ISO format)"),
54
- }),
55
- }, async ({ cohort_a, cohort_b, cohort_a_label, cohort_b_label, page_path, date_from, date_to, }) => {
56
- if (!isApiConfigured()) {
57
- return {
58
- content: [
59
- {
60
- type: "text",
61
- text: JSON.stringify({ error: "API not configured" }),
62
- },
63
- ],
64
- isError: true,
65
- };
66
- }
67
- const { data, error } = await apiPost("/cohorts/compare", {
68
- cohort_a,
69
- cohort_b,
70
- cohort_a_label,
71
- cohort_b_label,
72
- page_path,
73
- date_from,
74
- date_to,
75
- });
76
- if (error) {
77
- return {
78
- content: [{ type: "text", text: JSON.stringify({ error }) }],
79
- isError: true,
80
- };
81
- }
82
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
83
- });
84
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * compare_periods tool
3
- *
4
- * Compare metrics between two time periods for a page.
5
- */
6
- export declare function registerComparePeriods(server: any): void;
@@ -1,54 +0,0 @@
1
- /**
2
- * compare_periods tool
3
- *
4
- * Compare metrics between two time periods for a page.
5
- */
6
- import { z } from "zod";
7
- import { apiPost, isApiConfigured } from "../api/client.js";
8
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
- export function registerComparePeriods(server) {
10
- server.registerTool("compare_periods", {
11
- description: "Compare behavioral metrics between two time periods for a specific page. " +
12
- "Returns metrics for each period and the deltas between them. " +
13
- "Use this to measure the impact of changes or compare week-over-week performance.",
14
- inputSchema: z.object({
15
- page_path: z.string().describe("Page path to compare"),
16
- period_a: z
17
- .object({
18
- from: z.string().describe("Start date for period A (ISO format)"),
19
- to: z.string().describe("End date for period A (ISO format)"),
20
- })
21
- .describe("First time period"),
22
- period_b: z
23
- .object({
24
- from: z.string().describe("Start date for period B (ISO format)"),
25
- to: z.string().describe("End date for period B (ISO format)"),
26
- })
27
- .describe("Second time period"),
28
- }),
29
- }, async ({ page_path, period_a, period_b, }) => {
30
- if (!isApiConfigured()) {
31
- return {
32
- content: [
33
- {
34
- type: "text",
35
- text: JSON.stringify({ error: "API not configured" }),
36
- },
37
- ],
38
- isError: true,
39
- };
40
- }
41
- const { data, error } = await apiPost("/pages/compare-periods", {
42
- page_path,
43
- period_a,
44
- period_b,
45
- });
46
- if (error) {
47
- return {
48
- content: [{ type: "text", text: JSON.stringify({ error }) }],
49
- isError: true,
50
- };
51
- }
52
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
53
- });
54
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * detect_drift tool
3
- *
4
- * Detect behavioral drift over time.
5
- */
6
- export declare function registerDetectDrift(server: any): void;