@browserstack/mcp-server 1.0.5 → 1.0.6
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/dist/index.js +4 -0
- package/dist/lib/api.js +48 -0
- package/dist/lib/error.js +26 -0
- package/dist/tools/automate.js +52 -0
- package/dist/tools/sdk-utils/constants.js +1 -0
- package/dist/tools/testmanagement-utils/create-project-folder.js +107 -0
- package/dist/tools/testmanagement-utils/create-testcase.js +115 -0
- package/dist/tools/testmanagement.js +56 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,12 +14,16 @@ const applive_1 = __importDefault(require("./tools/applive"));
|
|
|
14
14
|
const observability_1 = __importDefault(require("./tools/observability"));
|
|
15
15
|
const live_1 = __importDefault(require("./tools/live"));
|
|
16
16
|
const accessibility_1 = __importDefault(require("./tools/accessibility"));
|
|
17
|
+
const automate_1 = __importDefault(require("./tools/automate"));
|
|
18
|
+
const testmanagement_1 = __importDefault(require("./tools/testmanagement"));
|
|
17
19
|
function registerTools(server) {
|
|
18
20
|
(0, bstack_sdk_1.default)(server);
|
|
19
21
|
(0, applive_1.default)(server);
|
|
20
22
|
(0, live_1.default)(server);
|
|
21
23
|
(0, observability_1.default)(server);
|
|
22
24
|
(0, accessibility_1.default)(server);
|
|
25
|
+
(0, automate_1.default)(server);
|
|
26
|
+
(0, testmanagement_1.default)(server);
|
|
23
27
|
}
|
|
24
28
|
// Create an MCP server
|
|
25
29
|
const server = new mcp_js_1.McpServer({
|
package/dist/lib/api.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getLatestO11YBuildInfo = getLatestO11YBuildInfo;
|
|
7
|
+
exports.retrieveNetworkFailures = retrieveNetworkFailures;
|
|
7
8
|
const config_1 = __importDefault(require("../config"));
|
|
8
9
|
async function getLatestO11YBuildInfo(buildName, projectName) {
|
|
9
10
|
const buildsUrl = `https://api-observability.browserstack.com/ext/v1/builds/latest?build_name=${encodeURIComponent(buildName)}&project_name=${encodeURIComponent(projectName)}`;
|
|
@@ -20,3 +21,50 @@ async function getLatestO11YBuildInfo(buildName, projectName) {
|
|
|
20
21
|
}
|
|
21
22
|
return buildsResponse.json();
|
|
22
23
|
}
|
|
24
|
+
// Fetches network logs for a given session ID and returns only failure logs
|
|
25
|
+
async function retrieveNetworkFailures(sessionId) {
|
|
26
|
+
if (!sessionId) {
|
|
27
|
+
throw new Error("Session ID is required");
|
|
28
|
+
}
|
|
29
|
+
const url = `https://api.browserstack.com/automate/sessions/${sessionId}/networklogs`;
|
|
30
|
+
const auth = Buffer.from(`${config_1.default.browserstackUsername}:${config_1.default.browserstackAccessKey}`).toString("base64");
|
|
31
|
+
const response = await fetch(url, {
|
|
32
|
+
method: "GET",
|
|
33
|
+
headers: {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
Authorization: `Basic ${auth}`,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
if (response.status === 404) {
|
|
40
|
+
throw new Error("Invalid session ID");
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`Failed to fetch network logs: ${response.statusText}`);
|
|
43
|
+
}
|
|
44
|
+
const networklogs = await response.json();
|
|
45
|
+
// Filter for failure logs
|
|
46
|
+
const failureEntries = networklogs.log.entries.filter((entry) => {
|
|
47
|
+
return (entry.response.status === 0 ||
|
|
48
|
+
entry.response.status >= 400 ||
|
|
49
|
+
entry.response._error !== undefined);
|
|
50
|
+
});
|
|
51
|
+
// Return only the failure entries with some context
|
|
52
|
+
return {
|
|
53
|
+
failures: failureEntries.map((entry) => ({
|
|
54
|
+
startedDateTime: entry.startedDateTime,
|
|
55
|
+
request: {
|
|
56
|
+
method: entry.request?.method,
|
|
57
|
+
url: entry.request?.url,
|
|
58
|
+
queryString: entry.request?.queryString,
|
|
59
|
+
},
|
|
60
|
+
response: {
|
|
61
|
+
status: entry.response?.status,
|
|
62
|
+
statusText: entry.response?.statusText,
|
|
63
|
+
_error: entry.response?._error,
|
|
64
|
+
},
|
|
65
|
+
serverIPAddress: entry.serverIPAddress,
|
|
66
|
+
time: entry.time,
|
|
67
|
+
})),
|
|
68
|
+
totalFailures: failureEntries.length,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatAxiosError = formatAxiosError;
|
|
4
|
+
const axios_1 = require("axios");
|
|
5
|
+
/**
|
|
6
|
+
* Formats an AxiosError into a CallToolResult with an appropriate message.
|
|
7
|
+
* @param err - The error object to format
|
|
8
|
+
* @param defaultText - The fallback error message
|
|
9
|
+
*/
|
|
10
|
+
function formatAxiosError(err, defaultText) {
|
|
11
|
+
let text = defaultText;
|
|
12
|
+
if (err instanceof axios_1.AxiosError && err.response?.data) {
|
|
13
|
+
const message = err.response.data.message ||
|
|
14
|
+
err.response.data.error ||
|
|
15
|
+
err.message ||
|
|
16
|
+
defaultText;
|
|
17
|
+
text = message;
|
|
18
|
+
}
|
|
19
|
+
else if (err instanceof Error) {
|
|
20
|
+
text = err.message;
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text }],
|
|
24
|
+
isError: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getNetworkFailures = getNetworkFailures;
|
|
7
|
+
exports.default = addAutomateTools;
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
10
|
+
const api_1 = require("../lib/api");
|
|
11
|
+
/**
|
|
12
|
+
* Fetches failed network requests from a BrowserStack Automate session.
|
|
13
|
+
* Returns network requests that resulted in errors or failed to complete.
|
|
14
|
+
*/
|
|
15
|
+
async function getNetworkFailures(args) {
|
|
16
|
+
try {
|
|
17
|
+
const failureLogs = await (0, api_1.retrieveNetworkFailures)(args.sessionId);
|
|
18
|
+
logger_1.default.info("Successfully fetched failure network logs for session: %s", args.sessionId);
|
|
19
|
+
// Check if there are any failures
|
|
20
|
+
const hasFailures = failureLogs.totalFailures > 0;
|
|
21
|
+
const text = hasFailures
|
|
22
|
+
? `${failureLogs.totalFailures} network failure(s) found for session :\n\n${JSON.stringify(failureLogs.failures, null, 2)}`
|
|
23
|
+
: `No network failures found for session`;
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: "text",
|
|
28
|
+
text,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
|
35
|
+
logger_1.default.error("Failed to fetch network logs: %s", errorMessage);
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: `Failed to fetch network logs: ${errorMessage}`,
|
|
41
|
+
isError: true,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
isError: true,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function addAutomateTools(server) {
|
|
49
|
+
server.tool("getNetworkFailures", "Use this tool to fetch failed network requests from a BrowserStack Automate session.", {
|
|
50
|
+
sessionId: zod_1.z.string().describe("The Automate session ID."),
|
|
51
|
+
}, getNetworkFailures);
|
|
52
|
+
}
|
|
@@ -17,6 +17,7 @@ const nodejsInstructions = `
|
|
|
17
17
|
\`\`\`json
|
|
18
18
|
"browserstack-node-sdk": "latest"
|
|
19
19
|
\`\`\`
|
|
20
|
+
- Inform user to export BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY as environment variables.
|
|
20
21
|
`;
|
|
21
22
|
const pythonInstructions = `
|
|
22
23
|
Run the following command to install the browserstack-sdk:
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CreateProjFoldSchema = void 0;
|
|
7
|
+
exports.createProjectOrFolder = createProjectOrFolder;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const config_1 = __importDefault(require("../../config"));
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
const error_1 = require("../../lib/error"); // or correct path
|
|
12
|
+
// Schema for combined project/folder creation
|
|
13
|
+
exports.CreateProjFoldSchema = zod_1.z.object({
|
|
14
|
+
project_name: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Name of the project to create."),
|
|
18
|
+
project_description: zod_1.z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Description for the new project."),
|
|
22
|
+
project_identifier: zod_1.z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Existing project identifier to use for folder creation."),
|
|
26
|
+
folder_name: zod_1.z.string().optional().describe("Name of the folder to create."),
|
|
27
|
+
folder_description: zod_1.z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Description for the new folder."),
|
|
31
|
+
parent_id: zod_1.z
|
|
32
|
+
.number()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Parent folder ID; if omitted, folder is created at root."),
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Creates a project and/or folder in BrowserStack Test Management.
|
|
38
|
+
*/
|
|
39
|
+
async function createProjectOrFolder(args) {
|
|
40
|
+
const { project_name, project_description, project_identifier, folder_name, folder_description, parent_id, } = exports.CreateProjFoldSchema.parse(args);
|
|
41
|
+
if (!project_name && !project_identifier && !folder_name) {
|
|
42
|
+
throw new Error("Provide project_name (to create project), or project_identifier and folder_name (to create folder).");
|
|
43
|
+
}
|
|
44
|
+
let projId = project_identifier;
|
|
45
|
+
// Step 1: Create project if project_name provided
|
|
46
|
+
if (project_name) {
|
|
47
|
+
try {
|
|
48
|
+
const res = await axios_1.default.post("https://test-management.browserstack.com/api/v2/projects", { project: { name: project_name, description: project_description } }, {
|
|
49
|
+
auth: {
|
|
50
|
+
username: config_1.default.browserstackUsername,
|
|
51
|
+
password: config_1.default.browserstackAccessKey,
|
|
52
|
+
},
|
|
53
|
+
headers: { "Content-Type": "application/json" },
|
|
54
|
+
});
|
|
55
|
+
if (!res.data.success) {
|
|
56
|
+
throw new Error(`Failed to create project: ${JSON.stringify(res.data)}`);
|
|
57
|
+
}
|
|
58
|
+
// Project created successfully
|
|
59
|
+
projId = res.data.project.identifier;
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return (0, error_1.formatAxiosError)(err, "Failed to create project..");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Step 2: Create folder if folder_name provided
|
|
66
|
+
if (folder_name) {
|
|
67
|
+
if (!projId)
|
|
68
|
+
throw new Error("Cannot create folder without project_identifier.");
|
|
69
|
+
try {
|
|
70
|
+
const res = await axios_1.default.post(`https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(projId)}/folders`, {
|
|
71
|
+
folder: {
|
|
72
|
+
name: folder_name,
|
|
73
|
+
description: folder_description,
|
|
74
|
+
parent_id,
|
|
75
|
+
},
|
|
76
|
+
}, {
|
|
77
|
+
auth: {
|
|
78
|
+
username: config_1.default.browserstackUsername,
|
|
79
|
+
password: config_1.default.browserstackAccessKey,
|
|
80
|
+
},
|
|
81
|
+
headers: { "Content-Type": "application/json" },
|
|
82
|
+
});
|
|
83
|
+
if (!res.data.success) {
|
|
84
|
+
throw new Error(`Failed to create folder: ${JSON.stringify(res.data)}`);
|
|
85
|
+
}
|
|
86
|
+
// Folder created successfully
|
|
87
|
+
const folder = res.data.folder;
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: `Folder created: ID=${folder.id}, name=${folder.name} in project with identifier ${projId}`,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
return (0, error_1.formatAxiosError)(err, "Failed to create folder.");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Only project was created
|
|
102
|
+
return {
|
|
103
|
+
content: [
|
|
104
|
+
{ type: "text", text: `Project created with identifier=${projId}` },
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CreateTestCaseSchema = void 0;
|
|
7
|
+
exports.sanitizeArgs = sanitizeArgs;
|
|
8
|
+
exports.createTestCase = createTestCase;
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const config_1 = __importDefault(require("../../config"));
|
|
11
|
+
const zod_1 = require("zod");
|
|
12
|
+
const error_1 = require("../../lib/error"); // or correct
|
|
13
|
+
exports.CreateTestCaseSchema = zod_1.z.object({
|
|
14
|
+
project_identifier: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.describe("The ID of the BrowserStack project where the test case should be created. If no project identifier is provided, ask the user if they would like to create a new project using the createProjectOrFolder tool."),
|
|
17
|
+
folder_id: zod_1.z
|
|
18
|
+
.string()
|
|
19
|
+
.describe("The ID of the folder within the project where the test case should be created. If not provided, ask the user if they would like to create a new folder using the createProjectOrFolder tool."),
|
|
20
|
+
name: zod_1.z.string().describe("Name of the test case."),
|
|
21
|
+
description: zod_1.z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Brief description of the test case."),
|
|
25
|
+
owner: zod_1.z
|
|
26
|
+
.string()
|
|
27
|
+
.email()
|
|
28
|
+
.describe("Email of the test case owner.")
|
|
29
|
+
.optional(),
|
|
30
|
+
preconditions: zod_1.z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Any preconditions (HTML allowed)."),
|
|
34
|
+
test_case_steps: zod_1.z
|
|
35
|
+
.array(zod_1.z.object({
|
|
36
|
+
step: zod_1.z.string().describe("Action to perform in this step."),
|
|
37
|
+
result: zod_1.z.string().describe("Expected result of this step."),
|
|
38
|
+
}))
|
|
39
|
+
.describe("List of steps and expected results."),
|
|
40
|
+
issues: zod_1.z
|
|
41
|
+
.array(zod_1.z.string())
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("List of the linked Jira, Asana or Azure issues ID's. This should be strictly in array format not the string of json."),
|
|
44
|
+
issue_tracker: zod_1.z
|
|
45
|
+
.object({
|
|
46
|
+
name: zod_1.z
|
|
47
|
+
.string()
|
|
48
|
+
.describe("Issue tracker name, For example, use jira for Jira, azure for Azure DevOps, or asana for Asana."),
|
|
49
|
+
host: zod_1.z.string().url().describe("Base URL of the issue tracker."),
|
|
50
|
+
})
|
|
51
|
+
.optional(),
|
|
52
|
+
tags: zod_1.z
|
|
53
|
+
.array(zod_1.z.string())
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("Tags to attach to the test case. This should be strictly in array format not the string of json"),
|
|
56
|
+
custom_fields: zod_1.z
|
|
57
|
+
.record(zod_1.z.string(), zod_1.z.string())
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("Map of custom field names to values."),
|
|
60
|
+
});
|
|
61
|
+
function sanitizeArgs(args) {
|
|
62
|
+
const cleaned = { ...args };
|
|
63
|
+
if (cleaned.description === null)
|
|
64
|
+
delete cleaned.description;
|
|
65
|
+
if (cleaned.owner === null)
|
|
66
|
+
delete cleaned.owner;
|
|
67
|
+
if (cleaned.preconditions === null)
|
|
68
|
+
delete cleaned.preconditions;
|
|
69
|
+
if (cleaned.issue_tracker) {
|
|
70
|
+
if (cleaned.issue_tracker.name === undefined ||
|
|
71
|
+
cleaned.issue_tracker.host === undefined) {
|
|
72
|
+
delete cleaned.issue_tracker;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return cleaned;
|
|
76
|
+
}
|
|
77
|
+
async function createTestCase(params) {
|
|
78
|
+
const body = { test_case: params };
|
|
79
|
+
try {
|
|
80
|
+
const response = await axios_1.default.post(`https://test-management.browserstack.com/api/v2/projects/${encodeURIComponent(params.project_identifier)}/folders/${encodeURIComponent(params.folder_id)}/test-cases`, body, {
|
|
81
|
+
auth: {
|
|
82
|
+
username: config_1.default.browserstackUsername,
|
|
83
|
+
password: config_1.default.browserstackAccessKey,
|
|
84
|
+
},
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
});
|
|
87
|
+
const { data } = response.data;
|
|
88
|
+
if (!data.success) {
|
|
89
|
+
return {
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: "text",
|
|
93
|
+
text: `Failed to create test case: ${JSON.stringify(response.data)}`,
|
|
94
|
+
isError: true,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
isError: true,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const tc = data.test_case;
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: `Successfully created test case ${tc.identifier}: ${tc.title}`,
|
|
106
|
+
},
|
|
107
|
+
{ type: "text", text: JSON.stringify(tc, null, 2) },
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
// Delegate to our centralized Axios error formatter
|
|
113
|
+
return (0, error_1.formatAxiosError)(err, "Failed to create test case");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createProjectOrFolderTool = createProjectOrFolderTool;
|
|
4
|
+
exports.createTestCaseTool = createTestCaseTool;
|
|
5
|
+
exports.default = addTestManagementTools;
|
|
6
|
+
const create_project_folder_1 = require("./testmanagement-utils/create-project-folder");
|
|
7
|
+
const create_testcase_1 = require("./testmanagement-utils/create-testcase");
|
|
8
|
+
/**
|
|
9
|
+
* Wrapper to call createProjectOrFolder util.
|
|
10
|
+
*/
|
|
11
|
+
async function createProjectOrFolderTool(args) {
|
|
12
|
+
try {
|
|
13
|
+
return await (0, create_project_folder_1.createProjectOrFolder)(args);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: `Failed to create project/folder: ${err instanceof Error ? err.message : "Unknown error"}. Please open an issue on GitHub if the problem persists`,
|
|
21
|
+
isError: true,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
isError: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Creates a test case in BrowserStack Test Management.
|
|
30
|
+
*/
|
|
31
|
+
async function createTestCaseTool(args) {
|
|
32
|
+
// Sanitize input arguments
|
|
33
|
+
const cleanedArgs = (0, create_testcase_1.sanitizeArgs)(args);
|
|
34
|
+
try {
|
|
35
|
+
return await (0, create_testcase_1.createTestCase)(cleanedArgs);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
return {
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: `Failed to create test case: ${err instanceof Error ? err.message : "Unknown error"}. Please open an issue on GitHub if the problem persists`,
|
|
43
|
+
isError: true,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
isError: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Registers both project/folder and test-case tools.
|
|
52
|
+
*/
|
|
53
|
+
function addTestManagementTools(server) {
|
|
54
|
+
server.tool("createProjectOrFolder", "Create a project and/or folder in BrowserStack Test Management.", create_project_folder_1.CreateProjFoldSchema.shape, createProjectOrFolderTool);
|
|
55
|
+
server.tool("createTestCase", "Use this tool to create a test case in BrowserStack Test Management.", create_testcase_1.CreateTestCaseSchema.shape, createTestCaseTool);
|
|
56
|
+
}
|