@usercase/mcp 0.2.1-next.1 → 0.2.1-next.2

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/README.md CHANGED
@@ -83,13 +83,13 @@ Claude reads your code to work out the route each task is meant to take, tells y
83
83
 
84
84
  The dashboard's **New question** picks one simple moment (on arrival, after a pause, when leaving, after a click). For a moment made of several steps — "typed a search, opened no result, then did nothing for 10 seconds" — Claude writes it from your code and checks it against your recent real visits. Both need the API key.
85
85
 
86
- **You wrote the question, and want it to appear at a precise moment.** In New question, choose **Several steps**, describe the moment, and copy the command it gives you:
86
+ **You wrote the question, and want it to appear at a precise moment.** In New question, choose **Several steps** and copy the command it gives you:
87
87
 
88
88
  ```
89
89
  /mcp__usercase__steps <window id>
90
90
  ```
91
91
 
92
- Claude reads what you wrote, writes the steps, and sends them back to that window. You see them there, and save the question as usual.
92
+ Claude reads your question, asks you when it should appear, writes the steps, and sends them back to that window. You see them there, and save the question as usual.
93
93
 
94
94
  **You're not sure what to ask.** Run this and tell Claude who you want to hear from:
95
95
 
@@ -23,7 +23,7 @@ Rules that make a card actually appear and mean something:
23
23
 
24
24
  Call `question_check` with the condition. Read the result:
25
25
  - **Problems**: fix them and check again. The server refuses the condition while there are any.
26
- - **Matched 0** with visits present: the paths or words are wrong, or the situation has not happened recently. Compare with `question_context`.
26
+ - **Does not match recent visits** (matched 0, a path or word not seen): usually a wrong path or word — compare with `question_context` and the code, and fix it. But the screen or button may be new or not live yet. Then tell the user it has not been seen in recent visits, and send it with `acceptWarnings: true` only if they say so.
27
27
  - **Examples**: read what the matched visitors did. If it is not the situation the user meant, the condition is wrong even if it passes.
28
28
  - **Overlaps**: an existing question fires at the same moment; only one card shows per visit. Tell the user.
29
29
  - `idle` and `leave` moments are not counted by the check — it counts visits where the steps happened. Fewer people will actually see the card.
