@browserstack/mcp-server 1.2.22 → 1.2.23-beta.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/dist/tools/rca-agent-utils/get-failed-test-id.d.ts +2 -1
- package/dist/tools/rca-agent-utils/get-failed-test-id.js +2 -3
- package/dist/tools/rca-agent-utils/list-build-id.d.ts +4 -0
- package/dist/tools/rca-agent-utils/list-build-id.js +23 -0
- package/dist/tools/rca-agent.d.ts +1 -0
- package/dist/tools/rca-agent.js +42 -2
- package/dist/tools/testmanagement-utils/TCG-utils/api.js +6 -5
- package/dist/tools/testmanagement-utils/TCG-utils/config.d.ts +1 -0
- package/dist/tools/testmanagement-utils/TCG-utils/config.js +1 -0
- package/package.json +1 -1
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { TestStatus, FailedTestInfo } from "./types.js";
|
|
1
|
+
import { TestStatus, FailedTestInfo, TestDetails } from "./types.js";
|
|
2
2
|
export declare function getTestIds(buildId: string, authString: string, status?: TestStatus): Promise<FailedTestInfo[]>;
|
|
3
|
+
export declare function extractFailedTestIds(hierarchy: TestDetails[], status?: TestStatus): FailedTestInfo[];
|
|
@@ -46,11 +46,10 @@ export async function getTestIds(buildId, authString, status) {
|
|
|
46
46
|
throw error;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
function extractFailedTestIds(hierarchy, status) {
|
|
49
|
+
export function extractFailedTestIds(hierarchy, status) {
|
|
51
50
|
let failedTests = [];
|
|
52
51
|
for (const node of hierarchy) {
|
|
53
|
-
if (node.details?.status === status
|
|
52
|
+
if (node.details?.status === status) {
|
|
54
53
|
if (node.details?.observability_url) {
|
|
55
54
|
const idMatch = node.details.observability_url.match(/details=(\d+)/);
|
|
56
55
|
if (idMatch) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { apiClient } from "../../lib/apiClient.js";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the latest build for a project + build name across all users (not just the caller's).
|
|
4
|
+
*/
|
|
5
|
+
export async function listBuildId(projectName, buildName, username, accessKey) {
|
|
6
|
+
const authHeader = "Basic " + Buffer.from(`${username}:${accessKey}`).toString("base64");
|
|
7
|
+
const response = await apiClient.get({
|
|
8
|
+
url: "https://api-automation.browserstack.com/ext/v1/builds/latest",
|
|
9
|
+
headers: {
|
|
10
|
+
Authorization: authHeader,
|
|
11
|
+
"Content-Type": "application/json",
|
|
12
|
+
},
|
|
13
|
+
params: {
|
|
14
|
+
project_name: projectName,
|
|
15
|
+
build_name: buildName,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
const buildId = response.data?.build_id;
|
|
19
|
+
if (!buildId) {
|
|
20
|
+
throw new Error(`No build found for project "${projectName}" and build "${buildName}"`);
|
|
21
|
+
}
|
|
22
|
+
return buildId;
|
|
23
|
+
}
|
|
@@ -4,6 +4,7 @@ import { BrowserStackConfig } from "../lib/types.js";
|
|
|
4
4
|
import { TestStatus } from "./rca-agent-utils/types.js";
|
|
5
5
|
import { BuildIdArgs } from "./rca-agent-utils/types.js";
|
|
6
6
|
export declare function getBuildIdTool(args: BuildIdArgs, config: BrowserStackConfig): Promise<CallToolResult>;
|
|
7
|
+
export declare function listBuildIdTool(args: BuildIdArgs, config: BrowserStackConfig): Promise<CallToolResult>;
|
|
7
8
|
export declare function fetchRCADataTool(args: {
|
|
8
9
|
testId: number[];
|
|
9
10
|
}, config: BrowserStackConfig): Promise<CallToolResult>;
|
package/dist/tools/rca-agent.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logger from "../logger.js";
|
|
2
2
|
import { getBrowserStackAuth } from "../lib/get-auth.js";
|
|
3
3
|
import { getBuildId } from "./rca-agent-utils/get-build-id.js";
|
|
4
|
+
import { listBuildId } from "./rca-agent-utils/list-build-id.js";
|
|
4
5
|
import { getTestIds } from "./rca-agent-utils/get-failed-test-id.js";
|
|
5
6
|
import { getRCAData } from "./rca-agent-utils/rca-data.js";
|
|
6
7
|
import { formatRCAData } from "./rca-agent-utils/format-rca.js";
|
|
@@ -37,6 +38,36 @@ export async function getBuildIdTool(args, config) {
|
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
}
|
|
41
|
+
// Tool function to fetch the build ID across all users (no user scoping)
|
|
42
|
+
export async function listBuildIdTool(args, config) {
|
|
43
|
+
try {
|
|
44
|
+
const { browserStackProjectName, browserStackBuildName } = args;
|
|
45
|
+
const authString = getBrowserStackAuth(config);
|
|
46
|
+
const [username, accessKey] = authString.split(":");
|
|
47
|
+
const buildId = await listBuildId(browserStackProjectName, browserStackBuildName, username, accessKey);
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: buildId,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
logger.error("Error fetching build ID", error);
|
|
59
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: "text",
|
|
64
|
+
text: `Error fetching build ID: ${errorMessage}`,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
40
71
|
// Tool function that fetches RCA data
|
|
41
72
|
export async function fetchRCADataTool(args, config) {
|
|
42
73
|
try {
|
|
@@ -99,7 +130,7 @@ export async function listTestIdsTool(args, config) {
|
|
|
99
130
|
}
|
|
100
131
|
export default function addRCATools(server, config) {
|
|
101
132
|
const tools = {};
|
|
102
|
-
tools.fetchRCA = server.tool("fetchRCA", "Fetch AI Root Cause Analysis for failed BrowserStack Automate/App-Automate tests. Suggests fixes only; never auto-apply, require explicit user approval.", FETCH_RCA_PARAMS, async (args) => {
|
|
133
|
+
tools.fetchRCA = server.tool("fetchRCA", "Fetch AI Root Cause Analysis for the current user's failed BrowserStack Automate/App-Automate tests. Suggests fixes only; never auto-apply, require explicit user approval.", FETCH_RCA_PARAMS, async (args) => {
|
|
103
134
|
try {
|
|
104
135
|
trackMCP("fetchRCA", server.server.getClientVersion(), undefined, config);
|
|
105
136
|
return await fetchRCADataTool(args, config);
|
|
@@ -108,7 +139,7 @@ export default function addRCATools(server, config) {
|
|
|
108
139
|
return handleMCPError("fetchRCA", server, config, error);
|
|
109
140
|
}
|
|
110
141
|
});
|
|
111
|
-
tools.getBuildId = server.tool("getBuildId", "Get the BrowserStack build ID for a given project and build name.", GET_BUILD_ID_PARAMS, async (args) => {
|
|
142
|
+
tools.getBuildId = server.tool("getBuildId", "Get the BrowserStack build ID for a given project and build name, scoped to the current user's builds.", GET_BUILD_ID_PARAMS, async (args) => {
|
|
112
143
|
try {
|
|
113
144
|
trackMCP("getBuildId", server.server.getClientVersion(), undefined, config);
|
|
114
145
|
return await getBuildIdTool(args, config);
|
|
@@ -117,6 +148,15 @@ export default function addRCATools(server, config) {
|
|
|
117
148
|
return handleMCPError("getBuildId", server, config, error);
|
|
118
149
|
}
|
|
119
150
|
});
|
|
151
|
+
tools.listBuildId = server.tool("listBuildId", "Get the latest build ID for a project and build name, across all users (no user filter).", GET_BUILD_ID_PARAMS, async (args) => {
|
|
152
|
+
try {
|
|
153
|
+
trackMCP("listBuildId", server.server.getClientVersion(), undefined, config);
|
|
154
|
+
return await listBuildIdTool(args, config);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return handleMCPError("listBuildId", server, config, error);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
120
160
|
tools.listTestIds = server.tool("listTestIds", "List test IDs from a BrowserStack Automate build, optionally filtered by status", LIST_TEST_IDS_PARAMS, async (args) => {
|
|
121
161
|
try {
|
|
122
162
|
trackMCP("listTestIds", server.server.getClientVersion(), undefined, config);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { apiClient } from "../../../lib/apiClient.js";
|
|
2
|
-
import { TCG_TRIGGER_URL, TCG_POLL_URL, FETCH_DETAILS_URL, FORM_FIELDS_URL, BULK_CREATE_URL, } from "./config.js";
|
|
2
|
+
import { TCG_TRIGGER_URL, TCG_POLL_URL, FETCH_DETAILS_URL, FORM_FIELDS_URL, BULK_CREATE_URL, TC_DETAILS_MAX_BATCH, } from "./config.js";
|
|
3
3
|
import { createTestCasePayload } from "./helpers.js";
|
|
4
4
|
import { getBrowserStackAuth } from "../../../lib/get-auth.js";
|
|
5
5
|
import { getTMBaseURL } from "../../../lib/tm-base-url.js";
|
|
@@ -165,11 +165,11 @@ export async function pollScenariosTestDetails(args, traceId, context, documentI
|
|
|
165
165
|
if (msg.type === "testcase") {
|
|
166
166
|
const sc = msg.data.scenario;
|
|
167
167
|
if (sc) {
|
|
168
|
-
const array = Array.isArray(msg.data.testcases)
|
|
168
|
+
const array = (Array.isArray(msg.data.testcases)
|
|
169
169
|
? msg.data.testcases
|
|
170
170
|
: msg.data.testcases
|
|
171
171
|
? [msg.data.testcases]
|
|
172
|
-
: [];
|
|
172
|
+
: []).slice(0, TC_DETAILS_MAX_BATCH);
|
|
173
173
|
const ids = array.map((tc) => tc.id || tc.test_case_id);
|
|
174
174
|
const reqId = await fetchTestCaseDetails(documentId, folderId, projectReferenceId, ids, source, config);
|
|
175
175
|
detailPromises.push(pollTestCaseDetails(reqId, config));
|
|
@@ -228,12 +228,13 @@ export async function bulkCreateTestCases(scenariosMap, projectId, folderId, fie
|
|
|
228
228
|
const tmBaseUrl = await getTMBaseURL(config);
|
|
229
229
|
const BULK_CREATE_URL_VALUE = BULK_CREATE_URL(tmBaseUrl, projectId, folderId);
|
|
230
230
|
for (const { id, testcases } of Object.values(scenariosMap)) {
|
|
231
|
-
const
|
|
231
|
+
const cappedTestcases = testcases.slice(0, TC_DETAILS_MAX_BATCH);
|
|
232
|
+
const testCaseLength = cappedTestcases.length;
|
|
232
233
|
testCaseCount += testCaseLength;
|
|
233
234
|
if (testCaseLength === 0)
|
|
234
235
|
continue;
|
|
235
236
|
const payload = {
|
|
236
|
-
test_cases:
|
|
237
|
+
test_cases: cappedTestcases.map((tc) => createTestCasePayload(tc, id, folderId, fieldMaps, documentId, booleanFieldId, traceId)),
|
|
237
238
|
};
|
|
238
239
|
try {
|
|
239
240
|
const resp = await apiClient.post({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export const TC_DETAILS_MAX_BATCH = 10;
|
|
1
2
|
export const TCG_TRIGGER_URL = (baseUrl) => `${baseUrl}/api/v1/integration/tcg/test-generation/suggest-test-cases`;
|
|
2
3
|
export const TCG_POLL_URL = (baseUrl) => `${baseUrl}/api/v1/integration/tcg/test-generation/test-cases-polling`;
|
|
3
4
|
export const FETCH_DETAILS_URL = (baseUrl) => `${baseUrl}/api/v1/integration/tcg/test-generation/fetch-test-case-details`;
|