@browserstack/mcp-server 1.5.0-beta.8 → 1.5.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 (95) hide show
  1. package/README.md +48 -32
  2. package/dist/config.d.ts +4 -1
  3. package/dist/config.js +23 -2
  4. package/dist/index.d.ts +2 -1
  5. package/dist/index.js +7 -3
  6. package/dist/lib/constants.d.ts +3 -0
  7. package/dist/lib/constants.js +3 -0
  8. package/dist/lib/instrumentation.d.ts +14 -2
  9. package/dist/lib/instrumentation.js +104 -29
  10. package/dist/lib/node-version-notice.d.ts +1 -0
  11. package/dist/lib/node-version-notice.js +9 -0
  12. package/dist/lib/tool-latency.d.ts +4 -0
  13. package/dist/lib/tool-latency.js +16 -0
  14. package/dist/lib/untrusted-content.d.ts +15 -0
  15. package/dist/lib/untrusted-content.js +24 -0
  16. package/dist/lib/upload-validator.d.ts +3 -2
  17. package/dist/lib/upload-validator.js +18 -15
  18. package/dist/lib/utils.js +10 -3
  19. package/dist/lib/version-resolver.d.ts +0 -5
  20. package/dist/lib/version-resolver.js +8 -2
  21. package/dist/logger.js +1 -10
  22. package/dist/server-factory.js +10 -6
  23. package/dist/tools/accessibility.js +9 -5
  24. package/dist/tools/accessiblity-utils/accessibility-rag.js +3 -1
  25. package/dist/tools/appautomate-utils/native-execution/constants.js +4 -2
  26. package/dist/tools/appautomate.js +3 -1
  27. package/dist/tools/applive.js +1 -1
  28. package/dist/tools/ask-browserstack/central-oauth.d.ts +120 -0
  29. package/dist/tools/ask-browserstack/central-oauth.js +277 -0
  30. package/dist/tools/ask-browserstack/config.d.ts +102 -0
  31. package/dist/tools/ask-browserstack/config.js +140 -0
  32. package/dist/tools/ask-browserstack/egress.d.ts +34 -0
  33. package/dist/tools/ask-browserstack/egress.js +31 -0
  34. package/dist/tools/ask-browserstack/register.d.ts +61 -0
  35. package/dist/tools/ask-browserstack/register.js +416 -0
  36. package/dist/tools/ask-browserstack/relay.d.ts +201 -0
  37. package/dist/tools/ask-browserstack/relay.js +577 -0
  38. package/dist/tools/ask-browserstack/stream.d.ts +116 -0
  39. package/dist/tools/ask-browserstack/stream.js +236 -0
  40. package/dist/tools/ask-browserstack/types.d.ts +196 -0
  41. package/dist/tools/ask-browserstack/types.js +14 -0
  42. package/dist/tools/automate-utils/list-session-ids.d.ts +28 -0
  43. package/dist/tools/automate-utils/list-session-ids.js +87 -0
  44. package/dist/tools/automate-utils/resolve-hashed-build-id.d.ts +30 -0
  45. package/dist/tools/automate-utils/resolve-hashed-build-id.js +124 -0
  46. package/dist/tools/automate.d.ts +7 -0
  47. package/dist/tools/automate.js +104 -1
  48. package/dist/tools/bstack-sdk.js +2 -2
  49. package/dist/tools/build-insights.js +41 -2
  50. package/dist/tools/failurelogs-utils/app-automate.js +4 -3
  51. package/dist/tools/failurelogs-utils/automate.js +5 -4
  52. package/dist/tools/failurelogs-utils/resolve-app-build-id.d.ts +2 -0
  53. package/dist/tools/failurelogs-utils/resolve-app-build-id.js +5 -0
  54. package/dist/tools/failurelogs-utils/video.d.ts +3 -0
  55. package/dist/tools/failurelogs-utils/video.js +25 -0
  56. package/dist/tools/get-failure-logs.js +30 -11
  57. package/dist/tools/observability.js +3 -1
  58. package/dist/tools/percy-sdk.js +9 -9
  59. package/dist/tools/rca-agent-utils/format-rca.js +5 -4
  60. package/dist/tools/rca-agent-utils/get-failed-test-id.js +12 -0
  61. package/dist/tools/rca-agent-utils/types.d.ts +1 -0
  62. package/dist/tools/rca-agent.js +5 -2
  63. package/dist/tools/review-agent.js +2 -1
  64. package/dist/tools/sdk-utils/common/constants.d.ts +1 -1
  65. package/dist/tools/sdk-utils/common/constants.js +2 -1
  66. package/dist/tools/selfheal.js +6 -3
  67. package/dist/tools/testmanagement-utils/TCG-utils/api.js +26 -7
  68. package/dist/tools/testmanagement-utils/TCG-utils/config.d.ts +2 -0
  69. package/dist/tools/testmanagement-utils/TCG-utils/config.js +5 -0
  70. package/dist/tools/testmanagement-utils/testcase-from-file.js +2 -1
  71. package/dist/tools/testmanagement-utils/upload-file.js +16 -2
  72. package/dist/tools/testmanagement.js +39 -17
  73. package/dist/tools/tool-handoff.d.ts +66 -0
  74. package/dist/tools/tool-handoff.js +78 -0
  75. package/package.json +4 -5
  76. package/capability/loadtesting.capability-index.json +0 -1790
  77. package/capability/tm.capability-index.json +0 -19966
  78. package/dist/tools/capability-registry/bind.d.ts +0 -29
  79. package/dist/tools/capability-registry/bind.js +0 -134
  80. package/dist/tools/capability-registry/config.d.ts +0 -62
  81. package/dist/tools/capability-registry/config.js +0 -218
  82. package/dist/tools/capability-registry/discovery.d.ts +0 -44
  83. package/dist/tools/capability-registry/discovery.js +0 -99
  84. package/dist/tools/capability-registry/egress.d.ts +0 -44
  85. package/dist/tools/capability-registry/egress.js +0 -128
  86. package/dist/tools/capability-registry/index-loader.d.ts +0 -133
  87. package/dist/tools/capability-registry/index-loader.js +0 -369
  88. package/dist/tools/capability-registry/register.d.ts +0 -34
  89. package/dist/tools/capability-registry/register.js +0 -373
  90. package/dist/tools/capability-registry/resolve.d.ts +0 -38
  91. package/dist/tools/capability-registry/resolve.js +0 -45
  92. package/dist/tools/capability-registry/search.d.ts +0 -66
  93. package/dist/tools/capability-registry/search.js +0 -416
  94. package/dist/tools/capability-registry/types.d.ts +0 -219
  95. package/dist/tools/capability-registry/types.js +0 -33
