@browserstack/mcp-server 1.5.0-beta.1 → 1.5.0-beta.11

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.
@@ -3,7 +3,7 @@
3
3
  "version": "1.0",
4
4
  "build_id": "43eba70_2026-09-02T14:26:51Z",
5
5
  "loadtesting": {
6
- "summary": "Load and performance testing: run k6, JMeter, Gatling and Locust load tests at scale. List and inspect projects and load tests; create, update, start, stop and monitor runs; read run reports, AI insights and historical trends; compare runs; and check VU-hour quota and cost estimates. Test definitions, runs and their results live here. Account plan and billing do not — only VU-hour entitlement is exposed, via quota.",
6
+ "summary": "Load and performance testing: run k6, JMeter, Gatling and Locust load tests at scale. List and inspect projects and load tests; create, update, start, stop and monitor runs; read run reports, AI insights and historical trends; compare runs; and check VU-hour quota and cost estimates. Test definitions, runs and their results live here. Account plan and billing do not — only VU-hour entitlement is exposed, via quota. There is no capability to delete a load test or schedule recurring runs — for those, point the user to the web dashboard. Each capability returns its full result in one call; reuse a result within a task rather than re-fetching the same data.",
7
7
  "base_url": "https://load-api.browserstack.com",
8
8
  "auth": {
9
9
  "type": "http",
@@ -242,7 +242,8 @@
242
242
  "intent": "Show how a project's load-test metrics trend across recent runs — use this for 'is performance getting better or worse across this project?'",
243
243
  "guidance": [
244
244
  "metrics accepts dotted names or @ aliases; @vitals / @all expand to metric sets.",
245
- "windowRuns bounds how many recent runs are aggregated."
245
+ "windowRuns bounds how many recent runs are aggregated.",
246
+ "Returns the whole windowed series across metrics in one call — request all needed metrics together; do not call once per metric or re-fetch the same window."
246
247
  ],
247
248
  "returns": [
248
249
  "metrics"
@@ -328,13 +329,20 @@
328
329
  "name": "hadSlaBreach",
329
330
  "type": "boolean",
330
331
  "description": "Filter to runs that did / did not breach SLA."
332
+ },
333
+ {
334
+ "name": "tag",
335
+ "type": "string",
336
+ "description": "Filter to runs carrying this tag (a run's own tags, or the tags it inherits from its test when it has none of its own)."
331
337
  }
332
338
  ],
333
339
  "intent": "List the execution history across every load test in a project — newest first, paginated. Use for 'what ran last week in this project?' or to find runs across tests to compare.",
334
340
  "guidance": [
335
341
  "Returns run metadata only, not metrics — use getLoadTestRunReport for a run's KPIs.",
342
+ "Each run carries a tags array — its own run-level tags if set (via updateLoadTest with runId), otherwise the tags inherited from its test. Filter with the tag query param.",
336
343
  "Page with cursor + limit; nextCursor is opaque.",
337
- "For a single test's history use /loadTests/{testId}/runs; for currently-live runs use /loadTests/runs/active."
344
+ "For a single test's history use /loadTests/{testId}/runs; for currently-live runs use /loadTests/runs/active.",
345
+ "One call returns the page of run history — reuse it for follow-ups and page with cursor only when more rows are needed; do not re-list the same window."
338
346
  ],
339
347
  "returns": [
340
348
  "runs",
@@ -386,12 +394,18 @@
386
394
  "name": "userId",
387
395
  "type": "integer",
388
396
  "description": "Restrict to runs started by a user."
397
+ },
398
+ {
399
+ "name": "tag",
400
+ "type": "string",
401
+ "description": "Filter to runs carrying this tag (a run's own tags, or the tags it inherits from its test when it has none of its own)."
389
402
  }
390
403
  ],
391
404
  "intent": "List load-test runs currently executing — use this for 'what's running right now?' or to find a runId to stop or monitor.",
392
405
  "guidance": [
393
406
  "Returns non-terminal runs across the account.",
394
407
  "runId here is the UUID needed by getLoadTestRunStatus and stopLoadTestRun.",
408
+ "Each run carries a tags array — its own run-level tags if set, otherwise the tags inherited from its test. Filter with the tag query param.",
395
409
  "vuHoursBurnedSoFar reflects consumption at the moment of the call."
396
410
  ],
