@smartbear/mcp 0.14.1 → 0.16.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.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/dist/bugsnag/client.js +47 -1340
  3. package/dist/bugsnag/input-schemas.js +18 -18
  4. package/dist/bugsnag/tool/error/get-error.js +98 -0
  5. package/dist/bugsnag/tool/error/list-project-errors.js +102 -0
  6. package/dist/bugsnag/tool/error/update-error.js +256 -0
  7. package/dist/bugsnag/tool/event/get-event-details-from-dashboard-url.js +55 -0
  8. package/dist/bugsnag/tool/event/get-event.js +38 -0
  9. package/dist/bugsnag/tool/performance/get-network-endpoint-groupings.js +46 -0
  10. package/dist/bugsnag/tool/performance/get-span-group.js +73 -0
  11. package/dist/bugsnag/tool/performance/get-trace.js +83 -0
  12. package/dist/bugsnag/tool/performance/list-span-groups.js +111 -0
  13. package/dist/bugsnag/tool/performance/list-spans.js +97 -0
  14. package/dist/bugsnag/tool/performance/list-trace-fields.js +41 -0
  15. package/dist/bugsnag/tool/performance/set-network-endpoint-groupings.js +90 -0
  16. package/dist/bugsnag/tool/project/get-current-project.js +31 -0
  17. package/dist/bugsnag/tool/project/list-project-event-filters.js +42 -0
  18. package/dist/bugsnag/tool/project/list-projects.js +43 -0
  19. package/dist/bugsnag/tool/release/get-build.js +50 -0
  20. package/dist/bugsnag/tool/release/get-release.js +68 -0
  21. package/dist/bugsnag/tool/release/list-releases.js +88 -0
  22. package/dist/common/prompts.js +9 -0
  23. package/dist/common/server.js +16 -0
  24. package/dist/common/transport-http.js +2 -0
  25. package/dist/package.json.js +1 -1
  26. package/dist/qmetry/client/api/client-api.js +2 -1
  27. package/dist/qmetry/client/automation.js +2 -1
  28. package/dist/qmetry/client/tools/testcase-tools.js +269 -1
  29. package/dist/qmetry/client/tools/testsuite-tools.js +1 -1
  30. package/dist/reflect/client.js +82 -255
  31. package/dist/reflect/config/constants.js +8 -0
  32. package/dist/reflect/prompt/sap-test.js +29 -0
  33. package/dist/reflect/tool/recording/add-prompt-step.js +60 -0
  34. package/dist/reflect/tool/recording/add-segment.js +56 -0
  35. package/dist/reflect/tool/recording/connect-to-session.js +89 -0
  36. package/dist/reflect/tool/recording/delete-previous-step.js +47 -0
  37. package/dist/reflect/tool/recording/get-screenshot.js +55 -0
  38. package/dist/reflect/tool/suites/cancel-suite-execution.js +50 -0
  39. package/dist/reflect/tool/suites/execute-suite.js +40 -0
  40. package/dist/reflect/tool/suites/get-suite-execution-status.js +50 -0
  41. package/dist/reflect/tool/suites/list-suite-executions.js +40 -0
  42. package/dist/reflect/tool/suites/list-suites.js +27 -0
  43. package/dist/reflect/tool/tests/get-test-status.js +42 -0
  44. package/dist/reflect/tool/tests/list-segments.js +68 -0
  45. package/dist/reflect/tool/tests/list-tests.js +27 -0
  46. package/dist/reflect/tool/tests/run-test.js +40 -0
  47. package/dist/reflect/websocket-manager.js +92 -0
  48. package/dist/zephyr/client.js +35 -1
  49. package/dist/zephyr/common/rest-api-schemas.js +463 -477
  50. package/dist/zephyr/tool/folder/create-folder.js +55 -0
  51. package/dist/zephyr/tool/issue-link/get-test-cases.js +33 -0
  52. package/dist/zephyr/tool/issue-link/get-test-cycles.js +32 -0
  53. package/dist/zephyr/tool/issue-link/get-test-executions.js +32 -0
  54. package/dist/zephyr/tool/test-case/create-issue-link.js +38 -0
  55. package/dist/zephyr/tool/test-case/create-test-script.js +57 -0
  56. package/dist/zephyr/tool/test-case/create-test-steps.js +91 -0
  57. package/dist/zephyr/tool/test-case/create-web-link.js +5 -2
  58. package/dist/zephyr/tool/test-case/get-links.js +32 -0
  59. package/dist/zephyr/tool/test-case/get-test-script.js +46 -0
  60. package/dist/zephyr/tool/test-case/get-test-steps.js +56 -0
  61. package/dist/zephyr/tool/test-cycle/create-issue-link.js +45 -0
  62. package/dist/zephyr/tool/test-cycle/create-web-link.js +56 -0
  63. package/dist/zephyr/tool/test-cycle/get-links.js +39 -0
  64. package/dist/zephyr/tool/test-execution/create-issue-link.js +45 -0
  65. package/dist/zephyr/tool/test-execution/get-test-execution-links.js +39 -0
  66. package/dist/zephyr/tool/test-execution/get-test-steps.js +75 -0
  67. package/dist/zephyr/tool/test-execution/update-test-execution.js +73 -0
  68. package/package.json +11 -9
