@browserstack/mcp-server 2.2.0-beta.1 → 2.2.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.
- package/README.md +42 -432
- package/capability/loadtesting.capability-index.json +25 -2
- package/capability/tm.capability-index.json +1 -2
- package/dist/config.d.ts +27 -2
- package/dist/config.js +19 -6
- package/dist/lib/instrumentation.js +29 -3
- package/dist/lib/utils.js +8 -0
- package/dist/tools/accessiblity-utils/scanner.js +1 -1
- package/dist/tools/ask-browserstack/central-oauth.d.ts +46 -25
- package/dist/tools/ask-browserstack/central-oauth.js +177 -55
- package/dist/tools/ask-browserstack/config.d.ts +0 -14
- package/dist/tools/ask-browserstack/config.js +0 -16
- package/dist/tools/ask-browserstack/deferred.d.ts +74 -0
- package/dist/tools/ask-browserstack/deferred.js +242 -0
- package/dist/tools/ask-browserstack/register.d.ts +3 -2
- package/dist/tools/ask-browserstack/register.js +219 -72
- package/dist/tools/ask-browserstack/relay.js +11 -17
- package/dist/tools/ask-browserstack/stream.d.ts +27 -5
- package/dist/tools/ask-browserstack/stream.js +25 -14
- package/dist/tools/ask-browserstack/types.d.ts +54 -3
- package/dist/tools/ask-browserstack/types.js +11 -1
- package/dist/tools/automate-utils/fetch-screenshots.js +17 -15
- package/dist/tools/capability-registry/bind.js +7 -43
- package/dist/tools/capability-registry/discovery.js +1 -3
- package/dist/tools/capability-registry/egress.d.ts +5 -12
- package/dist/tools/capability-registry/egress.js +1 -24
- package/dist/tools/capability-registry/redact.js +7 -5
- package/dist/tools/capability-registry/register.js +41 -289
- package/dist/tools/capability-registry/resolve.d.ts +1 -1
- package/dist/tools/capability-registry/resolve.js +3 -24
- package/dist/tools/capability-registry/search.d.ts +1 -28
- package/dist/tools/capability-registry/search.js +4 -202
- package/dist/tools/capability-registry/types.d.ts +3 -42
- package/dist/tools/testmanagement.js +5 -5
- package/dist/tools/tool-handoff.d.ts +12 -15
- package/dist/tools/tool-handoff.js +18 -21
- package/package.json +3 -4
- package/capability/tra.capability-index.json +0 -52074
- package/dist/lib/central-oauth.d.ts +0 -133
- package/dist/lib/central-oauth.js +0 -246
- package/dist/tools/capability-registry/oauth.d.ts +0 -63
- package/dist/tools/capability-registry/oauth.js +0 -176
- package/dist/tools/capability-registry/routing-token.d.ts +0 -25
- package/dist/tools/capability-registry/routing-token.js +0 -87
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The routing step's verdict, signed so it can be handed back instead of remembered.
|
|
3
|
-
*
|
|
4
|
-
* The gate needs to know what the LAST routing call concluded — whether the request
|
|
5
|
-
* clashed, or settled, and on what. That is a fact about the conversation, and a tool call
|
|
6
|
-
* carries no conversation, so the server kept it: a set of unspent tokens and the listing's
|
|
7
|
-
* last verdict, both living for the life of the connection. Under stdio that is one process
|
|
8
|
-
* per client and harmless; it stops being harmless the moment one process serves several
|
|
9
|
-
* sessions, where a single shared `settledByListing` lets one client's listing satisfy
|
|
10
|
-
* another client's gate.
|
|
11
|
-
*
|
|
12
|
-
* So the verdict travels with the caller instead. It is signed with a per-process secret,
|
|
13
|
-
* which is what keeps it honest: the caller cannot mint one, cannot edit the product inside
|
|
14
|
-
* it, and cannot produce one at all without having made the routing call that issues it.
|
|
15
|
-
* Verification is recomputation — there is nothing to store, nothing to grow, and nothing
|
|
16
|
-
* to leak between sessions.
|
|
17
|
-
*
|
|
18
|
-
* WHAT THIS CANNOT DO, stated plainly: it proves a routing call happened and what it said.
|
|
19
|
-
* It cannot prove a human answered. Nothing a caller transmits can. A caller that reworded
|
|
20
|
-
* its request and ran discovery again on the new words holds a genuine token for a verdict
|
|
21
|
-
* it manufactured — closing THAT needs memory of the first question, which is the thing
|
|
22
|
-
* being removed here. `user_words`, checked against the index, remains the part that
|
|
23
|
-
* carries what the user actually said.
|
|
24
|
-
*/
|
|
25
|
-
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
26
|
-
/**
|
|
27
|
-
* Per process, and deliberately not persisted.
|
|
28
|
-
*
|
|
29
|
-
* A restart invalidates every outstanding token, which is the right behaviour: a new
|
|
30
|
-
* process is a new conversation, and a verdict from the last one says nothing about this
|
|
31
|
-
* one. It also means nothing has to be configured to run the server.
|
|
32
|
-
*/
|
|
33
|
-
const SECRET = randomBytes(32);
|
|
34
|
-
/** Tokens outlive a turn, not a sitting. Long enough to answer a question, not to bank. */
|
|
35
|
-
export const TOKEN_TTL_SECONDS = 60 * 30;
|
|
36
|
-
const b64 = (b) => b.toString("base64url");
|
|
37
|
-
function seal(payload) {
|
|
38
|
-
return createHmac("sha256", SECRET).update(payload).digest("base64url");
|
|
39
|
-
}
|
|
40
|
-
/** Sign a verdict into an opaque token the caller hands back. */
|
|
41
|
-
export function signRouting(verdict) {
|
|
42
|
-
const body = {
|
|
43
|
-
...verdict,
|
|
44
|
-
iat: verdict.iat ?? Math.floor(Date.now() / 1000),
|
|
45
|
-
};
|
|
46
|
-
const payload = b64(Buffer.from(JSON.stringify(body)));
|
|
47
|
-
return `${payload}.${seal(payload)}`;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Read a token back, or `undefined` if it was not issued here, was edited, or has expired.
|
|
51
|
-
*
|
|
52
|
-
* Every failure returns the same nothing on purpose: a caller learning WHY its token was
|
|
53
|
-
* rejected learns how to build a better one, and there is no legitimate caller that needs
|
|
54
|
-
* to know the difference.
|
|
55
|
-
*/
|
|
56
|
-
export function readRouting(token, now = Math.floor(Date.now() / 1000)) {
|
|
57
|
-
if (!token)
|
|
58
|
-
return undefined;
|
|
59
|
-
const cut = token.lastIndexOf(".");
|
|
60
|
-
if (cut <= 0)
|
|
61
|
-
return undefined;
|
|
62
|
-
const payload = token.slice(0, cut);
|
|
63
|
-
const signature = token.slice(cut + 1);
|
|
64
|
-
const expected = Buffer.from(seal(payload));
|
|
65
|
-
const given = Buffer.from(signature);
|
|
66
|
-
// Length has to match before timingSafeEqual will look at the bytes, and comparing
|
|
67
|
-
// lengths first leaks only the length, which the caller already knows.
|
|
68
|
-
if (expected.length !== given.length)
|
|
69
|
-
return undefined;
|
|
70
|
-
if (!timingSafeEqual(expected, given))
|
|
71
|
-
return undefined;
|
|
72
|
-
try {
|
|
73
|
-
const body = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
74
|
-
if (typeof body?.iat !== "number")
|
|
75
|
-
return undefined;
|
|
76
|
-
if (now - body.iat > TOKEN_TTL_SECONDS)
|
|
77
|
-
return undefined;
|
|
78
|
-
if (body.verdict !== "clash" &&
|
|
79
|
-
body.verdict !== "blank" &&
|
|
80
|
-
body.verdict !== "settled")
|
|
81
|
-
return undefined;
|
|
82
|
-
return body;
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
}
|