397
411
  "returns": [
@@ -437,7 +451,8 @@
437
451
  "guidance": [
438
452
  "jobId is the run UUID from startLoadTestRun or listLoadTestRuns.",
439
453
  "Respect pollAfterSeconds between polls instead of tight-looping.",
440
- "slaBreachFlags surfaces threshold breaches as they trip."
454
+ "slaBreachFlags surfaces threshold breaches as they trip.",
455
+ "For 'is it done?' / 'how much time is left?', this status call is sufficient — do not fetch the run report to answer a status question."
441
456
  ],
442
457
  "returns": [
443
458
  "status",
@@ -578,14 +593,7 @@
578
593
  {
579
594
  "name": "errorCategory",
580
595
  "type": "string",
581
- "values": [
582
- "5xx",
583
- "4xx",
584
- "timeout",
585
- "connection",
586
- "assertion"
587
- ],
588
- "description": "Comma-separated error categories to include."
596
+ "description": "Comma-separated error categories — any combination of: 5xx, 4xx, timeout, connection, assertion (e.g. \"5xx,4xx\")."
589
597
  },
590
598
  {
591
599
  "name": "metrics",
@@ -613,7 +621,9 @@
613
621
  "Only valid for a terminal run.",
614
622
  "Start with detail=aggregate; escalate to per-txn or full only when you need transaction- or network-level detail — full is large.",
615
623
  "groupBy and errorCategory narrow the payload; byteCap hard-caps the response (max 256 KB).",
616
- "metrics accepts dotted names or @ aliases; see getLoadTestMetricsManifest for what applies to this test type."
624
+ "metrics accepts dotted names or @ aliases; see getLoadTestMetricsManifest for what applies to this test type.",
625
+ "Answer a scoped question with the narrowest slice instead of the whole report: one metric → metrics=; error breakdown → errorCategory= (or slaOnly=true); a time window → sinceIso/untilIso; slowest transaction → detail=per-txn with groupBy=transaction and topN.",
626
+ "One call with the right params returns everything for that question — do not re-fetch the same run with the same params. Fetch the full report (view=full / detail=full) only when the user explicitly asks for the raw or complete report."
617
627
  ],
618
628
  "returns": [
619
629
  "runId",
@@ -748,7 +758,10 @@
748
758
  "guidance": [
749
759
  "Read-only despite being a POST — nothing is started.",
750
760
  "fitsInQuota / remainingAfterEstimate compare the estimate against current quota.",
751
- "For the same check at start time, call startLoadTestRun with dryRun:true."
761
+ "For the same check at start time, call startLoadTestRun with dryRun:true.",
762
+ "Always use this for a cost or VU-hour estimate of a hypothetical run — it models ramp-up. Do not compute VU-hours by hand from VUs × duration.",
763
+ "A protocol (plu) run is billed at a full load-generator pod's capacity (e.g. 1000 VUs for k6), not the VUs it actually uses, and carries a minimum billing floor (5 minutes) — so a small or short plu run can estimate far higher than VUs × duration would suggest. That is expected; report the returned estimatedVuHours as-is rather than second-guessing it as an error.",
764
+ "The estimate is for the test's OWN type: a browser (blu) run costs about 10x a protocol (plu) run at the same VUs and duration (browser VUs carry a 10x weight). So the number depends heavily on whether the test is plu, blu or hybrid — always state which type the estimate is for. When the user asks about a hypothetical run without fixing the type, do not silently inherit the type of whatever test you priced against: say the type explicitly, and if it is genuinely open, give both the plu and blu figures (they differ ~10x) or ask which they mean."
752
765
  ],
753
766
  "returns": [
754
767
  "estimatedVuHours",
@@ -830,7 +843,8 @@
830
843
  "intent": "Compare two completed runs and surface the deltas — use this for 'did this run regress vs the baseline?'",
831
844
  "guidance": [
832
845
  "baselineRunId and candidateRunId are run UUIDs and must differ; both runs must be terminal.",
833
- "regressedOnly + pctChangeMin filter to material regressions; dimensions accepts kpi, transaction, sla."
846
+ "regressedOnly + pctChangeMin filter to material regressions; dimensions accepts kpi, transaction, sla.",
847
+ "Use this to compare two runs — it returns per-KPI and per-transaction deltas directly. Do not fetch both run reports and diff them yourself."
834
848
  ],
835
849
  "returns": [
836
850
  "kpiDeltas",
@@ -867,6 +881,7 @@
867
881
  "name": "testType",
868
882
  "type": "string",
869
883
  "required": true,
884
+ "description": "plu = protocol/API load; blu = real-browser load; hybrid = BOTH in one test (one PLU leg + one BLU leg, supplied via children). These tokens are INTERNAL wire values — send them here but never show them to the user; the user-facing labels are 'API / Protocol' (plu), 'Browser' (blu) and 'Hybrid' (hybrid). All three are valid, user-selectable options — hybrid is not a rare/advanced variant, offer it alongside the other two.",
870
885
  "values": [
871
886
  "plu",
872
887
  "blu",
@@ -877,11 +892,17 @@
877
892
  "name": "framework",
878
893
  "type": "string",
879
894
  "required": true,
895
+ "description": "PLU (protocol) frameworks: k6, jmeter, gatling, locust. BLU (browser) frameworks: playwright, selenium, webdriverio, nightwatch, lcncnightwatch. Must match testType — a PLU framework for testType plu, a BLU framework for testType blu (the backend rejects a mismatched pair).",
880
896
  "values": [
881
897
  "k6",
882
898
  "jmeter",
883
899
  "gatling",
884
- "locust"
900
+ "locust",
901
+ "playwright",
902
+ "selenium",
903
+ "webdriverio",
904
+ "nightwatch",
905
+ "lcncnightwatch"
885
906
  ]
886
907
  },
887
908
  {
@@ -897,12 +918,12 @@
897
918
  {
898
919
  "name": "config",
899
920
  "type": "object",
900
- "description": "Test configuration incl. scriptRef {source: s3|s3_upload|existing_zip_id, value|identifier}, vuRamp, durationSec, loadGeneratorLocations, slaThresholds, envVarKeys, tags. To supply a script from a local file or URL, use the pendingScriptUpload flow, then source='s3'."
921
+ "description": "Test configuration incl. scriptRef {source: s3|s3_upload|existing_zip_id|sample, value|identifier}, loadProfile (constant|ramping|iterations|throughput), vus, vuRamp, durationSec, iterations, targetRps, maxVus, loadGeneratorLocations, slaThresholds, envVarKeys, tags. See the load-profile guidance for which fields each loadProfile needs (iterations + throughput are PLU-only). To supply a script from a local file or URL, use the pendingScriptUpload flow, then source='s3'. To create a test from the platform's built-in sample (no upload), use scriptRef:{source:'sample'} — for Selenium also pass scriptRef.subType (testng|junit|vanillajava|python|pytest|jest|serenity-cucumber)."
901
922
  },
902
923
  {
903
924
  "name": "children",
904
925
  "type": "array",
905
- "description": "Child scenarios for hybrid tests."
926
+ "description": "Child scenarios for a hybrid test. A hybrid is exactly one PLU (protocol) leg + one BLU (browser) leg — each leg carries its own framework + scriptRef (a sample or an uploaded script). Send the BLU leg as the top-level testType='blu'/framework/config and put the PLU leg in children[] (one entry, testType='plu' with its framework + config.scriptRef). The backend requires exactly one PLU and one BLU leg and rejects any other composition."
906
927
  },
907
928
  {
908
929
  "name": "idempotencyKey",
@@ -932,9 +953,17 @@
932
953
  ],
933
954
  "intent": "Create a new load test in a project — use this to define a test before running it. JSON body only (no multipart).",
934
955
  "guidance": [
956
+ "PRECONDITION — do NOT call this endpoint until THREE things are known: (1) testType (plu/blu/hybrid), (2) framework, (3) the script (a built-in sample or the user's own upload). These are MANDATORY and NOT defaultable — never infer or default them. If the user's request does not state one of the three, ASK the user for the missing ones and WAIT for their answer before creating. 'create a test' with no type/framework/script named means all three are missing → ask all three; do not silently pick k6/plu/sample. Only vus, duration, region and load profile are defaultable (see the DEFAULTS line) — the three above are not.",
957
+ "'plu' / 'blu' / 'hybrid' are INTERNAL wire values — send them in the request, but NEVER show them to the user. Do not print them in questions, option labels, confirmations, summaries, or prose (no 'Browser (BLU)', no '(plu+blu)'). User-facing labels are: plu → 'API / Protocol', blu → 'Browser', hybrid → 'Hybrid (both API and Browser)'. Frameworks (k6, jmeter, selenium, playwright, …) are real product names and ARE shown to the user.",
958
+ "When you ASK the user to pick testType or framework, present the FULL, exact option set — never drop, merge, or cross-contaminate options. testType: offer all THREE, using the user-facing labels above — 'API / Protocol', 'Browser', and 'Hybrid'; do not omit Hybrid. framework (ask AFTER testType is chosen, and show only that type's frameworks, each as its OWN separate option): for an API/Protocol test offer exactly k6, jmeter, gatling AND locust (all four — do not drop locust); for a Browser test offer exactly playwright, selenium, webdriverio AND nightwatch (all four — never list the API/Protocol frameworks under a Browser test, and never merge selenium and playwright into one option). For a Hybrid test, collect an API/Protocol leg (its framework + script) AND a Browser leg (its framework + script) and assemble them per the children field — Hybrid needs both legs, so it takes more than the three questions a single-type test does.",
935
959
  "Provide exactly one of projectId or projectName; projectName creates the project if absent.",
936
960
  "Script upload is two-phase: send pendingScriptUpload to get a presigned uploadUrl + s3Key, PUT the file, then call create again with the scriptRef source and s3Key returned in the response's nextStep.",
937
- "Pass idempotencyKey so a retried create does not duplicate the test."
961
+ "To spin up a test from a built-in sample with NO file handling (the dashboard's 'use sample script'), pass scriptRef:{source:'sample'} — the platform's bundled sample for the given framework is used. For Selenium, also pass scriptRef.subType (testng|junit|vanillajava|python|pytest|jest|serenity-cucumber) to pick the binding. testType and framework are still needed; the load profile defaults to constant 1 VU / 30s (see below).",
962
+ "Pass idempotencyKey so a retried create does not duplicate the test.",
963
+ "Only THREE things must be known before creating, and each is taken from the user's request when they've stated it — ask ONLY for the ones still missing, and ask about nothing else: (1) testType — plu (protocol / API load), blu (real-browser load) or hybrid (both); (2) framework — k6 / jmeter / gatling / locust for plu, playwright / selenium / webdriverio / nightwatch for blu; (3) the script — a built-in sample (scriptRef:{source:'sample'}; for Selenium also pass scriptRef.subType) OR the user's own script via the pendingScriptUpload flow. Do not guess a framework/testType, but do not re-ask for one the user already gave.",
964
+ "There is no clone capability. To duplicate a test, getLoadTest the source and copy its full config into this create — vuRamp/vus, durationSec, loadGeneratorLocations and slaThresholds included; nothing is inherited from the source, so anything you omit is dropped.",
965
+ "DEFAULTS apply ONLY after the three mandatory fields (testType, framework, script) are known — they never substitute for a missing one of those. Everything BEYOND those three — do not ask about it; apply the default unless the user explicitly specifies otherwise: loadProfile='constant', config.vus=1, config.durationSec=30, region us-east-1 (omit loadGeneratorLocations so the backend defaults it), and NO advanced features (do not enable log capture, response capture, artifacts, thresholds, etc.). Send config.vus=1 + config.durationSec=30 with no vuRamp for the default constant profile.",
966
+ "Only when the user explicitly asks for a different load shape, set config.loadProfile: 'ramping' (config.vuRamp: array of {vus, durationSec} stages; ramp up/down is inferred from adjacent VU deltas), 'iterations' (PLU only — config.iterations = fixed run count, plus config.vus), or 'throughput' (PLU and only JMeter/Gatling/locust/k6 — config.targetRps + config.maxVus + config.durationSec). A stage's own 'type' is NOT honored — every stage persists as a hold."
938
967
  ],
939
968
  "returns": [
940
969
  "testId",
@@ -1014,7 +1043,8 @@
1014
1043
  "guidance": [
1015
1044
  "testId is the numeric test id, not a run id.",
1016
1045
  "dryRun:true returns the VU-hour estimate and quota fit without starting anything.",
1017
- "On success returns runId (UUID) + dashboardLink; poll getLoadTestRunStatus with the runId."
1046
+ "On success returns runId (UUID) + dashboardLink; poll getLoadTestRunStatus with the runId.",
1047
+ "A run without dryRun generates real load and consumes VU-hours. Unless the user has already asked to run it now, dryRun:true first, show the estimate/quota fit and the parameters that will be used (VUs, duration, target), and start the real run only after the user confirms — do not treat your own confirmation as the user's."
1018
1048
  ],
1019
1049
  "returns": [
1020
1050
  "runId",
@@ -1098,12 +1128,19 @@
1098
1128
  "name": "hadSlaBreach",
1099
1129
  "type": "boolean",
1100
1130
  "description": "Only runs that breached an SLA."
1131
+ },
1132
+ {
1133
+ "name": "tag",
1134
+ "type": "string",
1135
+ "description": "Filter to runs carrying this tag (a run's own tags, or the tags it inherits from the test when it has none of its own)."
1101
1136
  }
1102
1137
  ],
1103
1138
  "intent": "List the execution history of a test — use this to find past runs of a specific test or to get a runId.",
1104
1139
  "guidance": [
1105
1140
  "testId is numeric; runId values returned are UUIDs.",
1106
- "Filter with status / verdict / date range; page with cursor + limit."
1141
+ "Each run carries a tags array — its own run-level tags if set (via updateLoadTest with runId), otherwise the tags inherited from the test. Filter with the tag query param.",
1142
+ "Filter with status / verdict / date range; page with cursor + limit.",
1143
+ "One call returns this test's run history — reuse it and page with cursor when needed; do not re-list the same window."
1107
1144
  ],
1108
1145
  "returns": [
1109
1146
  "runs",
@@ -1185,7 +1222,8 @@
1185
1222
  "intent": "Show how one test's metrics trend across its recent runs — use this for 'is this test getting slower over time?'",
1186
1223
  "guidance": [
1187
1224
  "metrics accepts dotted names or @ aliases; @vitals / @all expand to metric sets.",
1188
- "windowRuns bounds how many recent runs are aggregated."
1225
+ "windowRuns bounds how many recent runs are aggregated.",
1226
+ "Returns the whole windowed series across metrics in one call — request all needed metrics together; do not call once per metric or re-fetch the same window."
1189
1227
  ],
1190
1228
  "returns": [
1191
1229
  "metrics"
@@ -1295,13 +1333,22 @@
1295
1333
  "type": "string"
1296
1334
  }
1297
1335
  ]
1336
+ },
1337
+ {
1338
+ "name": "runId",
1339
+ "type": "string",
1340
+ "description": "Tag a specific RUN instead of the test definition. When set, config.tags is applied to that run's own tags (the saved test is NOT changed); only config.tags may accompany runId. Omit it to edit the test."
1298
1341
  }
1299
1342
  ],
1300
- "intent": "Update an existing load test's name or configuration — use this to change tags, SLA thresholds, script or settings.",
1343
+ "intent": "Update an existing load test's name or configuration — use this to change tags, SLA thresholds, script or settings; also tags a specific run when runId is set.",
1301
1344
  "guidance": [
1302
1345
  "Partial update: send only the fields to change.",
1303
1346
  "Pass ifVersion for optimistic concurrency; a stale value returns 409 VERSION_CONFLICT.",
1304
- "Script replacement uses the same two-phase pendingScriptUpload flow as create."
1347
+ "Script replacement uses the same two-phase pendingScriptUpload flow as create.",
1348
+ "config is a partial update, but each field it carries REPLACES that field wholesale — it does not merge. tags overwrites the entire tag set; it does not append. To add a tag to a test (or the same tag across several tests), getLoadTest each one first and send the union under config.tags.",
1349
+ "To change the load profile, send config.loadProfile plus that profile's fields (see createLoadTest's load-profile guidance for the four shapes). Switching profiles clears the previous profile's fields — e.g. ramping→throughput empties the stages and drops iterations. iterations and throughput are PLU-only.",
1350
+ "To tag a specific RUN rather than the test, pass runId (a run UUID from listLoadTestRuns) together with config.tags — the tags apply to that one run and the saved test is untouched. A run inherits the test's tags until you set its own; setting run tags overrides (they also replace wholesale, so send the union to add). Omit runId to tag the test itself.",
1351
+ "Tags live on the load test, not on its runs — there is no per-run tagging, so do not touch runs when asked to tag a test. To tag every test in a project, list them with listLoadTests and page through with cursor until hasMore is false, then updateLoadTest each one — do not stop after the first page or a subset."
1305
1352
  ],
1306
1353
  "returns": [
1307
1354
  "testId",
@@ -1344,13 +1391,7 @@
1344
1391
  {
1345
1392
  "name": "include",
1346
1393
  "type": "string",
1347
- "values": [
1348
- "config",
1349
- "thresholds",
1350
- "tags",
1351
- "children"
1352
- ],
1353
- "description": "Comma-separated sub-resources to expand."
1394
+ "description": "Comma-separated sub-resources to expand — any combination of: config, thresholds, tags, children (e.g. \"config,thresholds\"). Ask for everything you need in ONE call (include=config,thresholds,tags) rather than one request per sub-resource."
1354
1395
  },
1355
1396
  {
1356
1397
  "name": "fields",
@@ -1361,7 +1402,8 @@
1361
1402
  "intent": "Get the full configuration of a single load test — use this to inspect a test's settings, script reference, SLA thresholds and children.",
1362
1403
  "guidance": [
1363
1404
  "testId is numeric (from listLoadTests).",
1364
- "Use include to expand config / thresholds / tags / children."
1405
+ "Use include to expand config / thresholds / tags / children.",
1406
+ "A single call returns the complete configuration — VU/ramp profile, duration, load-generator regions and SLA thresholds (expand them with include=config,thresholds). Do not call again for the same testId within a task; reuse the result."
1365
1407
  ],
1366
1408
  "returns": [
1367
1409
  "testId",