whyusersleave 1.2.0 → 1.3.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.
Files changed (2) hide show
  1. package/index.js +66 -14
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -13,7 +13,7 @@ if (!API_KEY) {
13
13
 
14
14
  const server = new McpServer({
15
15
  name: "whyusersleave",
16
- version: "1.1.0",
16
+ version: "1.3.1",
17
17
  });
18
18
 
19
19
  // Cache resolved sites
@@ -36,15 +36,18 @@ async function apiCall(path, options = {}) {
36
36
  return res;
37
37
  }
38
38
 
39
- /** Fire-and-forget tool call tracking */
40
- function trackToolCall(toolName) {
39
+ /** Fire-and-forget tool call tracking with optional result logging */
40
+ function trackToolCall(toolName, { input, result } = {}) {
41
+ const payload = { tool_name: toolName };
42
+ if (input) payload.input = input;
43
+ if (result) payload.result = typeof result === "string" ? result : JSON.stringify(result);
41
44
  fetch(`${API_BASE}/api/mcp/activity`, {
42
45
  method: "POST",
43
46
  headers: {
44
47
  Authorization: `Bearer ${API_KEY}`,
45
48
  "Content-Type": "application/json",
46
49
  },
47
- body: JSON.stringify({ tool_name: toolName }),
50
+ body: JSON.stringify(payload),
48
51
  }).catch(() => {});
49
52
  }
50
53
 
@@ -90,7 +93,6 @@ server.tool(
90
93
  {},
91
94
  async () => {
92
95
  const sites = await getSites();
93
- trackToolCall("get_ux_issues");
94
96
 
95
97
  if (sites.length === 0) {
96
98
  return {
@@ -168,8 +170,10 @@ server.tool(
168
170
  }
169
171
  }
170
172
 
173
+ const output = allLines.join("\n");
174
+ trackToolCall("get_ux_issues", { result: output });
171
175
  return {
172
- content: [{ type: "text", text: allLines.join("\n") }],
176
+ content: [{ type: "text", text: output }],
173
177
  };
174
178
  }
175
179
  );
@@ -181,7 +185,6 @@ server.tool(
181
185
  {},
182
186
  async () => {
183
187
  const sites = await getSites();
184
- trackToolCall("generate_report");
185
188
  const allOutput = [];
186
189
 
187
190
  for (const site of sites) {
@@ -199,8 +202,10 @@ server.tool(
199
202
  allOutput.push(text);
200
203
  }
201
204
 
205
+ const output = allOutput.join("\n\n---\n\n");
206
+ trackToolCall("generate_report", { result: output });
202
207
  return {
203
- content: [{ type: "text", text: allOutput.join("\n\n---\n\n") }],
208
+ content: [{ type: "text", text: output }],
204
209
  };
205
210
  }
206
211
  );
@@ -212,7 +217,6 @@ server.tool(
212
217
  {},
213
218
  async () => {
214
219
  const sites = await getSites();
215
- trackToolCall("verify_fixes");
216
220
  const allLines = [];
217
221
 
218
222
  for (const site of sites) {
@@ -272,8 +276,10 @@ server.tool(
272
276
  }
273
277
  }
274
278
 
279
+ const output = allLines.join("\n");
280
+ trackToolCall("verify_fixes", { result: output });
275
281
  return {
276
- content: [{ type: "text", text: allLines.join("\n") }],
282
+ content: [{ type: "text", text: output }],
277
283
  };
278
284
  }
279
285
  );
@@ -285,7 +291,6 @@ server.tool(
285
291
  {},
286
292
  async () => {
287
293
  const sites = await getSites();
288
- trackToolCall("get_site_context");
289
294
  const lines = [];
290
295
 
291
296
  for (const site of sites) {
@@ -311,8 +316,10 @@ server.tool(
311
316
  lines.push("");
312
317
  }
313
318
 
319
+ const output = lines.join("\n");
320
+ trackToolCall("get_site_context", { result: output });
314
321
  return {
315
- content: [{ type: "text", text: lines.join("\n") }],
322
+ content: [{ type: "text", text: output }],
316
323
  };
317
324
  }
318
325
  );
@@ -330,7 +337,6 @@ server.tool(
330
337
  },
331
338
  async ({ question }) => {
332
339
  const sites = await getSites();
333
- trackToolCall("ask_question");
334
340
  const allLines = [];
335
341
 
336
342
  for (const site of sites) {
@@ -350,8 +356,54 @@ server.tool(
350
356
  }
351
357
  }
352
358
 
359
+ const output = allLines.join("\n\n");
360
+ trackToolCall("ask_question", { input: { question }, result: output });
353
361
  return {
354
- content: [{ type: "text", text: allLines.join("\n\n") }],
362
+ content: [{ type: "text", text: output }],
363
+ };
364
+ }
365
+ );
366
+
367
+ // Tool 6: get_recommendations
368
+ server.tool(
369
+ "get_recommendations",
370
+ "Get a prioritized action plan based on real user behavior data. Returns 3-5 recommendations ordered by business impact — what's hurting conversion/retention most and exactly what to fix. Call this before starting any work to know where to focus.",
371
+ {},
372
+ async () => {
373
+ const sites = await getSites();
374
+ const allLines = [];
375
+
376
+ for (const site of sites) {
377
+ if (sites.length > 1) {
378
+ allLines.push(`# ${site.name || site.domain}\n`);
379
+ }
380
+
381
+ const res = await apiCall(
382
+ `/api/recommendations${qs(siteParam(site.id))}`
383
+ );
384
+ const data = await res.json();
385
+
386
+ if (data.data_status === "no_data") {
387
+ allLines.push(
388
+ data.recommendations ||
389
+ "No data yet. Run `generate_report` first."
390
+ );
391
+ continue;
392
+ }
393
+
394
+ if (data.stats) {
395
+ allLines.push(
396
+ `*${data.stats.sessions} sessions, ${data.stats.bounce_rate}% bounce rate, ${data.stats.open_issues} open issues*\n`
397
+ );
398
+ }
399
+
400
+ allLines.push(data.recommendations || "No recommendations generated.");
401
+ }
402
+
403
+ const output = allLines.join("\n\n");
404
+ trackToolCall("get_recommendations", { result: output });
405
+ return {
406
+ content: [{ type: "text", text: output }],
355
407
  };
356
408
  }
357
409
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whyusersleave",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "MCP server for WhyUsersLeave UX analytics — get UX issues, generate reports, and verify fixes directly in Claude Code",
5
5
  "bin": {
6
6
  "whyusersleave": "./index.js"