@@ -0,0 +1,68 @@
1
+ import { z } from "zod";
2
+ import { Tool, ToolError } from "../../../common/tools.js";
3
+ import { toolInputParameters } from "../../input-schemas.js";
4
+ const inputSchema = z.object({
5
+ projectId: toolInputParameters.projectId,
6
+ releaseId: toolInputParameters.releaseId
7
+ });
8
+ class GetRelease extends Tool {
9
+ specification = {
10
+ title: "Get Release",
11
+ summary: "Get more details for a specific release by its ID, including source control information and associated builds",
12
+ purpose: "Retrieve detailed information about a release for analysis and debugging",
13
+ useCases: [
14
+ "View release metadata such as version, source control info, and error counts",
15
+ "Analyze the stability data and targets for a release",
16
+ "See the builds that make up the release"
17
+ ],
18
+ inputSchema,
19
+ examples: [
20
+ {
21
+ description: "Get details for a specific release",
22
+ parameters: {
23
+ releaseId: "5f8d0d55c9e77c0017a1b2c3"
24
+ },
25
+ expectedOutput: "JSON object with release details including version, source control info, error counts and stability data."
26
+ }
27
+ ],
28
+ hints: ["Release IDs can be found using the List releases tool"],
29
+ readOnly: true,
30
+ idempotent: true,
31
+ outputDescription: "JSON object containing release details along with stability metrics such as user and session stability, and whether it meets project targets"
32
+ };
33
+ handle = async (args, _extra) => {
34
+ const params = inputSchema.parse(args);
35
+ const project = await this.client.getInputProject(params.projectId);
36
+ const releaseResponse = await this.client.projectApi.getReleaseGroup(
37
+ params.releaseId
38
+ );
39
+ if (!releaseResponse.body)
40
+ throw new ToolError(`No release for ${params.releaseId} found.`);
41
+ const release = this.client.addStabilityData(releaseResponse.body, project);
42
+ let builds = [];
43
+ if (releaseResponse.body) {
44
+ const buildsResponse = await this.client.projectApi.listBuildsInRelease(
45
+ params.releaseId
46
+ );
47
+ if (buildsResponse.body) {
48
+ builds = buildsResponse.body.map(
49
+ (b) => this.client.addStabilityData(b, project)
50
+ );
51
+ }
52
+ }
53
+ return {
54
+ content: [
55
+ {
56
+ type: "text",
57
+ text: JSON.stringify({
58
+ release,
59
+ builds
60
+ })
61
+ }
62
+ ]
63
+ };
64
+ };
65
+ }
66
+ export {
67
+ GetRelease
68
+ };
@@ -0,0 +1,88 @@
1
+ import { z } from "zod";
2
+ import { Tool } from "../../../common/tools.js";
3
+ import { toolInputParameters } from "../../input-schemas.js";
4
+ const inputSchema = z.object({
5
+ projectId: toolInputParameters.projectId,
6
+ releaseStage: toolInputParameters.releaseStage,
7
+ visibleOnly: z.boolean().describe(
8
+ "Whether to only include releases that are marked as visible in the dashboard"
9
+ ).default(false),
10
+ perPage: toolInputParameters.perPage,
11
+ nextUrl: toolInputParameters.nextUrl
12
+ });
13
+ class ListReleases extends Tool {
14
+ specification = {
15
+ title: "List Releases",
16
+ summary: "List releases for a project",
17
+ purpose: "Retrieve a list of release summaries to analyze deployment history and associated errors",
18
+ useCases: [
19
+ "View recent releases to correlate with error spikes",
20
+ "Filter releases by stage (e.g. production, staging) for targeted analysis"
21
+ ],
22
+ inputSchema,
23
+ examples: [
24
+ {
25
+ description: "List production releases for a project",
26
+ parameters: {},
27
+ expectedOutput: "JSON array of release objects in the production stage"
28
+ },
29
+ {
30
+ description: "List staging releases for a project",
31
+ parameters: {
32
+ releaseStage: "staging"
33
+ },
34
+ expectedOutput: "JSON array of release objects in the staging stage"
35
+ },
36
+ {
37
+ description: "Get the next page of results",
38
+ parameters: {
39
+ nextUrl: "/projects/515fb9337c1074f6fd000003/releases?offset=30&per_page=30"
40
+ },
41
+ expectedOutput: "JSON array of release objects with metadata from the next page"
42
+ }
43
+ ],
44
+ hints: [
45
+ "Use the Get Release tool to get more details on a specific release, including the builds it contains",
46
+ "The release stage defaults to 'production' if not specified",
47
+ "Use visibleOnly to filter out releases that have been marked as hidden in the dashboard"
48
+ ],
49
+ readOnly: true,
50
+ idempotent: true,
51
+ outputDescription: "JSON array of release summary objects with metadata, with a URL to the next page if more results are available"
52
+ };
53
+ handle = async (args, _extra) => {
54
+ const params = inputSchema.parse(args);
55
+ const project = await this.client.getInputProject(params.projectId);
56
+ const response = await this.client.projectApi.listProjectReleaseGroups(
57
+ project.id,
58
+ params.releaseStage,
59
+ false,
60
+ // Not top-only
61
+ params.visibleOnly,
62
+ params.perPage,
63
+ params.nextUrl
64
+ );
65
+ let releases = [];
66
+ if (response.body) {
67
+ releases = response.body.map(
68
+ (r) => this.client.addStabilityData(r, project)
69
+ );
70
+ }
71
+ return {
72
+ content: [
73
+ {
74
+ type: "text",
75
+ text: JSON.stringify({
76
+ data: releases,
77
+ next_url: response.nextUrl ?? void 0,
78
+ data_count: releases.length,
79
+ total_count: response.totalCount ?? void 0
80
+ })
81
+ }
82
+ ]
83
+ };
84
+ };
85
+ }
86
+ export {
87
+ ListReleases
88
+ };
@@ -0,0 +1,9 @@
1
+ class Prompt {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ }
7
+ export {
8
+ Prompt
9
+ };
@@ -10,6 +10,7 @@ class SmartBearMcpServer extends McpServer {
10
10
  cache;
11
11
  samplingSupported = false;
12
12
  elicitationSupported = false;
13
+ clients = [];
13
14
  constructor() {
14
15
  super(
15
16
  {
@@ -17,6 +18,15 @@ class SmartBearMcpServer extends McpServer {
17
18
  version: MCP_SERVER_VERSION
18
19
  },
19
20
  {
21
+ instructions: `When creating or editing a Reflect test using a connected recording session, follow these guidelines:
22
+
23
+ 1. After connecting to a session, get the list of segments for the session's platform type so you know what actions could be added via segments vs needing to create new steps. Do not list tests, only list segments.
24
+ 2. Before performing an action, take a screenshot to understand the current state of the application.
25
+ 3. Each add_prompt_step request should perform a single action or assertion. Do not combine multiple actions or assertions into a single step.
26
+ 4. Only perform one action at a time unless you're sure the action won't move the application to a different screen. For example, you can send multiple add_prompt_step requests to fill out individual form fields if those fields are visible on the current screen.
27
+ 5. Check the list of existing Segments to see if a Segment exists that achieves a similar goal to what you're trying to do next. If so, add the segment instead of creating new steps.
28
+ 6. If a step fails, use delete_previous_step to remove it and try a different approach.
29
+ 7. After completing a task, if the task required multiple prompt steps, add a final prompt step that validates the current state of the page based on what you see on the screen. In your validation, do not reference information that can change from run to run.`,
20
30
  capabilities: {
21
31
  resources: { listChanged: true },
22
32
  // Server supports dynamic resource lists
@@ -46,7 +56,13 @@ class SmartBearMcpServer extends McpServer {
46
56
  isElicitationSupported() {
47
57
  return this.elicitationSupported;
48
58
  }
59
+ async cleanupSession(mcpSessionId) {
60
+ for (const client of this.clients) {
61
+ await client.cleanupSession?.(mcpSessionId);
62
+ }
63
+ }
49
64
  async addClient(client) {
65
+ this.clients.push(client);
50
66
  await client.registerTools(
51
67
  (params, cb) => {
52
68
  const toolName = `${client.toolPrefix}_${params.title.replace(/\s+/g, "_").toLowerCase()}`;
@@ -153,6 +153,7 @@ async function createNewTransport(req, res, transports) {
153
153
  if (transport.sessionId) {
154
154
  console.log(`[MCP] Session closed: ${transport.sessionId}`);
155
155
  transports.delete(transport.sessionId);
156
+ server.cleanupSession(transport.sessionId);
156
157
  }
157
158
  };
158
159
  await server.connect(transport);
@@ -205,6 +206,7 @@ async function handleLegacySseRequest(req, res, transports) {
205
206
  transports.set(transport.sessionId, { server, transport });
206
207
  res.on("close", () => {
207
208
  transports.delete(transport.sessionId);
209
+ server.cleanupSession(transport.sessionId);
208
210
  });
209
211
  await server.connect(transport);
210
212
  }
@@ -1,4 +1,4 @@
1
- const version = "0.14.1";
1
+ const version = "0.16.0";
2
2
  const config = { "mcpServerName": "SmartBear MCP Server" };
3
3
  const packageJson = {
4
4
  version,
@@ -13,7 +13,8 @@ async function qmetryRequest({
13
13
  const headers = {
14
14
  apikey: token,
15
15
  project: project || QMETRY_DEFAULTS.PROJECT_KEY,
16
- "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`
16
+ "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
17
+ "qmetry-source": "smartbear-mcp"
17
18
  };
18
19
  if (body) {
19
20
  headers["Content-Type"] = "application/json";
@@ -91,7 +91,8 @@ async function importAutomationResults(token, baseUrl, project, payload) {
91
91
  const headers = {
92
92
  apikey: token,
93
93
  project: finalPayload.projectID || project || QMETRY_DEFAULTS.PROJECT_KEY,
94
- "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`
94
+ "User-Agent": `${MCP_SERVER_NAME}/${MCP_SERVER_VERSION}`,
95
+ "qmetry-source": "smartbear-mcp"
95
96
  // Note: Content-Type will be set automatically by fetch for FormData
96
97
  };
97
98
  let res;
@@ -254,7 +254,7 @@ const TESTCASE_TOOLS = [
254
254
  versionComment: "version 2 with preserved steps",
255
255
  notruncurrent: true,
256
256
  notrunall: true,
257
- isStepUpdated: false
257
+ isStepUpdated: true
258
258
  },
259
259
  expectedOutput: "New version 2 created with all steps from version 1 preserved. Steps carry forward with their tcStepID values. Version comment added for tracking."
260
260
  },
@@ -267,6 +267,70 @@ const TESTCASE_TOOLS = [
267
267
  name: "New Name"
268
268
  },
269
269
  expectedOutput: "Metadata updated only. Steps unchanged. tcID/tcVersionID auto-resolved. Existing version modified."
270
+ },
271
+ {
272
+ description: "Create NEW VERSION from existing version 2 with updated steps (working payload for linked test cases)",
273
+ parameters: {
274
+ tcID: 4594145,
275
+ tcVersionID: 5536706,
276
+ tcVersion: 2,
277
+ name: "Mock Test Case - E-commerce Checkout Flow - v3",
278
+ steps: [
279
+ {
280
+ orderId: 1,
281
+ description: "Open browser and navigate to e-commerce website",
282
+ expectedOutcome: "Homepage loads successfully with product catalog",
283
+ inputData: "URL: https://example-shop.com",
284
+ tcStepID: 38129471
285
+ },
286
+ {
287
+ orderId: 2,
288
+ description: "Search for product",
289
+ expectedOutcome: "Search results display relevant products",
290
+ inputData: "Search term: 'wireless headphones'",
291
+ tcStepID: 38129475
292
+ },
293
+ {
294
+ orderId: 3,
295
+ description: "Select product and add to cart",
296
+ expectedOutcome: "Product added to cart, cart counter increments",
297
+ inputData: "Click 'Add to Cart' button",
298
+ tcStepID: 38129472
299
+ },
300
+ {
301
+ orderId: 4,
302
+ description: "Proceed to checkout",
303
+ expectedOutcome: "Checkout page displays with cart summary",
304
+ inputData: "Click cart icon and 'Proceed to Checkout'",
305
+ tcStepID: 38129473
306
+ },
307
+ {
308
+ orderId: 5,
309
+ description: "Complete payment",
310
+ expectedOutcome: "Order confirmation page displayed",
311
+ inputData: "Fill payment details and submit",
312
+ tcStepID: 38129474
313
+ },
314
+ {
315
+ orderId: 6,
316
+ description: "Verify order confirmation email received",
317
+ expectedOutcome: "Email with order details received in inbox",
318
+ inputData: "Check email account for confirmation"
319
+ },
320
+ {
321
+ orderId: 7,
322
+ description: "Check order status in account dashboard",
323
+ expectedOutcome: "Order status shows as 'Processing' with tracking information",
324
+ inputData: "Navigate to My Orders section"
325
+ }
326
+ ],
327
+ withVersion: true,
328
+ versionComment: "Created version 3: Added 2 new verification steps (email and order status check)",
329
+ notrunall: false,
330
+ notruncurrent: false,
331
+ scope: "project"
332
+ },
333
+ expectedOutput: "New version 3 created successfully from version 2. Test case now has 7 steps (5 preserved + 2 new). Key: tcVersion=2 was used because version 2 already existed in system. notrunall and notruncurrent both false (not true). Result shows tcVersion: 3 in response with new tcVersionID."
270
334
  }
271
335
  ],
272
336
  hints: [
@@ -444,6 +508,210 @@ const TESTCASE_TOOLS = [
444
508
  "- Pitfall 5: Not including tcStepID for steps when creating version → Steps may duplicate instead of preserving",
445
509
  "- Pitfall 6: Confusing tcVersionID (version identifier) with tcVersion (version number) → Wrong API payload",
446
510
  "",
511
+ "CRITICAL ERROR HANDLING: TC.VERSION_NOT_SYNCED FOR LINKED TEST CASES",
512
+ "",
513
+ "PROBLEM: Test cases linked to test suites or with existing executions cannot be updated directly",
514
+ "TRIGGERS:",
515
+ " ✓ Test case is linked to one or more test suites",
516
+ " ✓ Test case has execution history (test runs exist)",
517
+ " ✓ Test case is part of a release/cycle with test runs",
518
+ " ✓ Any step modification when test case has associations",
519
+ "",
520
+ "ERROR CODE: TC.VERSION_NOT_SYNCED",
521
+ "ERROR MESSAGE: 'This Test Case has been associated. Create a new version to save modifications.'",
522
+ "",
523
+ "AUTOMATIC RETRY STRATEGY (IMPLEMENT THIS PATTERN):",
524
+ "When you receive TC.VERSION_NOT_SYNCED error, AUTOMATICALLY retry with version creation:",
525
+ "DO NOT ask user for confirmation - this is expected behavior for associated test cases",
526
+ "",
527
+ "1. FIRST ATTEMPT (Normal Update):",
528
+ " - Try updating with isStepUpdated=true (for step changes) or without withVersion flag",
529
+ " - If error code is TC.VERSION_NOT_SYNCED, proceed to step 2",
530
+ " - If error is different, report the error to user",
531
+ "",
532
+ "2. AUTOMATIC RETRY (Version Creation):",
533
+ " - Use the SAME tcID, tcVersionID, and steps array from first attempt",
534
+ " - Add these flags to payload:",
535
+ " * withVersion: true (CRITICAL - enables version creation)",
536
+ " * tcVersion: <current version number> (get from test case details or executions)",
537
+ " * notrunall: false (use false, not true)",
538
+ " * notruncurrent: false (use false, not true)",
539
+ " * scope: 'project' (always required)",
540
+ " * versionComment: 'Auto-created version due to test suite association' (or custom message)",
541
+ " - Set isStepUpdated: true whenever you modify steps (including when withVersion=true)",
542
+ " - IMPORTANT: Include ALL existing steps with tcStepID + new steps without tcStepID",
543
+ "",
544
+ "3. VERIFICATION:",
545
+ " - Check response for new tcVersionID (will be different from source)",
546
+ " - Verify tcVersion incremented (e.g., 1→2, 2→3)",
547
+ " - Confirm success message: 'Test Case <entityKey> updated successfully'",
548
+ "",
549
+ "UI BEHAVIOR COMPARISON:",
550
+ "QMetry UI shows a popup: 'Save as new version?' with optional comment field",
551
+ "API equivalent: Automatic retry with withVersion=true after detecting TC.VERSION_NOT_SYNCED",
552
+ "",
553
+ "REAL-WORLD EXAMPLE FROM UI PAYLOADS:",
554
+ "",
555
+ "First Attempt (FAILS with TC.VERSION_NOT_SYNCED):",
556
+ "```pseudo",
557
+ "{",
558
+ ' "tcID": 4594140,',
559
+ ' "tcVersionID": 5536696,',
560
+ ' "withVersion": false,',
561
+ ' "notrunall": false,',
562
+ ' "steps": [',
563
+ " // ... 5 existing steps with tcStepID ...",
564
+ " // ... 1 new step without tcStepID (orderId: 6) ...",
565
+ " ],",
566
+ ' "removeSteps": [],',
567
+ ' "isStepUpdated": true',
568
+ "}",
569
+ "```",
570
+ "Response: 400 - TC.VERSION_NOT_SYNCED error",
571
+ "",
572
+ "Second Attempt (SUCCEEDS - Creates Version 2):",
573
+ "```pseudo",
574
+ "{",
575
+ ' "withVersion": true, // NEW: Version creation flag',
576
+ ' "notrunall": false,',
577
+ ' "notruncurrent": false,',
578
+ ' "steps": [',
579
+ " // SAME steps array as first attempt",
580
+ " // ... 5 existing steps with tcStepID ...",
581
+ " // ... 1 new step without tcStepID ...",
582
+ " ],",
583
+ ' "removeSteps": [],',
584
+ ' "scope": "project",',
585
+ ' "tcID": 4594140, // SAME tcID',
586
+ ' "tcVersion": 1, // NEW: Current version number',
587
+ ' "tcVersionID": 5536696, // SAME tcVersionID (source version)',
588
+ ' "versionComment": "test", // NEW: Version comment (optional)',
589
+ " // NOTE: isStepUpdated field is NOT included when withVersion=true",
590
+ "}",
591
+ "```",
592
+ "Response: 200 - Success, new tcVersionID created (e.g., 5536697), tcVersion=2",
593
+ "",
594
+ "IMPLEMENTATION PSEUDO-CODE:",
595
+ "```typescript",
596
+ "try {",
597
+ " // First attempt: Normal update",
598
+ " const response = await updateTestCase({",
599
+ " tcID, tcVersionID, steps, isStepUpdated: true",
600
+ " });",
601
+ "} catch (error) {",
602
+ " if (error.code === 'TC.VERSION_NOT_SYNCED') {",
603
+ " // Automatic retry with version creation",
604
+ " const testCaseDetails = await fetchTestCaseDetails(tcID);",
605
+ " // CRITICAL: Use the LATEST version number from system",
606
+ " const latestVersion = testCaseDetails.tcVersion; // e.g., 2 if v2 exists",
607
+ " const response = await updateTestCase({",
608
+ " tcID,",
609
+ " tcVersionID, // Same source version",
610
+ " tcVersion: latestVersion, // Use latest version number (not always 1!)",
611
+ " steps, // Same steps array",
612
+ " // DO NOT include isStepUpdated when withVersion=true",
613
+ " withVersion: true, // Enable version creation",
614
+ " notrunall: false, // Use false (verified working value)",
615
+ " notruncurrent: false, // Use false (verified working value)",
616
+ " scope: 'project', // Always required",
617
+ " versionComment: 'Auto-created version due to test suite association'",
618
+ " });",
619
+ " } else {",
620
+ " throw error; // Different error, report to user",
621
+ " }",
622
+ "}",
623
+ "```",
624
+ "",
625
+ "KEY INSIGHTS:",
626
+ "- DO NOT ask user for confirmation - auto-retry is expected behavior",
627
+ "- Use SAME tcVersionID in both attempts (source version for creation)",
628
+ "- Second attempt creates NEW version (tcVersionID changes in response)",
629
+ "- Steps array is IDENTICAL in both attempts",
630
+ "- tcVersion parameter is ONLY in second attempt (withVersion=true)",
631
+ "- This matches QMetry UI behavior where popup auto-triggers version creation",
632
+ "",
633
+ "CRITICAL: INCREMENTAL tcVersion SELECTION RULE",
634
+ "",
635
+ "PROBLEM: When multiple versions exist, which tcVersion should you use?",
636
+ "SOLUTION: Use the VERSION NUMBER of the version you are creating FROM (the latest existing version)",
637
+ "",
638
+ "RULE: When creating a new version, tcVersion must equal the CURRENT LATEST VERSION in the system",
639
+ "",
640
+ "EXAMPLES:",
641
+ "- If only version 1 exists: Use tcVersion: 1 (creates version 2 from v1)",
642
+ "- If version 1 and 2 exist: Use tcVersion: 2 (creates version 3 from v2)",
643
+ "- If version 1, 2, and 3 exist: Use tcVersion: 3 (creates version 4 from v3)",
644
+ "",
645
+ "WORKFLOW TO DETERMINE CORRECT tcVersion:",
646
+ "1. Call FETCH_TEST_CASE_DETAILS or FETCH_TEST_CASE_EXECUTIONS",
647
+ "2. Check the highest tcVersion number in the system",
648
+ "3. Use that number as your tcVersion parameter in the update payload",
649
+ "4. This ensures you're creating from the latest version, not an old one",
650
+ "",
651
+ "REAL-WORLD SCENARIO:",
652
+ "Scenario: Test case VKMCP-TC-43 has version 2 already created in UI",
653
+ "Wrong Approach (will fail): tcVersion: 1, withVersion: true → TC.VERSION_NOT_SYNCED error",
654
+ "Correct Approach (will succeed): tcVersion: 2, withVersion: true → Creates version 3 successfully",
655
+ "",
656
+ "VERIFIED WORKING PAYLOAD (from user's Postman testing):",
657
+ "```json",
658
+ "{",
659
+ ' "notrunall": false,',
660
+ ' "notruncurrent": false,',
661
+ ' "scope": "project",',
662
+ ' "tcID": 4594145,',
663
+ ' "tcVersion": 2, // KEY: Use version 2 because v2 already exists',
664
+ ' "tcVersionID": 5536706, // Source version ID (stays same)',
665
+ ' "versionComment": "Added new steps", // Describes what changed',
666
+ ' "withVersion": true, // Enable version creation',
667
+ ' "steps": [',
668
+ " // 5 existing steps with tcStepID (preserved from source)",
669
+ " // 2 new steps without tcStepID (to be added)",
670
+ " ]",
671
+ "}",
672
+ "```",
673
+ "Result: New version 3 created successfully with 7 total steps",
674
+ "",
675
+ "DEFAULT VALUES FOR TC.VERSION_NOT_SYNCED RETRIES (THIS PATTERN):",
676
+ "- notrunall: false - For this retry pattern, override any usual `true` default",
677
+ "- notruncurrent: false - For this retry pattern, override any usual `true` default",
678
+ '- scope: "project" - Always use this',
679
+ "- withVersion: true - Required when creating a new version (both initial and retries)",
680
+ "",
681
+ "WHEN TO APPLY THIS PATTERN:",
682
+ "✓ Adding steps to test case linked to test suite",
683
+ "✓ Editing steps in test case with existing executions",
684
+ "✓ Removing steps from associated test case",
685
+ "✓ Any modification to steps when TC.VERSION_NOT_SYNCED occurs",
686
+ "✓ When creating new versions from existing versions (always check latest version number)",
687
+ "",
688
+ "WHEN NOT TO APPLY:",
689
+ "✗ Test case is NOT linked to test suite (normal update works)",
690
+ "✗ Only updating metadata (name, priority, etc.) without steps",
691
+ "✗ Different error codes (handle appropriately)",
692
+ "",
693
+ "BENEFITS OF THIS APPROACH:",
694
+ "1. Seamless UX - LLM handles version creation automatically",
695
+ "2. Matches UI behavior - no manual intervention needed",
696
+ "3. Preserves test history - creates proper version trail",
697
+ "4. Maintains test suite linkage - version creation preserves associations",
698
+ "5. Handles incremental versions correctly - uses latest version as source",
699
+ "",
700
+ "🎯 GRACEFUL HANDLING SUMMARY:",
701
+ "",
702
+ "When adding/editing/removing steps from test cases:",
703
+ "1. Always TRY normal update first (without withVersion flag)",
704
+ "2. If TC.VERSION_NOT_SYNCED error received:",
705
+ " - Fetch latest version number from test case details/executions",
706
+ " - Automatically retry with withVersion=true + correct tcVersion",
707
+ " - Use notrunall=false, notruncurrent=false, scope='project'",
708
+ " - Include version comment describing the changes",
709
+ "3. Report success with new version details to user",
710
+ "4. NEVER ask for confirmation - handle it transparently",
711
+ "",
712
+ "This ensures test cases with executions or suite associations are handled gracefully",
713
+ "without user intervention, matching the QMetry UI experience exactly.",
714
+ "",
447
715
  "executionMinutes time is in minutes (legacy field).",
448
716
  "estimatedTime is in seconds (preferred for version creation).",
449
717
  "Description and testingType are optional but recommended for clarity."
@@ -947,7 +947,7 @@ const TESTSUITE_TOOLS = [
947
947
  hints: [
948
948
  "CRITICAL: entityIDs, entityType, qmTsRunId, and runStatusID are REQUIRED parameters",
949
949
  "",
950
- "⚠️ CRITICAL - ALWAYS FETCH STATUS IDs FROM PROJECT INFO:",
950
+ "CRITICAL - ALWAYS FETCH STATUS IDs FROM PROJECT INFO:",
951
951
  "NEVER use hardcoded or memorized status IDs. Status IDs are PROJECT-SPECIFIC and must be fetched dynamically.",
952
952
  "MANDATORY WORKFLOW BEFORE USING runStatusID:",
953
953
  "1. Call mcp_smartbear_qmetry_fetch_qmetry_project_info with the current projectKey",