@browserstack/mcp-server 1.3.1-beta.1 → 1.4.0-beta.1
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 +5 -2
- package/dist/server-factory.js +5 -0
- package/dist/tools/accessibility.js +5 -2
- package/dist/tools/ask-browserstack/central-oauth.d.ts +114 -0
- package/dist/tools/ask-browserstack/central-oauth.js +271 -0
- package/dist/tools/ask-browserstack/config.d.ts +96 -0
- package/dist/tools/ask-browserstack/config.js +134 -0
- package/dist/tools/ask-browserstack/egress.d.ts +34 -0
- package/dist/tools/ask-browserstack/egress.js +31 -0
- package/dist/tools/ask-browserstack/register.d.ts +61 -0
- package/dist/tools/ask-browserstack/register.js +394 -0
- package/dist/tools/ask-browserstack/relay.d.ts +201 -0
- package/dist/tools/ask-browserstack/relay.js +575 -0
- package/dist/tools/ask-browserstack/stream.d.ts +116 -0
- package/dist/tools/ask-browserstack/stream.js +237 -0
- package/dist/tools/ask-browserstack/types.d.ts +196 -0
- package/dist/tools/ask-browserstack/types.js +10 -0
- package/dist/tools/get-failure-logs.js +3 -1
- package/dist/tools/rca-agent.js +5 -2
- package/dist/tools/selfheal.js +5 -2
- package/dist/tools/testmanagement.js +33 -15
- package/dist/tools/tool-handoff.d.ts +37 -0
- package/dist/tools/tool-handoff.js +47 -0
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ import { getTestPlan, GetTestPlanSchema, } from "./testmanagement-utils/get-test
|
|
|
19
19
|
import { listSubTestPlans, ListSubTestPlansSchema, } from "./testmanagement-utils/list-sub-testplans.js";
|
|
20
20
|
import { getSubTestPlan, GetSubTestPlanSchema, } from "./testmanagement-utils/get-sub-testplan.js";
|
|
21
21
|
import { elicitCredentialsIfSupported } from "../lib/elicit-credentials.js";
|
|
22
|
+
import { NEEDS_PROJECT_ID, NEEDS_TEST_PLAN_ID } from "./tool-handoff.js";
|
|
22
23
|
//TODO: Moving the traceMCP and catch block to the parent(server) function
|
|
23
24
|
/**
|
|
24
25
|
* Wrapper to call createProjectOrFolder util.
|
|
@@ -432,35 +433,40 @@ export async function getSubTestPlanTool(args, config, server) {
|
|
|
432
433
|
*/
|
|
433
434
|
export default function addTestManagementTools(server, config) {
|
|
434
435
|
const tools = {};
|
|
435
|
-
tools.createProjectOrFolder = server.tool("createProjectOrFolder", "Create a project and/or folder in BrowserStack Test Management."
|
|
436
|
+
tools.createProjectOrFolder = server.tool("createProjectOrFolder", "Create a project and/or folder in BrowserStack Test Management." +
|
|
437
|
+
NEEDS_PROJECT_ID, CreateProjFoldSchema.shape, {
|
|
436
438
|
title: "Create Project or Folder",
|
|
437
439
|
readOnlyHint: false,
|
|
438
440
|
openWorldHint: false,
|
|
439
441
|
destructiveHint: false,
|
|
440
442
|
idempotentHint: false,
|
|
441
443
|
}, (args) => createProjectOrFolderTool(args, config, server));
|
|
442
|
-
tools.createTestCase = server.tool("createTestCase", "Use this tool to create a test case in BrowserStack Test Management."
|
|
444
|
+
tools.createTestCase = server.tool("createTestCase", "Use this tool to create a test case in BrowserStack Test Management." +
|
|
445
|
+
NEEDS_PROJECT_ID, CreateTestCaseSchema.shape, {
|
|
443
446
|
title: "Create Test Case",
|
|
444
447
|
readOnlyHint: false,
|
|
445
448
|
openWorldHint: false,
|
|
446
449
|
destructiveHint: false,
|
|
447
450
|
idempotentHint: false,
|
|
448
451
|
}, (args) => createTestCaseTool(args, config, server));
|
|
449
|
-
tools.updateTestCase = server.tool("updateTestCase", "Update an existing test case in BrowserStack Test Management. Any subset of the following fields may be changed: name, description, preconditions, test_case_steps, owner, priority, case_type, automation_status, status, tags, issues, custom_fields. Only the supplied fields are modified."
|
|
452
|
+
tools.updateTestCase = server.tool("updateTestCase", "Update an existing test case in BrowserStack Test Management. Any subset of the following fields may be changed: name, description, preconditions, test_case_steps, owner, priority, case_type, automation_status, status, tags, issues, custom_fields. Only the supplied fields are modified." +
|
|
453
|
+
NEEDS_PROJECT_ID, UpdateTestCaseSchema.shape, {
|
|
450
454
|
title: "Update Test Case",
|
|
451
455
|
readOnlyHint: false,
|
|
452
456
|
openWorldHint: false,
|
|
453
457
|
destructiveHint: true,
|
|
454
458
|
idempotentHint: true,
|
|
455
459
|
}, (args) => updateTestCaseTool(args, config, server));
|
|
456
|
-
tools.listTestCases = server.tool("listTestCases", "List test cases in a project, optionally scoped to a specific folder. Omit folder_id to list all test cases in the project; provide folder_id (discoverable via listFolders) to list only that folder's cases. Supports filters: case_type, priority, pagination."
|
|
460
|
+
tools.listTestCases = server.tool("listTestCases", "List test cases in a project, optionally scoped to a specific folder. Omit folder_id to list all test cases in the project; provide folder_id (discoverable via listFolders) to list only that folder's cases. Supports filters: case_type, priority, pagination." +
|
|
461
|
+
NEEDS_PROJECT_ID, ListTestCasesSchema.shape, {
|
|
457
462
|
title: "List Test Cases",
|
|
458
463
|
readOnlyHint: true,
|
|
459
464
|
openWorldHint: false,
|
|
460
465
|
destructiveHint: false,
|
|
461
466
|
idempotentHint: true,
|
|
462
467
|
}, (args) => listTestCasesTool(args, config, server));
|
|
463
|
-
tools.listFolders = server.tool("listFolders", "List folders in a BrowserStack Test Management project, returning each folder's id and name (plus case counts and sub-folder counts). Pass parent_id to list sub-folders under a specific folder instead of top-level folders."
|
|
468
|
+
tools.listFolders = server.tool("listFolders", "List folders in a BrowserStack Test Management project, returning each folder's id and name (plus case counts and sub-folder counts). Pass parent_id to list sub-folders under a specific folder instead of top-level folders." +
|
|
469
|
+
NEEDS_PROJECT_ID, ListFoldersSchema.shape, {
|
|
464
470
|
title: "List Folders",
|
|
465
471
|
readOnlyHint: true,
|
|
466
472
|
openWorldHint: false,
|
|
@@ -474,35 +480,39 @@ export default function addTestManagementTools(server, config) {
|
|
|
474
480
|
destructiveHint: false,
|
|
475
481
|
idempotentHint: true,
|
|
476
482
|
}, (args) => listTemplatesTool(args, config, server));
|
|
477
|
-
tools.createTestRun = server.tool("createTestRun", "Create a test run in BrowserStack Test Management.", CreateTestRunSchema.shape, {
|
|
483
|
+
tools.createTestRun = server.tool("createTestRun", "Create a test run in BrowserStack Test Management." + NEEDS_PROJECT_ID, CreateTestRunSchema.shape, {
|
|
478
484
|
title: "Create Test Run",
|
|
479
485
|
readOnlyHint: false,
|
|
480
486
|
openWorldHint: false,
|
|
481
487
|
destructiveHint: false,
|
|
482
488
|
idempotentHint: false,
|
|
483
489
|
}, (args) => createTestRunTool(args, config, server));
|
|
484
|
-
tools.listTestRuns = server.tool("listTestRuns", "List test runs in a project with optional filters (date ranges, assignee, state, etc.)"
|
|
490
|
+
tools.listTestRuns = server.tool("listTestRuns", "List test runs in a project with optional filters (date ranges, assignee, state, etc.)" +
|
|
491
|
+
NEEDS_PROJECT_ID, ListTestRunsSchema.shape, {
|
|
485
492
|
title: "List Test Runs",
|
|
486
493
|
readOnlyHint: true,
|
|
487
494
|
openWorldHint: false,
|
|
488
495
|
destructiveHint: false,
|
|
489
496
|
idempotentHint: true,
|
|
490
497
|
}, (args) => listTestRunsTool(args, config, server));
|
|
491
|
-
tools.updateTestRun = server.tool("updateTestRun", "Update a test run's metadata and/or add test cases to it."
|
|
498
|
+
tools.updateTestRun = server.tool("updateTestRun", "Update a test run's metadata and/or add test cases to it." +
|
|
499
|
+
NEEDS_PROJECT_ID, UpdateTestRunSchema.shape, {
|
|
492
500
|
title: "Update Test Run",
|
|
493
501
|
readOnlyHint: false,
|
|
494
502
|
openWorldHint: false,
|
|
495
503
|
destructiveHint: true,
|
|
496
504
|
idempotentHint: true,
|
|
497
505
|
}, (args) => updateTestRunTool(args, config, server));
|
|
498
|
-
tools.addTestResult = server.tool("addTestResult", "Add a test result to a specific test run via BrowserStack Test Management API."
|
|
506
|
+
tools.addTestResult = server.tool("addTestResult", "Add a test result to a specific test run via BrowserStack Test Management API." +
|
|
507
|
+
NEEDS_PROJECT_ID, AddTestResultSchema.shape, {
|
|
499
508
|
title: "Add Test Result",
|
|
500
509
|
readOnlyHint: false,
|
|
501
510
|
openWorldHint: false,
|
|
502
511
|
destructiveHint: false,
|
|
503
512
|
idempotentHint: false,
|
|
504
513
|
}, (args) => addTestResultTool(args, config, server));
|
|
505
|
-
tools.uploadProductRequirementFile = server.tool("uploadProductRequirementFile", "Upload files (e.g., PDRs, PDFs) to BrowserStack Test Management and retrieve a file mapping ID. This is utilized for generating test cases from files and is part of the Test Case Generator AI Agent in BrowserStack."
|
|
514
|
+
tools.uploadProductRequirementFile = server.tool("uploadProductRequirementFile", "Upload files (e.g., PDRs, PDFs) to BrowserStack Test Management and retrieve a file mapping ID. This is utilized for generating test cases from files and is part of the Test Case Generator AI Agent in BrowserStack." +
|
|
515
|
+
NEEDS_PROJECT_ID, UploadFileSchema.shape, {
|
|
506
516
|
title: "Upload Product Requirement File",
|
|
507
517
|
readOnlyHint: false,
|
|
508
518
|
openWorldHint: false,
|
|
@@ -516,35 +526,43 @@ export default function addTestManagementTools(server, config) {
|
|
|
516
526
|
destructiveHint: false,
|
|
517
527
|
idempotentHint: false,
|
|
518
528
|
}, (args, context) => createTestCasesFromFileTool(args, context, config, server));
|
|
519
|
-
tools.createLCASteps = server.tool("createLCASteps", "Generate Low Code Automation (LCA) steps for a test case in BrowserStack Test Management using the Low Code Automation Agent."
|
|
529
|
+
tools.createLCASteps = server.tool("createLCASteps", "Generate Low Code Automation (LCA) steps for a test case in BrowserStack Test Management using the Low Code Automation Agent." +
|
|
530
|
+
NEEDS_PROJECT_ID, CreateLCAStepsSchema.shape, {
|
|
520
531
|
title: "Create LCA Steps",
|
|
521
532
|
readOnlyHint: false,
|
|
522
533
|
openWorldHint: false,
|
|
523
534
|
destructiveHint: false,
|
|
524
535
|
idempotentHint: false,
|
|
525
536
|
}, (args, context) => createLCAStepsTool(args, context, config, server));
|
|
526
|
-
tools.listTestPlans = server.tool("listTestPlans", "List test plans in a BrowserStack Test Management project. Returns each plan's identifier (TP-*), name, status, description, dates, and active/closed test-run counts. Supports pagination."
|
|
537
|
+
tools.listTestPlans = server.tool("listTestPlans", "List test plans in a BrowserStack Test Management project. Returns each plan's identifier (TP-*), name, status, description, dates, and active/closed test-run counts. Supports pagination." +
|
|
538
|
+
NEEDS_PROJECT_ID, ListTestPlansSchema.shape, {
|
|
527
539
|
title: "List Test Plans",
|
|
528
540
|
readOnlyHint: true,
|
|
529
541
|
openWorldHint: false,
|
|
530
542
|
destructiveHint: false,
|
|
531
543
|
idempotentHint: true,
|
|
532
544
|
}, (args) => listTestPlansTool(args, config, server));
|
|
533
|
-
tools.getTestPlan = server.tool("getTestPlan", "Fetch a test plan by identifier (TP-*) from BrowserStack Test Management. Returns plan metadata, the full list of linked test runs, total test-case count across runs, and a status summary — suitable for generating test documentation or QA status reports."
|
|
545
|
+
tools.getTestPlan = server.tool("getTestPlan", "Fetch a test plan by identifier (TP-*) from BrowserStack Test Management. Returns plan metadata, the full list of linked test runs, total test-case count across runs, and a status summary — suitable for generating test documentation or QA status reports." +
|
|
546
|
+
NEEDS_PROJECT_ID +
|
|
547
|
+
NEEDS_TEST_PLAN_ID, GetTestPlanSchema.shape, {
|
|
534
548
|
title: "Get Test Plan",
|
|
535
549
|
readOnlyHint: true,
|
|
536
550
|
openWorldHint: false,
|
|
537
551
|
destructiveHint: false,
|
|
538
552
|
idempotentHint: true,
|
|
539
553
|
}, (args) => getTestPlanTool(args, config, server));
|
|
540
|
-
tools.listSubTestPlans = server.tool("listSubTestPlans", "List sub-test-plans under a parent test plan (TP-*) in a Test Management project. Supports pagination."
|
|
554
|
+
tools.listSubTestPlans = server.tool("listSubTestPlans", "List sub-test-plans under a parent test plan (TP-*) in a Test Management project. Supports pagination." +
|
|
555
|
+
NEEDS_PROJECT_ID +
|
|
556
|
+
NEEDS_TEST_PLAN_ID, ListSubTestPlansSchema.shape, {
|
|
541
557
|
title: "List Sub Test Plans",
|
|
542
558
|
readOnlyHint: true,
|
|
543
559
|
openWorldHint: false,
|
|
544
560
|
destructiveHint: false,
|
|
545
561
|
idempotentHint: true,
|
|
546
562
|
}, (args) => listSubTestPlansTool(args, config, server));
|
|
547
|
-
tools.getSubTestPlan = server.tool("getSubTestPlan", "Fetch a sub-test-plan (STP-*) under a parent plan (TP-*). Returns metadata and linked test runs."
|
|
563
|
+
tools.getSubTestPlan = server.tool("getSubTestPlan", "Fetch a sub-test-plan (STP-*) under a parent plan (TP-*). Returns metadata and linked test runs." +
|
|
564
|
+
NEEDS_PROJECT_ID +
|
|
565
|
+
NEEDS_TEST_PLAN_ID, GetSubTestPlanSchema.shape, {
|
|
548
566
|
title: "Get Sub Test Plan",
|
|
549
567
|
readOnlyHint: true,
|
|
550
568
|
openWorldHint: false,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Precondition sentences appended to a tool's description.
|
|
3
|
+
*
|
|
4
|
+
* WHY THESE EXIST. Nothing routes an MCP call: the client's model picks a tool from the
|
|
5
|
+
* descriptions alone. A tool that needs an identifier the caller does not have is a dead
|
|
6
|
+
* end — the model either asks the user for something they also do not know, or gives up.
|
|
7
|
+
* These sentences turn that dead end into a HANDOFF by naming, in the description itself,
|
|
8
|
+
* where the missing identifier comes from.
|
|
9
|
+
*
|
|
10
|
+
* Point at a sibling tool whenever one can produce the id — it is faster and more
|
|
11
|
+
* predictable than an agent. Point at `askBrowserstackAI` only when NO tool here can.
|
|
12
|
+
*
|
|
13
|
+
* The one that matters most: 15 of the 17 Test Management tools require a project
|
|
14
|
+
* identifier and NONE of them accepts its absence, yet no tool in this server lists
|
|
15
|
+
* projects. "List my projects" is the first step of nearly every Test Management journey
|
|
16
|
+
* and it was unserved, which is exactly why that request did not reach any tool unless a
|
|
17
|
+
* user named one explicitly.
|
|
18
|
+
*
|
|
19
|
+
* Keep these as shared constants, not per-tool prose: the wording is a routing signal, and
|
|
20
|
+
* twenty hand-written variants drift into twenty different signals.
|
|
21
|
+
*/
|
|
22
|
+
/** No tool lists projects, so this genuinely has to go to the agent. */
|
|
23
|
+
export declare const NEEDS_PROJECT_ID: string;
|
|
24
|
+
/** A sibling tool can produce the id — prefer it over the agent. */
|
|
25
|
+
export declare function needsIdFrom(idLabel: string, sourceTool: string): string;
|
|
26
|
+
/** A test plan id (TP-*) comes from listTestPlans. */
|
|
27
|
+
export declare const NEEDS_TEST_PLAN_ID: string;
|
|
28
|
+
/** A build id comes from either build-lookup tool. */
|
|
29
|
+
export declare const NEEDS_BUILD_ID: string;
|
|
30
|
+
/** Session ids are not listable by any tool here. */
|
|
31
|
+
export declare const NEEDS_SESSION_ID: string;
|
|
32
|
+
/** A completed scan's ids come from startAccessibilityScan, or from the agent. */
|
|
33
|
+
export declare const NEEDS_A11Y_SCAN_ID: string;
|
|
34
|
+
/** Auth-config ids are not listable by any tool here. */
|
|
35
|
+
export declare const NEEDS_A11Y_CONFIG_ID: string;
|
|
36
|
+
/** Test ids come from listTestIds, which itself needs a build id. */
|
|
37
|
+
export declare const NEEDS_TEST_IDS: string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Precondition sentences appended to a tool's description.
|
|
3
|
+
*
|
|
4
|
+
* WHY THESE EXIST. Nothing routes an MCP call: the client's model picks a tool from the
|
|
5
|
+
* descriptions alone. A tool that needs an identifier the caller does not have is a dead
|
|
6
|
+
* end — the model either asks the user for something they also do not know, or gives up.
|
|
7
|
+
* These sentences turn that dead end into a HANDOFF by naming, in the description itself,
|
|
8
|
+
* where the missing identifier comes from.
|
|
9
|
+
*
|
|
10
|
+
* Point at a sibling tool whenever one can produce the id — it is faster and more
|
|
11
|
+
* predictable than an agent. Point at `askBrowserstackAI` only when NO tool here can.
|
|
12
|
+
*
|
|
13
|
+
* The one that matters most: 15 of the 17 Test Management tools require a project
|
|
14
|
+
* identifier and NONE of them accepts its absence, yet no tool in this server lists
|
|
15
|
+
* projects. "List my projects" is the first step of nearly every Test Management journey
|
|
16
|
+
* and it was unserved, which is exactly why that request did not reach any tool unless a
|
|
17
|
+
* user named one explicitly.
|
|
18
|
+
*
|
|
19
|
+
* Keep these as shared constants, not per-tool prose: the wording is a routing signal, and
|
|
20
|
+
* twenty hand-written variants drift into twenty different signals.
|
|
21
|
+
*/
|
|
22
|
+
/** No tool lists projects, so this genuinely has to go to the agent. */
|
|
23
|
+
export const NEEDS_PROJECT_ID = " Requires a project identifier (PR-*). No tool here lists projects, so if you do not " +
|
|
24
|
+
'have one, call askBrowserstackAI with product "tm" and ask which projects exist, then ' +
|
|
25
|
+
"retry this tool with the identifier it returns.";
|
|
26
|
+
/** A sibling tool can produce the id — prefer it over the agent. */
|
|
27
|
+
export function needsIdFrom(idLabel, sourceTool) {
|
|
28
|
+
return ` Requires ${idLabel}. Call ${sourceTool} first if you do not have it.`;
|
|
29
|
+
}
|
|
30
|
+
/** A test plan id (TP-*) comes from listTestPlans. */
|
|
31
|
+
export const NEEDS_TEST_PLAN_ID = needsIdFrom("a test plan identifier (TP-*)", "listTestPlans");
|
|
32
|
+
/** A build id comes from either build-lookup tool. */
|
|
33
|
+
export const NEEDS_BUILD_ID = needsIdFrom("a BrowserStack build id", "getBuildId or listBuildId");
|
|
34
|
+
/** Session ids are not listable by any tool here. */
|
|
35
|
+
export const NEEDS_SESSION_ID = " Requires a session id, which no tool here lists. If you only know the build, call " +
|
|
36
|
+
"getBuildId or listBuildId; if you have neither, call askBrowserstackAI with product " +
|
|
37
|
+
'"tra" and describe the run you mean.';
|
|
38
|
+
/** A completed scan's ids come from startAccessibilityScan, or from the agent. */
|
|
39
|
+
export const NEEDS_A11Y_SCAN_ID = " Requires the ids of a completed scan. They are returned by startAccessibilityScan; " +
|
|
40
|
+
'for a scan run earlier, call askBrowserstackAI with product "a11y" to locate it, since ' +
|
|
41
|
+
"no tool here lists past scans.";
|
|
42
|
+
/** Auth-config ids are not listable by any tool here. */
|
|
43
|
+
export const NEEDS_A11Y_CONFIG_ID = " Requires the numeric id returned by createAccessibilityAuthConfig. No tool here lists " +
|
|
44
|
+
"existing configurations, so if you do not have the id, call askBrowserstackAI with " +
|
|
45
|
+
'product "a11y".';
|
|
46
|
+
/** Test ids come from listTestIds, which itself needs a build id. */
|
|
47
|
+
export const NEEDS_TEST_IDS = needsIdFrom("test ids", "listTestIds");
|