@browserstack/mcp-server 1.1.8 → 1.2.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 (125) hide show
  1. package/README.md +71 -35
  2. package/dist/config.d.ts +13 -0
  3. package/dist/config.js +10 -6
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.js +20 -30
  6. package/dist/lib/api.d.ts +2 -0
  7. package/dist/lib/api.js +10 -5
  8. package/dist/lib/apiClient.d.ts +31 -0
  9. package/dist/lib/apiClient.js +108 -0
  10. package/dist/lib/constants.d.ts +17 -0
  11. package/dist/lib/device-cache.d.ts +9 -0
  12. package/dist/lib/device-cache.js +3 -3
  13. package/dist/lib/error.d.ts +7 -0
  14. package/dist/lib/fuzzy.d.ts +1 -0
  15. package/dist/lib/get-auth.d.ts +2 -0
  16. package/dist/lib/get-auth.js +8 -0
  17. package/dist/lib/inmemory-store.d.ts +1 -0
  18. package/dist/lib/instrumentation.d.ts +4 -0
  19. package/dist/lib/instrumentation.js +8 -7
  20. package/dist/lib/local.d.ts +3 -0
  21. package/dist/lib/local.js +12 -3
  22. package/dist/lib/types.d.ts +4 -0
  23. package/dist/lib/types.js +1 -0
  24. package/dist/lib/utils.d.ts +4 -0
  25. package/dist/lib/version-resolver.d.ts +6 -0
  26. package/dist/logger.d.ts +3 -0
  27. package/dist/logger.js +20 -4
  28. package/dist/oninitialized.d.ts +2 -0
  29. package/dist/oninitialized.js +2 -7
  30. package/dist/server-factory.d.ts +3 -0
  31. package/dist/server-factory.js +37 -0
  32. package/dist/tools/accessibility.d.ts +3 -0
  33. package/dist/tools/accessibility.js +17 -10
  34. package/dist/tools/accessiblity-utils/accessibility-rag.d.ts +12 -0
  35. package/dist/tools/accessiblity-utils/accessibility-rag.js +22 -12
  36. package/dist/tools/accessiblity-utils/report-fetcher.d.ts +8 -0
  37. package/dist/tools/accessiblity-utils/report-fetcher.js +26 -16
  38. package/dist/tools/accessiblity-utils/report-parser.d.ts +23 -0
  39. package/dist/tools/accessiblity-utils/report-parser.js +3 -3
  40. package/dist/tools/accessiblity-utils/scanner.d.ts +25 -0
  41. package/dist/tools/accessiblity-utils/scanner.js +46 -24
  42. package/dist/tools/appautomate-utils/appautomate.d.ts +42 -0
  43. package/dist/tools/appautomate-utils/appautomate.js +95 -9
  44. package/dist/tools/appautomate-utils/types.d.ts +5 -0
  45. package/dist/tools/appautomate-utils/types.js +6 -0
  46. package/dist/tools/appautomate.d.ts +3 -0
  47. package/dist/tools/appautomate.js +109 -13
  48. package/dist/tools/applive-utils/device-search.d.ts +6 -0
  49. package/dist/tools/applive-utils/start-session.d.ts +15 -0
  50. package/dist/tools/applive-utils/start-session.js +11 -4
  51. package/dist/tools/applive-utils/types.d.ts +7 -0
  52. package/dist/tools/applive-utils/upload-app.d.ts +5 -0
  53. package/dist/tools/applive-utils/upload-app.js +8 -12
  54. package/dist/tools/applive-utils/version-utils.d.ts +4 -0
  55. package/dist/tools/applive.d.ts +13 -0
  56. package/dist/tools/applive.js +6 -6
  57. package/dist/tools/automate-utils/fetch-screenshots.d.ts +6 -0
  58. package/dist/tools/automate-utils/fetch-screenshots.js +16 -12
  59. package/dist/tools/automate.d.ts +9 -0
  60. package/dist/tools/automate.js +6 -6
  61. package/dist/tools/bstack-sdk.d.ts +17 -0
  62. package/dist/tools/bstack-sdk.js +47 -20
  63. package/dist/tools/failurelogs-utils/app-automate.d.ts +7 -0
  64. package/dist/tools/failurelogs-utils/app-automate.js +29 -11
  65. package/dist/tools/failurelogs-utils/automate.d.ts +6 -0
  66. package/dist/tools/failurelogs-utils/automate.js +27 -12
  67. package/dist/tools/failurelogs-utils/utils.d.ts +30 -0
  68. package/dist/tools/getFailureLogs.d.ts +14 -0
  69. package/dist/tools/getFailureLogs.js +11 -11
  70. package/dist/tools/live-utils/desktop-filter.d.ts +2 -0
  71. package/dist/tools/live-utils/mobile-filter.d.ts +2 -0
  72. package/dist/tools/live-utils/start-session.d.ts +6 -0
  73. package/dist/tools/live-utils/start-session.js +18 -5
  74. package/dist/tools/live-utils/types.d.ts +33 -0
  75. package/dist/tools/live.d.ts +3 -0
  76. package/dist/tools/live.js +11 -11
  77. package/dist/tools/observability.d.ts +5 -0
  78. package/dist/tools/observability.js +14 -11
  79. package/dist/tools/sdk-utils/commands.d.ts +3 -0
  80. package/dist/tools/sdk-utils/commands.js +20 -5
  81. package/dist/tools/sdk-utils/constants.d.ts +2 -0
  82. package/dist/tools/sdk-utils/constants.js +284 -160
  83. package/dist/tools/sdk-utils/instructions.d.ts +6 -0
  84. package/dist/tools/sdk-utils/instructions.js +28 -6
  85. package/dist/tools/sdk-utils/percy/constants.d.ts +3 -0
  86. package/dist/tools/sdk-utils/percy/constants.js +36 -25
  87. package/dist/tools/sdk-utils/percy/instructions.d.ts +10 -0
  88. package/dist/tools/sdk-utils/percy/types.d.ts +5 -0
  89. package/dist/tools/sdk-utils/types.d.ts +39 -0
  90. package/dist/tools/sdk-utils/types.js +3 -0
  91. package/dist/tools/selfheal-utils/selfheal.d.ts +11 -0
  92. package/dist/tools/selfheal-utils/selfheal.js +10 -6
  93. package/dist/tools/selfheal.d.ts +7 -0
  94. package/dist/tools/selfheal.js +6 -6
  95. package/dist/tools/testmanagement-utils/TCG-utils/api.d.ts +34 -0
  96. package/dist/tools/testmanagement-utils/TCG-utils/api.js +57 -44
  97. package/dist/tools/testmanagement-utils/TCG-utils/config.d.ts +5 -0
  98. package/dist/tools/testmanagement-utils/TCG-utils/helpers.d.ts +13 -0
  99. package/dist/tools/testmanagement-utils/TCG-utils/helpers.js +2 -1
  100. package/dist/tools/testmanagement-utils/TCG-utils/types.d.ts +26 -0
  101. package/dist/tools/testmanagement-utils/add-test-result.d.ts +42 -0
  102. package/dist/tools/testmanagement-utils/add-test-result.js +23 -10
  103. package/dist/tools/testmanagement-utils/create-lca-steps.d.ts +100 -0
  104. package/dist/tools/testmanagement-utils/create-lca-steps.js +64 -55
  105. package/dist/tools/testmanagement-utils/create-project-folder.d.ts +31 -0
  106. package/dist/tools/testmanagement-utils/create-project-folder.js +31 -21
  107. package/dist/tools/testmanagement-utils/create-testcase.d.ts +122 -0
  108. package/dist/tools/testmanagement-utils/create-testcase.js +13 -10
  109. package/dist/tools/testmanagement-utils/create-testrun.d.ts +82 -0
  110. package/dist/tools/testmanagement-utils/create-testrun.js +11 -8
  111. package/dist/tools/testmanagement-utils/list-testcases.d.ts +30 -0
  112. package/dist/tools/testmanagement-utils/list-testcases.js +9 -7
  113. package/dist/tools/testmanagement-utils/list-testruns.d.ts +22 -0
  114. package/dist/tools/testmanagement-utils/list-testruns.js +9 -7
  115. package/dist/tools/testmanagement-utils/poll-lca-status.d.ts +11 -0
  116. package/dist/tools/testmanagement-utils/poll-lca-status.js +12 -8
  117. package/dist/tools/testmanagement-utils/testcase-from-file.d.ts +4 -0
  118. package/dist/tools/testmanagement-utils/testcase-from-file.js +6 -6
  119. package/dist/tools/testmanagement-utils/update-testrun.d.ts +40 -0
  120. package/dist/tools/testmanagement-utils/update-testrun.js +11 -7
  121. package/dist/tools/testmanagement-utils/upload-file.d.ts +20 -0
  122. package/dist/tools/testmanagement-utils/upload-file.js +8 -6
  123. package/dist/tools/testmanagement.d.ts +60 -0
  124. package/dist/tools/testmanagement.js +51 -53
  125. package/package.json +1 -1