package/agents/steps.md CHANGED
@@ -6,11 +6,11 @@ The user is writing a question in the Usercase dashboard (New question → Sever
6
6
 
7
7
  You may read the code: the routes, the components, the labels on buttons.
8
8
 
9
- ## 1. Read what they wrote
9
+ ## 1. Read their question, then ask about the moment
10
10
 
11
- Call `steps_brief` with the window id. It gives the moment they described, the page they typed under Where (if any) and their question. If the window id is missing or unknown, ask the user to choose Several steps again and copy the new command.
11
+ Call `steps_brief` with the window id. It gives the page they typed under Where (if any) and their question. If the window id is missing or unknown, ask the user to choose Several steps again and copy the new command.
12
12
 
13
- If the description is vague, ask one short question to pin the moment down. Otherwise go on.
13
+ Then ask the user, in one short question, when the card should appear — what the visitor has done just before. Suggest one moment that fits their question so they can just say yes. If their answer is still vague, ask once more. Then go on.
14
14
 
15
15
  ## 2. Read the code and the visits
16
16
 
@@ -27,4 +27,6 @@ Make sure the moment fits their question: the card should appear when the visito
27
27
 
28
28
  Tell the user in plain words when it will appear and how many recent visits matched, and anything you could not express. Then call `steps_send` with the window id, the condition and `triggerEn`. The steps appear in their dashboard window right away; they save the question there. Do not save a question yourself.
29
29
 
30
+ If they want it changed, fix it, check it again and send it to the same window id — the new steps replace the old ones in their window.
31
+
30
32
  Do not change any code.
package/mcp/server.js CHANGED
@@ -330,8 +330,16 @@ const QCondition = z.object({
330
330
  function describeCheck(r) {
331
331
  const L = [`Checked against ${r.visits} visits from the last ${r.days} days: matched ${r.matched}.`];
332
332
  if (!r.visits) L.push("There are no recent visits yet, so the condition could only be checked for shape, not against real behavior.");
333
- if (r.issues.length) L.push("", "Problems — fix these before saving:", ...r.issues.map((s) => `- ${s}`));
333
+ if (r.issues.length) L.push("", "Problems — fix these; it cannot be saved with them:", ...r.issues.map((s) => `- ${s}`));
334
334
  else L.push("No problems found.");
335
+ const warnings = r.warnings || [];
336
+ if (warnings.length)
337
+ L.push(
338
+ "",
339
+ "Does not match recent visits — fine if the screen or button is new or not live yet, otherwise likely a wrong path or word:",
340
+ ...warnings.map((s) => `- ${s}`),
341
+ "To save anyway, tell the user, and only if they say so pass acceptWarnings: true.",
342
+ );
335
343
  if (r.overlaps.length)
336
344
  L.push("", "Fires at the same moment as existing questions (only one card shows per visit, so one of them would rarely appear):", ...r.overlaps.map((o) => `- "${o.question}" (${o.status})`));
337
345
  if (r.examples.length) L.push("", "What some matched visitors did, up to the moment the question would appear:", ...r.examples.map((e) => "```\n" + e + "\n```"));
@@ -390,6 +398,7 @@ server.registerTool(
390
398
  title: z.string().optional().describe("English, a few words, for the Inbox"),
391
399
  why: z.string().optional().describe("English. What the team wants to learn, shown in the Inbox"),
392
400
  triggerEn: z.string().optional().describe("English. One plain sentence: when and in what situation it appears. No paths or class names"),
401
+ acceptWarnings: z.boolean().optional().describe("true only after the user said to save even though it does not match recent visits"),
393
402
  },
394
403
  },
395
404
  wrap(async (args) => {
@@ -398,6 +407,7 @@ server.registerTool(
398
407
  r = await report.saveQuestion(args);
399
408
  } catch (e) {
400
409
  if (e.status === 422) throw new Error("The condition did not pass the check. Run question_check, fix the problems, then save again");
410
+ if (e.status === 409) throw new Error("It does not match recent visits. Tell the user; if they want it anyway (a new screen or button), save again with acceptWarnings: true");
401
411
  throw e;
402
412
  }
403
413
  const L = [`Saved as a draft — matched ${r.matched} of ${r.visits} recent visits.`, `Open it in the Inbox to turn it on: ${report.dashboardUrl(r.inboxPath)}`];
@@ -410,14 +420,13 @@ server.registerTool(
410
420
  server.registerTool(
411
421
  "steps_brief",
412
422
  {
413
- description: "What the user wrote in their New question window: the moment they described, the page under Where, and their question. Call first in the steps procedure.",
423
+ description: "What the user wrote in their New question window: the page under Where and their question. Call first in the steps procedure.",
414
424
  inputSchema: { session: z.string().describe("The window id from the dashboard command") },
415
425
  },
416
426
  wrap(async ({ session }) => {
417
427
  const b = await report.getStepsBrief(session);
418
428
  return text(
419
429
  [
420
- `Moment they described: ${b.moment || "(nothing — ask the user)"}`,
421
430
  `Where: ${b.where || "(empty)"}`,
422
431
  `Their question: ${b.question || "(not written yet)"}`,
423
432
  b.sent ? "Steps were already sent to this window once; sending again replaces them." : "",
@@ -437,14 +446,16 @@ server.registerTool(
437
446
  session: z.string().describe("The window id from the dashboard command"),
438
447
  condition: QCondition,
439
448
  triggerEn: z.string().describe("English. One plain sentence: when and in what situation it appears. No paths or class names"),
449
+ acceptWarnings: z.boolean().optional().describe("true only after the user said to send it even though it does not match recent visits"),
440
450
  },
441
451
  },
442
- wrap(async ({ session, condition, triggerEn }) => {
452
+ wrap(async ({ session, condition, triggerEn, acceptWarnings }) => {
443
453
  let r;
444
454
  try {
445
- r = await report.sendSteps(session, { condition, triggerEn });
455
+ r = await report.sendSteps(session, { condition, triggerEn, acceptWarnings });
446
456
  } catch (e) {
447
457
  if (e.status === 422) throw new Error("The condition did not pass the check. Run question_check, fix the problems, then send again");
458
+ if (e.status === 409) throw new Error("It does not match recent visits. Tell the user; if they want it anyway (a new screen or button), send again with acceptWarnings: true");
448
459
  throw e;
449
460
  }
450
461
  const L = [`Sent — the steps are now in the user's New question window (matched ${r.matched} of ${r.visits} recent visits). They save the question there.`];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usercase/mcp",
3
- "version": "0.2.1-next.1",
3
+ "version": "0.2.1-next.2",
4
4
  "description": "Virtual users that browse your website and tell you what they thought — an MCP server for Claude Code",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://usercase.io",