@@ -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, PLAN_WRITES_VIA_AGENT, PROJECT_ID_ONLY_FOR_FOLDER, } 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.
@@ -263,11 +264,11 @@ export async function uploadProductRequirementFileTool(args, config, server) {
263
264
  */
264
265
  export async function createTestCasesFromFileTool(args, context, config, server) {
265
266
  try {
266
- trackMCP("createTestCasesFromFile", server.server.getClientVersion(), undefined);
267
+ trackMCP("createTestCasesFromFile", server.server.getClientVersion(), undefined, config);
267
268
  return await createTestCasesFromFile(args, context, config);
268
269
  }
269
270
  catch (err) {
270
- trackMCP("createTestCasesFromFile", server.server.getClientVersion(), err);
271
+ trackMCP("createTestCasesFromFile", server.server.getClientVersion(), err, config);
271
272
  return {
272
273
  content: [
273
274
  {
@@ -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.", CreateProjFoldSchema.shape, {
436
+ tools.createProjectOrFolder = server.tool("createProjectOrFolder", "Create a project and/or folder in BrowserStack Test Management." +
437
+ PROJECT_ID_ONLY_FOR_FOLDER, 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.", CreateTestCaseSchema.shape, {
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.", UpdateTestCaseSchema.shape, {
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.", ListTestCasesSchema.shape, {
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.", ListFoldersSchema.shape, {
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.)", ListTestRunsSchema.shape, {
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.", UpdateTestRunSchema.shape, {
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.", AddTestResultSchema.shape, {
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.", UploadFileSchema.shape, {
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,47 @@ 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.", CreateLCAStepsSchema.shape, {
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.", ListTestPlansSchema.shape, {
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 +
539
+ PLAN_WRITES_VIA_AGENT, ListTestPlansSchema.shape, {
527
540
  title: "List Test Plans",
528
541
  readOnlyHint: true,
529
542
  openWorldHint: false,
530
543
  destructiveHint: false,
531
544
  idempotentHint: true,
532
545
  }, (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.", GetTestPlanSchema.shape, {
546
+ 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." +
547
+ NEEDS_PROJECT_ID +
548
+ NEEDS_TEST_PLAN_ID +
549
+ PLAN_WRITES_VIA_AGENT, GetTestPlanSchema.shape, {
534
550
  title: "Get Test Plan",
535
551
  readOnlyHint: true,
536
552
  openWorldHint: false,
537
553
  destructiveHint: false,
538
554
  idempotentHint: true,
539
555
  }, (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.", ListSubTestPlansSchema.shape, {
556
+ tools.listSubTestPlans = server.tool("listSubTestPlans", "List sub-test-plans under a parent test plan (TP-*) in a Test Management project. Supports pagination." +
557
+ NEEDS_PROJECT_ID +
558
+ NEEDS_TEST_PLAN_ID +
559
+ PLAN_WRITES_VIA_AGENT, ListSubTestPlansSchema.shape, {
541
560
  title: "List Sub Test Plans",
542
561
  readOnlyHint: true,
543
562
  openWorldHint: false,
544
563
  destructiveHint: false,
545
564
  idempotentHint: true,
546
565
  }, (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.", GetSubTestPlanSchema.shape, {
566
+ tools.getSubTestPlan = server.tool("getSubTestPlan", "Fetch a sub-test-plan (STP-*) under a parent plan (TP-*). Returns metadata and linked test runs." +
567
+ NEEDS_PROJECT_ID +
568
+ NEEDS_TEST_PLAN_ID +
569
+ PLAN_WRITES_VIA_AGENT, GetSubTestPlanSchema.shape, {
548
570
  title: "Get Sub Test Plan",
549
571
  readOnlyHint: true,
550
572
  openWorldHint: false,
@@ -0,0 +1,66 @@
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
+ /**
27
+ * createProjectOrFolder must NOT carry NEEDS_PROJECT_ID: `project_identifier` is optional
28
+ * there, and the create-a-PROJECT half needs no id at all. With the generic constant the
29
+ * tool read "Requires a project identifier ... call askBrowserStackAI", which routed
30
+ * "create me a project" through the agent before letting the tool run.
31
+ */
32
+ export declare const PROJECT_ID_ONLY_FOR_FOLDER: string;
33
+ /** A test plan id (TP-*) comes from listTestPlans. */
34
+ export declare const NEEDS_TEST_PLAN_ID: string;
35
+ /**
36
+ * The ONLY capability handoff here: every other constant points at a tool that produces a
37
+ * missing *id*, but plan WRITES have no tool at all — the surface is `listTestPlans`,
38
+ * `getTestPlan`, `listSubTestPlans`, `getSubTestPlan` and nothing else. Atlas can do them
39
+ * (the tm harness allows POST /api/v1/projects/{id}/test-plans plus /update, /delete,
40
+ * /clone, /test-runs and /test-runs/unlink), so without this line the model reads the four
41
+ * read tools, finds no create, and reports the capability as absent — which is exactly what
42
+ * a QA eval concluded.
43
+ *
44
+ * Deliberately narrow: it names the specific operations that are missing rather than
45
+ * inviting the model to route plan work to the agent generally, because the tool
46
+ * descriptions otherwise say to prefer a specific tool whenever one fits.
47
+ *
48
+ * Caveat worth knowing: askBrowserStackAI pins every write to human approval, so this path
49
+ * only completes on a client that can show a prompt. On one that cannot, the intended write
50
+ * comes back in `needs_approval` instead of happening.
51
+ */
52
+ export declare const PLAN_WRITES_VIA_AGENT: string;
53
+ /** A build id comes from either build-lookup tool. */
54
+ export declare const NEEDS_BUILD_ID: string;
55
+ /**
56
+ * Session ids ARE listable now — PR #395 added `listSessions`, which merged into main while
57
+ * this branch was open. This used to send the model to askBrowserStackAI for want of a tool;
58
+ * pointing at the agent when a real tool exists is exactly what the header above forbids.
59
+ */
60
+ export declare const NEEDS_SESSION_ID: string;
61
+ /** A completed scan's ids come from startAccessibilityScan, or from the agent. */
62
+ export declare const NEEDS_A11Y_SCAN_ID: string;
63
+ /** Auth-config ids are not listable by any tool here. */
64
+ export declare const NEEDS_A11Y_CONFIG_ID: string;
65
+ /** Test ids come from listTestIds, which itself needs a build id. */
66
+ export declare const NEEDS_TEST_IDS: string;
@@ -0,0 +1,78 @@
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
+ /**
31
+ * createProjectOrFolder must NOT carry NEEDS_PROJECT_ID: `project_identifier` is optional
32
+ * there, and the create-a-PROJECT half needs no id at all. With the generic constant the
33
+ * tool read "Requires a project identifier ... call askBrowserStackAI", which routed
34
+ * "create me a project" through the agent before letting the tool run.
35
+ */
36
+ export const PROJECT_ID_ONLY_FOR_FOLDER = " Creating a project needs no identifier. Creating a folder inside an EXISTING project " +
37
+ "needs that project's identifier (PR-*); no tool here lists projects, so ask " +
38
+ 'askBrowserStackAI with product "tm" for it.';
39
+ /** A test plan id (TP-*) comes from listTestPlans. */
40
+ export const NEEDS_TEST_PLAN_ID = needsIdFrom("a test plan identifier (TP-*)", "listTestPlans");
41
+ /**
42
+ * The ONLY capability handoff here: every other constant points at a tool that produces a
43
+ * missing *id*, but plan WRITES have no tool at all — the surface is `listTestPlans`,
44
+ * `getTestPlan`, `listSubTestPlans`, `getSubTestPlan` and nothing else. Atlas can do them
45
+ * (the tm harness allows POST /api/v1/projects/{id}/test-plans plus /update, /delete,
46
+ * /clone, /test-runs and /test-runs/unlink), so without this line the model reads the four
47
+ * read tools, finds no create, and reports the capability as absent — which is exactly what
48
+ * a QA eval concluded.
49
+ *
50
+ * Deliberately narrow: it names the specific operations that are missing rather than
51
+ * inviting the model to route plan work to the agent generally, because the tool
52
+ * descriptions otherwise say to prefer a specific tool whenever one fits.
53
+ *
54
+ * Caveat worth knowing: askBrowserStackAI pins every write to human approval, so this path
55
+ * only completes on a client that can show a prompt. On one that cannot, the intended write
56
+ * comes back in `needs_approval` instead of happening.
57
+ */
58
+ export const PLAN_WRITES_VIA_AGENT = " Creating a test plan or sub-plan, and linking or unlinking test runs on one, are not " +
59
+ 'available as tools here: call askBrowserStackAI with product "tm" and describe what you ' +
60
+ "want. It asks you to confirm before changing anything.";
61
+ /** A build id comes from either build-lookup tool. */
62
+ export const NEEDS_BUILD_ID = needsIdFrom("a BrowserStack build id", "getBuildId or listBuildId");
63
+ /**
64
+ * Session ids ARE listable now — PR #395 added `listSessions`, which merged into main while
65
+ * this branch was open. This used to send the model to askBrowserStackAI for want of a tool;
66
+ * pointing at the agent when a real tool exists is exactly what the header above forbids.
67
+ */
68
+ export const NEEDS_SESSION_ID = " Requires a session id. listSessions lists them for a build; if you do not have the " +
69
+ "build either, getBuildId or listBuildId resolves one from a project and build name.";
70
+ /** A completed scan's ids come from startAccessibilityScan, or from the agent. */
71
+ export const NEEDS_A11Y_SCAN_ID = " Requires the ids of a completed scan, which are returned by startAccessibilityScan. " +
72
+ "No tool here lists past scans, so if you do not have the ids, start a new scan rather " +
73
+ "than guessing.";
74
+ /** Auth-config ids are not listable by any tool here. */
75
+ export const NEEDS_A11Y_CONFIG_ID = " Requires the numeric id returned by createAccessibilityAuthConfig. No tool here lists " +
76
+ "existing configurations, so if you do not have the id, create one rather than guessing.";
77
+ /** Test ids come from listTestIds, which itself needs a build id. */
78
+ export const NEEDS_TEST_IDS = needsIdFrom("test ids", "listTestIds");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserstack/mcp-server",
3
- "version": "1.5.0-beta.8",
3
+ "version": "1.5.0",
4
4
  "description": "BrowserStack's Official MCP Server",
5
5
  "mcpName": "io.github.browserstack/mcp-server",
6
6
  "main": "dist/index.js",
@@ -21,8 +21,7 @@
21
21
  "browserstack-mcp-server": "dist/index.js"
22
22
  },
23
23
  "files": [
24
- "dist",
25
- "capability"
24
+ "dist"
26
25
  ],
27
26
  "keywords": [
28
27
  "mcp",
@@ -31,7 +30,7 @@
31
30
  "automation"
32
31
  ],
33
32
  "engines": {
34
- "node": ">=18"
33
+ "node": ">=20.9.0"
35
34
  },
36
35
  "author": "",
37
36
  "license": "ISC",
@@ -45,7 +44,7 @@
45
44
  "form-data": "^4.0.5",
46
45
  "pino": "^10.3.1",
47
46
  "pino-pretty": "^13.1.3",
48
- "sharp": "^0.34.5",
47
+ "sharp": "^0.35.4",
49
48
  "uuid": "^13.0.0",
50
49
  "webdriverio": "^9.27.0",
51
50
  "zod": "^4.3.6"