@@ -1,7 +1,6 @@
1
- import axios from "axios";
2
- import config from "../../config.js";
1
+ import { apiClient } from "../../lib/apiClient.js";
2
+ import { getBrowserStackAuth } from "../../lib/get-auth.js";
3
3
  import { z } from "zod";
4
- import { formatAxiosError } from "../../lib/error.js";
5
4
  /**
6
5
  * Schema for adding a test result to a test run.
7
6
  */
@@ -26,7 +25,7 @@ export const AddTestResultSchema = z.object({
26
25
  /**
27
26
  * Adds a test result to a specific test run via BrowserStack Test Management API.
28
27
  */
29
- export async function addTestResult(rawArgs) {
28
+ export async function addTestResult(rawArgs, config) {
30
29
  try {
31
30
  const args = AddTestResultSchema.parse(rawArgs);
32
31
  const url = `https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(args.project_identifier)}/test-runs/${encodeURIComponent(args.test_run_id)}/results`;
@@ -34,12 +33,15 @@ export async function addTestResult(rawArgs) {
34
33
  test_result: args.test_result,
35
34
  test_case_id: args.test_case_id,
36
35
  };
37
- const response = await axios.post(url, body, {
38
- auth: {
39
- username: config.browserstackUsername,
40
- password: config.browserstackAccessKey,
36
+ const authString = getBrowserStackAuth(config);
37
+ const [username, password] = authString.split(":");
38
+ const response = await apiClient.post({
39
+ url,
40
+ headers: {
41
+ "Content-Type": "application/json",
42
+ Authorization: "Basic " + Buffer.from(`${username}:${password}`).toString("base64"),
41
43
  },
42
- headers: { "Content-Type": "application/json" },
44
+ body,
43
45
  });
44
46
  const data = response.data;
45
47
  if (!data.success) {
@@ -56,6 +58,17 @@ export async function addTestResult(rawArgs) {
56
58
  };
57
59
  }
58
60
  catch (err) {
59
- return formatAxiosError(err, "Failed to add test result to test run");
61
+ const msg = err?.response?.data?.message ||
62
+ err?.response?.data?.error ||
63
+ err?.message ||
64
+ String(err);
65
+ return {
66
+ content: [
67
+ {
68
+ type: "text",
69
+ text: `Failed to add test result to test run: ${msg}`,
70
+ },
71
+ ],
72
+ };
60
73
  }
61
74
  }
@@ -0,0 +1,100 @@
1
+ import { z } from "zod";
2
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import { BrowserStackConfig } from "../../lib/types.js";
4
+ /**
5
+ * Schema for creating LCA steps for a test case
6
+ */
7
+ export declare const CreateLCAStepsSchema: z.ZodObject<{
8
+ project_identifier: z.ZodString;
9
+ test_case_identifier: z.ZodString;
10
+ base_url: z.ZodString;
11
+ credentials: z.ZodOptional<z.ZodObject<{
12
+ username: z.ZodString;
13
+ password: z.ZodString;
14
+ }, "strip", z.ZodTypeAny, {
15
+ username: string;
16
+ password: string;
17
+ }, {
18
+ username: string;
19
+ password: string;
20
+ }>>;
21
+ local_enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
22
+ test_name: z.ZodString;
23
+ test_case_details: z.ZodObject<{
24
+ name: z.ZodString;
25
+ description: z.ZodString;
26
+ preconditions: z.ZodString;
27
+ test_case_steps: z.ZodArray<z.ZodObject<{
28
+ step: z.ZodString;
29
+ result: z.ZodString;
30
+ }, "strip", z.ZodTypeAny, {
31
+ step: string;
32
+ result: string;
33
+ }, {
34
+ step: string;
35
+ result: string;
36
+ }>, "many">;
37
+ }, "strip", z.ZodTypeAny, {
38
+ name: string;
39
+ description: string;
40
+ test_case_steps: {
41
+ step: string;
42
+ result: string;
43
+ }[];
44
+ preconditions: string;
45
+ }, {
46
+ name: string;
47
+ description: string;
48
+ test_case_steps: {
49
+ step: string;
50
+ result: string;
51
+ }[];
52
+ preconditions: string;
53
+ }>;
54
+ wait_for_completion: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
55
+ }, "strip", z.ZodTypeAny, {
56
+ project_identifier: string;
57
+ test_case_identifier: string;
58
+ base_url: string;
59
+ local_enabled: boolean;
60
+ test_name: string;
61
+ test_case_details: {
62
+ name: string;
63
+ description: string;
64
+ test_case_steps: {
65
+ step: string;
66
+ result: string;
67
+ }[];
68
+ preconditions: string;
69
+ };
70
+ wait_for_completion: boolean;
71
+ credentials?: {
72
+ username: string;
73
+ password: string;
74
+ } | undefined;
75
+ }, {
76
+ project_identifier: string;
77
+ test_case_identifier: string;
78
+ base_url: string;
79
+ test_name: string;
80
+ test_case_details: {
81
+ name: string;
82
+ description: string;
83
+ test_case_steps: {
84
+ step: string;
85
+ result: string;
86
+ }[];
87
+ preconditions: string;
88
+ };
89
+ credentials?: {
90
+ username: string;
91
+ password: string;
92
+ } | undefined;
93
+ local_enabled?: boolean | undefined;
94
+ wait_for_completion?: boolean | undefined;
95
+ }>;
96
+ export type CreateLCAStepsArgs = z.infer<typeof CreateLCAStepsSchema>;
97
+ /**
98
+ * Creates LCA (Low Code Automation) steps for a test case in BrowserStack Test Management
99
+ */
100
+ export declare function createLCASteps(args: CreateLCAStepsArgs, context: any, config: BrowserStackConfig): Promise<CallToolResult>;
@@ -1,9 +1,8 @@
1
1
  import { z } from "zod";
2
- import axios from "axios";
3
- import config from "../../config.js";
4
- import { formatAxiosError } from "../../lib/error.js";
2
+ import { apiClient } from "../../lib/apiClient.js";
5
3
  import { projectIdentifierToId, testCaseIdentifierToDetails, } from "./TCG-utils/api.js";
6
4
  import { pollLCAStatus } from "./poll-lca-status.js";
5
+ import { getBrowserStackAuth } from "../../lib/get-auth.js";
7
6
  /**
8
7
  * Schema for creating LCA steps for a test case
9
8
  */
@@ -50,12 +49,12 @@ export const CreateLCAStepsSchema = z.object({
50
49
  /**
51
50
  * Creates LCA (Low Code Automation) steps for a test case in BrowserStack Test Management
52
51
  */
53
- export async function createLCASteps(args, context) {
52
+ export async function createLCASteps(args, context, config) {
54
53
  try {
55
54
  // Get the project ID from identifier
56
- const projectId = await projectIdentifierToId(args.project_identifier);
55
+ const projectId = await projectIdentifierToId(args.project_identifier, config);
57
56
  // Get the test case ID and folder ID from identifier
58
- const { testCaseId, folderId } = await testCaseIdentifierToDetails(projectId, args.test_case_identifier);
57
+ const { testCaseId, folderId } = await testCaseIdentifierToDetails(projectId, args.test_case_identifier, config);
59
58
  const url = `https://test-management.browserstack.com/api/v1/projects/${projectId}/test-cases/${testCaseId}/lcnc`;
60
59
  const payload = {
61
60
  base_url: args.base_url,
@@ -66,67 +65,53 @@ export async function createLCASteps(args, context) {
66
65
  version: "v2",
67
66
  webhook_path: `https://test-management.browserstack.com/api/v1/projects/${projectId}/test-cases/${testCaseId}/webhooks/lcnc`,
68
67
  };
69
- const response = await axios.post(url, payload, {
68
+ await apiClient.post({
69
+ url,
70
70
  headers: {
71
- "API-TOKEN": `${config.browserstackUsername}:${config.browserstackAccessKey}`,
71
+ "API-TOKEN": getBrowserStackAuth(config),
72
72
  accept: "application/json, text/plain, */*",
73
73
  "Content-Type": "application/json",
74
74
  },
75
+ body: payload,
75
76
  });
76
- if (response.status >= 200 && response.status < 300) {
77
- // Check if user wants to wait for completion
78
- if (!args.wait_for_completion) {
77
+ // Check if user wants to wait for completion
78
+ if (!args.wait_for_completion) {
79
+ return {
80
+ content: [
81
+ {
82
+ type: "text",
83
+ text: `LCA steps creation initiated for test case ${args.test_case_identifier} (ID: ${testCaseId})`,
84
+ },
85
+ {
86
+ type: "text",
87
+ text: "LCA build started. Check the BrowserStack Lowcode Automation UI for completion status.",
88
+ },
89
+ ],
90
+ };
91
+ }
92
+ // Start polling for LCA build completion
93
+ try {
94
+ const max_wait_minutes = 10; // Maximum wait time in minutes
95
+ const maxWaitMs = max_wait_minutes * 60 * 1000;
96
+ const lcaResult = await pollLCAStatus(projectId, folderId, testCaseId, context, maxWaitMs, // max wait time
97
+ 2 * 60 * 1000, // 2 minutes initial wait
98
+ 10 * 1000, // 10 seconds interval
99
+ config);
100
+ if (lcaResult && lcaResult.status === "done") {
79
101
  return {
80
102
  content: [
81
103
  {
82
104
  type: "text",
83
- text: `LCA steps creation initiated for test case ${args.test_case_identifier} (ID: ${testCaseId})`,
105
+ text: `Successfully created LCA steps for test case ${args.test_case_identifier} (ID: ${testCaseId})`,
84
106
  },
85
107
  {
86
108
  type: "text",
87
- text: "LCA build started. Check the BrowserStack Lowcode Automation UI for completion status.",
109
+ text: `LCA build completed! Resource URL: ${lcaResult.resource_path}`,
88
110
  },
89
111
  ],
90
112
  };
91
113
  }
92
- // Start polling for LCA build completion
93
- try {
94
- const max_wait_minutes = 10; // Maximum wait time in minutes
95
- const maxWaitMs = max_wait_minutes * 60 * 1000;
96
- const lcaResult = await pollLCAStatus(projectId, folderId, testCaseId, context, maxWaitMs, // max wait time
97
- 2 * 60 * 1000, // 2 minutes initial wait
98
- 10 * 1000);
99
- if (lcaResult && lcaResult.status === "done") {
100
- return {
101
- content: [
102
- {
103
- type: "text",
104
- text: `Successfully created LCA steps for test case ${args.test_case_identifier} (ID: ${testCaseId})`,
105
- },
106
- {
107
- type: "text",
108
- text: `LCA build completed! Resource URL: ${lcaResult.resource_path}`,
109
- },
110
- ],
111
- };
112
- }
113
- else {
114
- return {
115
- content: [
116
- {
117
- type: "text",
118
- text: `LCA steps creation initiated for test case ${args.test_case_identifier} (ID: ${testCaseId})`,
119
- },
120
- {
121
- type: "text",
122
- text: `Warning: LCA build did not complete within ${max_wait_minutes} minutes. You can check the status later in the BrowserStack Test Management UI.`,
123
- },
124
- ],
125
- };
126
- }
127
- }
128
- catch (pollError) {
129
- console.error("Error during LCA polling:", pollError);
114
+ else {
130
115
  return {
131
116
  content: [
132
117
  {
@@ -135,14 +120,26 @@ export async function createLCASteps(args, context) {
135
120
  },
136
121
  {
137
122
  type: "text",
138
- text: "Warning: Error occurred while polling for LCA build completion. Check the BrowserStack Test Management UI for status.",
123
+ text: `Warning: LCA build did not complete within ${max_wait_minutes} minutes. You can check the status later in the BrowserStack Test Management UI.`,
139
124
  },
140
125
  ],
141
126
  };
142
127
  }
143
128
  }
144
- else {
145
- throw new Error(`Unexpected response: ${JSON.stringify(response.data)}`);
129
+ catch (pollError) {
130
+ console.error("Error during LCA polling:", pollError);
131
+ return {
132
+ content: [
133
+ {
134
+ type: "text",
135
+ text: `LCA steps creation initiated for test case ${args.test_case_identifier} (ID: ${testCaseId})`,
136
+ },
137
+ {
138
+ type: "text",
139
+ text: "Warning: Error occurred while polling for LCA build completion. Check the BrowserStack Test Management UI for status.",
140
+ },
141
+ ],
142
+ };
146
143
  }
147
144
  }
148
145
  catch (error) {
@@ -161,6 +158,18 @@ export async function createLCASteps(args, context) {
161
158
  };
162
159
  }
163
160
  }
164
- return formatAxiosError(error, "Failed to create LCA steps");
161
+ const msg = error?.response?.data?.message ||
162
+ error?.response?.data?.error ||
163
+ error?.message ||
164
+ String(error);
165
+ return {
166
+ content: [
167
+ {
168
+ type: "text",
169
+ text: `Failed to create LCA steps: ${msg}`,
170
+ },
171
+ ],
172
+ isError: true,
173
+ };
165
174
  }
166
175
  }
@@ -0,0 +1,31 @@
1
+ import { z } from "zod";
2
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import { BrowserStackConfig } from "../../lib/types.js";
4
+ export declare const CreateProjFoldSchema: z.ZodObject<{
5
+ project_name: z.ZodOptional<z.ZodString>;
6
+ project_description: z.ZodOptional<z.ZodString>;
7
+ project_identifier: z.ZodOptional<z.ZodString>;
8
+ folder_name: z.ZodOptional<z.ZodString>;
9
+ folder_description: z.ZodOptional<z.ZodString>;
10
+ parent_id: z.ZodOptional<z.ZodNumber>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ project_name?: string | undefined;
13
+ project_description?: string | undefined;
14
+ project_identifier?: string | undefined;
15
+ folder_name?: string | undefined;
16
+ folder_description?: string | undefined;
17
+ parent_id?: number | undefined;
18
+ }, {
19
+ project_name?: string | undefined;
20
+ project_description?: string | undefined;
21
+ project_identifier?: string | undefined;
22
+ folder_name?: string | undefined;
23
+ folder_description?: string | undefined;
24
+ parent_id?: number | undefined;
25
+ }>;
26
+ type CreateProjFoldArgs = z.infer<typeof CreateProjFoldSchema>;
27
+ /**
28
+ * Creates a project and/or folder in BrowserStack Test Management.
29
+ */
30
+ export declare function createProjectOrFolder(args: CreateProjFoldArgs, config: BrowserStackConfig): Promise<CallToolResult>;
31
+ export {};
@@ -1,8 +1,8 @@
1
- import axios from "axios";
2
- import config from "../../config.js";
1
+ import { apiClient } from "../../lib/apiClient.js";
3
2
  import { z } from "zod";
4
- import { formatAxiosError } from "../../lib/error.js"; // or correct path
3
+ import { formatAxiosError } from "../../lib/error.js";
5
4
  import { projectIdentifierToId } from "../testmanagement-utils/TCG-utils/api.js";
5
+ import { getBrowserStackAuth } from "../../lib/get-auth.js";
6
6
  // Schema for combined project/folder creation
7
7
  export const CreateProjFoldSchema = z.object({
8
8
  project_name: z
@@ -30,21 +30,29 @@ export const CreateProjFoldSchema = z.object({
30
30
  /**
31
31
  * Creates a project and/or folder in BrowserStack Test Management.
32
32
  */
33
- export async function createProjectOrFolder(args) {
33
+ export async function createProjectOrFolder(args, config) {
34
34
  const { project_name, project_description, project_identifier, folder_name, folder_description, parent_id, } = CreateProjFoldSchema.parse(args);
35
35
  if (!project_name && !project_identifier && !folder_name) {
36
36
  throw new Error("Provide project_name (to create project), or project_identifier and folder_name (to create folder).");
37
37
  }
38
+ const authString = getBrowserStackAuth(config);
39
+ const [username, password] = authString.split(":");
38
40
  let projId = project_identifier;
39
41
  // Step 1: Create project if project_name provided
40
42
  if (project_name) {
41
43
  try {
42
- const res = await axios.post("https://test-management.browserstack.com/api/v2/projects", { project: { name: project_name, description: project_description } }, {
43
- auth: {
44
- username: config.browserstackUsername,
45
- password: config.browserstackAccessKey,
44
+ const authString = getBrowserStackAuth(config);
45
+ const [username, password] = authString.split(":");
46
+ const res = await apiClient.post({
47
+ url: "https://test-management.browserstack.com/api/v2/projects",
48
+ headers: {
49
+ "Content-Type": "application/json",
50
+ Authorization: "Basic " +
51
+ Buffer.from(`${username}:${password}`).toString("base64"),
52
+ },
53
+ body: {
54
+ project: { name: project_name, description: project_description },
46
55
  },
47
- headers: { "Content-Type": "application/json" },
48
56
  });
49
57
  if (!res.data.success) {
50
58
  throw new Error(`Failed to create project: ${JSON.stringify(res.data)}`);
@@ -53,7 +61,7 @@ export async function createProjectOrFolder(args) {
53
61
  projId = res.data.project.identifier;
54
62
  }
55
63
  catch (err) {
56
- return formatAxiosError(err, "Failed to create project..");
64
+ return formatAxiosError(err, "Failed to create project.");
57
65
  }
58
66
  }
59
67
  // Step 2: Create folder if folder_name provided
@@ -61,25 +69,27 @@ export async function createProjectOrFolder(args) {
61
69
  if (!projId)
62
70
  throw new Error("Cannot create folder without project_identifier.");
63
71
  try {
64
- const res = await axios.post(`https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(projId)}/folders`, {
65
- folder: {
66
- name: folder_name,
67
- description: folder_description,
68
- parent_id,
72
+ const res = await apiClient.post({
73
+ url: `https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(projId)}/folders`,
74
+ headers: {
75
+ "Content-Type": "application/json",
76
+ Authorization: "Basic " +
77
+ Buffer.from(`${username}:${password}`).toString("base64"),
69
78
  },
70
- }, {
71
- auth: {
72
- username: config.browserstackUsername,
73
- password: config.browserstackAccessKey,
79
+ body: {
80
+ folder: {
81
+ name: folder_name,
82
+ description: folder_description,
83
+ parent_id,
84
+ },
74
85
  },
75
- headers: { "Content-Type": "application/json" },
76
86
  });
77
87
  if (!res.data.success) {
78
88
  throw new Error(`Failed to create folder: ${JSON.stringify(res.data)}`);
79
89
  }
80
90
  // Folder created successfully
81
91
  const folder = res.data.folder;
82
- const projectId = await projectIdentifierToId(projId);
92
+ const projectId = await projectIdentifierToId(projId, config);
83
93
  return {
84
94
  content: [
85
95
  {
@@ -0,0 +1,122 @@
1
+ import { z } from "zod";
2
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ import { BrowserStackConfig } from "../../lib/types.js";
4
+ interface TestCaseStep {
5
+ step: string;
6
+ result: string;
7
+ }
8
+ interface IssueTracker {
9
+ name: string;
10
+ host: string;
11
+ }
12
+ export interface TestCaseCreateRequest {
13
+ project_identifier: string;
14
+ folder_id: string;
15
+ name: string;
16
+ description?: string;
17
+ owner?: string;
18
+ preconditions?: string;
19
+ test_case_steps: TestCaseStep[];
20
+ issues?: string[];
21
+ issue_tracker?: IssueTracker;
22
+ tags?: string[];
23
+ custom_fields?: Record<string, string>;
24
+ }
25
+ export interface TestCaseResponse {
26
+ data: {
27
+ success: boolean;
28
+ test_case: {
29
+ case_type: string;
30
+ priority: string;
31
+ status: string;
32
+ folder_id: number;
33
+ issues: Array<{
34
+ jira_id: string;
35
+ issue_type: string;
36
+ }>;
37
+ tags: string[];
38
+ template: string;
39
+ description: string;
40
+ preconditions: string;
41
+ title: string;
42
+ identifier: string;
43
+ automation_status: string;
44
+ owner: string;
45
+ steps: TestCaseStep[];
46
+ custom_fields: Array<{
47
+ name: string;
48
+ value: string;
49
+ }>;
50
+ };
51
+ };
52
+ }
53
+ export declare const CreateTestCaseSchema: z.ZodObject<{
54
+ project_identifier: z.ZodString;
55
+ folder_id: z.ZodString;
56
+ name: z.ZodString;
57
+ description: z.ZodOptional<z.ZodString>;
58
+ owner: z.ZodOptional<z.ZodString>;
59
+ preconditions: z.ZodOptional<z.ZodString>;
60
+ test_case_steps: z.ZodArray<z.ZodObject<{
61
+ step: z.ZodString;
62
+ result: z.ZodString;
63
+ }, "strip", z.ZodTypeAny, {
64
+ step: string;
65
+ result: string;
66
+ }, {
67
+ step: string;
68
+ result: string;
69
+ }>, "many">;
70
+ issues: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
71
+ issue_tracker: z.ZodOptional<z.ZodObject<{
72
+ name: z.ZodString;
73
+ host: z.ZodString;
74
+ }, "strip", z.ZodTypeAny, {
75
+ name: string;
76
+ host: string;
77
+ }, {
78
+ name: string;
79
+ host: string;
80
+ }>>;
81
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
82
+ custom_fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
83
+ }, "strip", z.ZodTypeAny, {
84
+ name: string;
85
+ test_case_steps: {
86
+ step: string;
87
+ result: string;
88
+ }[];
89
+ project_identifier: string;
90
+ folder_id: string;
91
+ issues?: string[] | undefined;
92
+ description?: string | undefined;
93
+ tags?: string[] | undefined;
94
+ custom_fields?: Record<string, string> | undefined;
95
+ preconditions?: string | undefined;
96
+ owner?: string | undefined;
97
+ issue_tracker?: {
98
+ name: string;
99
+ host: string;
100
+ } | undefined;
101
+ }, {
102
+ name: string;
103
+ test_case_steps: {
104
+ step: string;
105
+ result: string;
106
+ }[];
107
+ project_identifier: string;
108
+ folder_id: string;
109
+ issues?: string[] | undefined;
110
+ description?: string | undefined;
111
+ tags?: string[] | undefined;
112
+ custom_fields?: Record<string, string> | undefined;
113
+ preconditions?: string | undefined;
114
+ owner?: string | undefined;
115
+ issue_tracker?: {
116
+ name: string;
117
+ host: string;
118
+ } | undefined;
119
+ }>;
120
+ export declare function sanitizeArgs(args: any): any;
121
+ export declare function createTestCase(params: TestCaseCreateRequest, config: BrowserStackConfig): Promise<CallToolResult>;
122
+ export {};
@@ -1,7 +1,6 @@
1
- import axios from "axios";
2
- import config from "../../config.js";
1
+ import { apiClient } from "../../lib/apiClient.js";
3
2
  import { z } from "zod";
4
- import { formatAxiosError } from "../../lib/error.js"; // or correct
3
+ import { formatAxiosError } from "../../lib/error.js";
5
4
  import { projectIdentifierToId } from "./TCG-utils/api.js";
6
5
  export const CreateTestCaseSchema = z.object({
7
6
  project_identifier: z
@@ -67,15 +66,19 @@ export function sanitizeArgs(args) {
67
66
  }
68
67
  return cleaned;
69
68
  }
70
- export async function createTestCase(params) {
69
+ import { getBrowserStackAuth } from "../../lib/get-auth.js";
70
+ export async function createTestCase(params, config) {
71
71
  const body = { test_case: params };
72
+ const authString = getBrowserStackAuth(config);
73
+ const [username, password] = authString.split(":");
72
74
  try {
73
- const response = await axios.post(`https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(params.project_identifier)}/folders/${encodeURIComponent(params.folder_id)}/test-cases`, body, {
74
- auth: {
75
- username: config.browserstackUsername,
76
- password: config.browserstackAccessKey,
75
+ const response = await apiClient.post({
76
+ url: `https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(params.project_identifier)}/folders/${encodeURIComponent(params.folder_id)}/test-cases`,
77
+ headers: {
78
+ "Content-Type": "application/json",
79
+ Authorization: "Basic " + Buffer.from(`${username}:${password}`).toString("base64"),
77
80
  },
78
- headers: { "Content-Type": "application/json" },
81
+ body,
79
82
  });
80
83
  const { data } = response.data;
81
84
  if (!data.success) {
@@ -91,7 +94,7 @@ export async function createTestCase(params) {
91
94
  };
92
95
  }
93
96
  const tc = data.test_case;
94
- const projectId = await projectIdentifierToId(params.project_identifier);
97
+ const projectId = await projectIdentifierToId(params.project_identifier, config);
95
98
  return {
96
99
  content: [
97
100
  {