browser-devtools-mcp 0.0.1 → 0.0.3
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 +177 -50
- package/dist/browser.js +162 -22
- package/dist/browser.js.map +1 -1
- package/dist/config.js +46 -1
- package/dist/config.js.map +1 -1
- package/dist/context.js +72 -12
- package/dist/context.js.map +1 -1
- package/dist/index.js +77 -42
- package/dist/index.js.map +1 -1
- package/dist/otel/otel-controller.js +319 -0
- package/dist/otel/otel-controller.js.map +1 -0
- package/dist/otel/otel-initializer.bundle.js +2 -0
- package/dist/otel/otel-initializer.bundle.js.map +7 -0
- package/dist/otel/otel-proxy.js +407 -0
- package/dist/otel/otel-proxy.js.map +1 -0
- package/dist/server-info.js +48 -10
- package/dist/server-info.js.map +1 -1
- package/dist/server.js +47 -32
- package/dist/server.js.map +1 -1
- package/dist/tools/a11y/index.js +7 -0
- package/dist/tools/a11y/index.js.map +1 -0
- package/dist/tools/{content → a11y}/take-aria-snapshot.js +6 -1
- package/dist/tools/a11y/take-aria-snapshot.js.map +1 -0
- package/dist/tools/a11y/take-ax-tree-snapshot.js +850 -0
- package/dist/tools/a11y/take-ax-tree-snapshot.js.map +1 -0
- package/dist/tools/content/index.js +0 -2
- package/dist/tools/content/index.js.map +1 -1
- package/dist/tools/content/save-as-pdf.js +9 -36
- package/dist/tools/content/save-as-pdf.js.map +1 -1
- package/dist/tools/content/take-screenshot.js +14 -37
- package/dist/tools/content/take-screenshot.js.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/monitoring/get-trace-id.js +30 -0
- package/dist/tools/monitoring/get-trace-id.js.map +1 -0
- package/dist/tools/monitoring/index.js +10 -1
- package/dist/tools/monitoring/index.js.map +1 -1
- package/dist/tools/monitoring/new-trace-id.js +32 -0
- package/dist/tools/monitoring/new-trace-id.js.map +1 -0
- package/dist/tools/monitoring/set-trace-id.js +28 -0
- package/dist/tools/monitoring/set-trace-id.js.map +1 -0
- package/dist/tools/tool-executor.js +26 -4
- package/dist/tools/tool-executor.js.map +1 -1
- package/dist/utils.js +38 -0
- package/dist/utils.js.map +1 -1
- package/package.json +7 -2
- package/dist/tools/content/take-aria-snapshot.js.map +0 -1
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* -----------------------------------------------------------------------------
|
|
4
|
+
* WHY THIS OTEL PROXY EXISTS
|
|
5
|
+
* -----------------------------------------------------------------------------
|
|
6
|
+
*
|
|
7
|
+
* Problem:
|
|
8
|
+
* --------
|
|
9
|
+
* When OpenTelemetry Web SDK runs inside a real browser page, it exports traces
|
|
10
|
+
* via OTLP/HTTP using `fetch` or `XMLHttpRequest`.
|
|
11
|
+
*
|
|
12
|
+
* In Playwright-driven debugging sessions this causes multiple issues:
|
|
13
|
+
*
|
|
14
|
+
* 1) CORS restrictions
|
|
15
|
+
* -----------------
|
|
16
|
+
* Browsers enforce CORS. If the page origin (e.g. https://remote-site.com)
|
|
17
|
+
* tries to POST traces to a collector like:
|
|
18
|
+
*
|
|
19
|
+
* http://localhost:4318/v1/traces
|
|
20
|
+
*
|
|
21
|
+
* the request is blocked unless the collector explicitly enables
|
|
22
|
+
* Access-Control-Allow-Origin for that site.
|
|
23
|
+
*
|
|
24
|
+
* We often do NOT control the collector configuration (Jaeger, Tempo, etc),
|
|
25
|
+
* especially in local or remote debugging setups.
|
|
26
|
+
*
|
|
27
|
+
* 2) Remote pages + local tools
|
|
28
|
+
* ---------------------------
|
|
29
|
+
* A very common setup is:
|
|
30
|
+
* - Playwright + MCP server running locally
|
|
31
|
+
* - A remote production/staging website loaded in the browser
|
|
32
|
+
*
|
|
33
|
+
* That remote website has no way to directly talk to a local OTLP endpoint
|
|
34
|
+
* due to browser security rules.
|
|
35
|
+
*
|
|
36
|
+
* 3) Collector incompatibilities
|
|
37
|
+
* -----------------------------
|
|
38
|
+
* Different collectors behave differently:
|
|
39
|
+
* - Some support CORS, some don’t
|
|
40
|
+
* - Some only support OTLP/gRPC
|
|
41
|
+
* - Some reject preflight OPTIONS requests
|
|
42
|
+
*
|
|
43
|
+
* Solution:
|
|
44
|
+
* ---------
|
|
45
|
+
* We introduce a SAME-ORIGIN OTEL PROXY using Playwright's `context.route`.
|
|
46
|
+
*
|
|
47
|
+
* Instead of exporting directly to the real collector, the browser sends OTLP to:
|
|
48
|
+
*
|
|
49
|
+
* https://<page-origin>/__mcp_otel/v1/traces
|
|
50
|
+
*
|
|
51
|
+
* From the browser perspective this is SAME-ORIGIN → no CORS issues.
|
|
52
|
+
*
|
|
53
|
+
* Playwright intercepts that request *outside* the browser via `context.route`
|
|
54
|
+
* and forwards the payload to the real upstream collector.
|
|
55
|
+
*
|
|
56
|
+
* Why `context.route` (and not a local HTTP server)?
|
|
57
|
+
* --------------------------------------------------
|
|
58
|
+
* - Zero CORS by construction (browser thinks it's same-origin)
|
|
59
|
+
* - Works for ANY remote site origin
|
|
60
|
+
* - No port exposure / firewall issues
|
|
61
|
+
* - Lifecycle tied to BrowserContext (session-friendly)
|
|
62
|
+
*
|
|
63
|
+
* Path-based fan-out:
|
|
64
|
+
* -------------------
|
|
65
|
+
* Browser sends:
|
|
66
|
+
* /__mcp_otel/v1/traces
|
|
67
|
+
* /__mcp_otel/v1/metrics
|
|
68
|
+
* /__mcp_otel/v1/logs
|
|
69
|
+
*
|
|
70
|
+
* Proxy strips base path and forwards:
|
|
71
|
+
* <upstreamBase>/v1/traces
|
|
72
|
+
* <upstreamBase>/v1/metrics
|
|
73
|
+
* <upstreamBase>/v1/logs
|
|
74
|
+
*
|
|
75
|
+
* Performance considerations:
|
|
76
|
+
* ---------------------------
|
|
77
|
+
* - Browser is ACKed immediately (204/200)
|
|
78
|
+
* - Forwarding happens asynchronously in a bounded queue
|
|
79
|
+
* - Slow/failing collectors do NOT block the page
|
|
80
|
+
* -----------------------------------------------------------------------------
|
|
81
|
+
*/
|
|
82
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
83
|
+
if (k2 === undefined) k2 = k;
|
|
84
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
85
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
86
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
87
|
+
}
|
|
88
|
+
Object.defineProperty(o, k2, desc);
|
|
89
|
+
}) : (function(o, m, k, k2) {
|
|
90
|
+
if (k2 === undefined) k2 = k;
|
|
91
|
+
o[k2] = m[k];
|
|
92
|
+
}));
|
|
93
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
94
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
95
|
+
}) : function(o, v) {
|
|
96
|
+
o["default"] = v;
|
|
97
|
+
});
|
|
98
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
99
|
+
var ownKeys = function(o) {
|
|
100
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
101
|
+
var ar = [];
|
|
102
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
103
|
+
return ar;
|
|
104
|
+
};
|
|
105
|
+
return ownKeys(o);
|
|
106
|
+
};
|
|
107
|
+
return function (mod) {
|
|
108
|
+
if (mod && mod.__esModule) return mod;
|
|
109
|
+
var result = {};
|
|
110
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
111
|
+
__setModuleDefault(result, mod);
|
|
112
|
+
return result;
|
|
113
|
+
};
|
|
114
|
+
})();
|
|
115
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
116
|
+
exports.OTELProxy = void 0;
|
|
117
|
+
const logger = __importStar(require("../logger"));
|
|
118
|
+
function _normalizeBasePath(input) {
|
|
119
|
+
let p = input.trim();
|
|
120
|
+
if (!p.startsWith('/')) {
|
|
121
|
+
p = '/' + p;
|
|
122
|
+
}
|
|
123
|
+
if (!p.endsWith('/')) {
|
|
124
|
+
p = p + '/';
|
|
125
|
+
}
|
|
126
|
+
return p;
|
|
127
|
+
}
|
|
128
|
+
function _normalizeUpstreamBaseUrl(input) {
|
|
129
|
+
const u = input.trim();
|
|
130
|
+
if (!u) {
|
|
131
|
+
return u;
|
|
132
|
+
}
|
|
133
|
+
// Remove trailing slash to avoid double slashes when appending suffix
|
|
134
|
+
if (u.endsWith('/')) {
|
|
135
|
+
return u.slice(0, -1);
|
|
136
|
+
}
|
|
137
|
+
return u;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Extracts the pathname suffix after basePath.
|
|
141
|
+
*
|
|
142
|
+
* basePath is normalized to always end with '/', so for:
|
|
143
|
+
* basePath = '/__mcp_otel/'
|
|
144
|
+
* pathname = '/__mcp_otel/v1/traces'
|
|
145
|
+
*
|
|
146
|
+
* we return '/v1/traces'.
|
|
147
|
+
*/
|
|
148
|
+
function _computeSuffixPath(fullUrl, basePath) {
|
|
149
|
+
try {
|
|
150
|
+
const u = new URL(fullUrl);
|
|
151
|
+
const pathname = u.pathname;
|
|
152
|
+
if (!pathname.startsWith(basePath)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const raw = pathname.slice(basePath.length); // e.g. 'v1/traces'
|
|
156
|
+
if (!raw) {
|
|
157
|
+
// If someone POSTs directly to '/__mcp_otel/' without suffix,
|
|
158
|
+
// treat as invalid (we don't know where to fan-out).
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
return raw.startsWith('/') ? raw : '/' + raw;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function _appendSuffixToUpstream(upstreamBaseUrl, suffixPath, originalUrl) {
|
|
168
|
+
try {
|
|
169
|
+
const u = new URL(originalUrl);
|
|
170
|
+
const qs = u.search ?? '';
|
|
171
|
+
return upstreamBaseUrl + suffixPath + qs;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return upstreamBaseUrl + suffixPath;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
class OTELProxy {
|
|
178
|
+
config;
|
|
179
|
+
queue;
|
|
180
|
+
workers;
|
|
181
|
+
isRunning;
|
|
182
|
+
isInstalled;
|
|
183
|
+
metrics;
|
|
184
|
+
constructor(config) {
|
|
185
|
+
const maxQueueSize = config.maxQueueSize ?? 200;
|
|
186
|
+
const concurrency = config.concurrency ?? 2;
|
|
187
|
+
const respondNoContent = config.respondNoContent ?? true;
|
|
188
|
+
const normalizedLocalPath = _normalizeBasePath(config.localPath);
|
|
189
|
+
const normalizedUpstreamUrl = _normalizeUpstreamBaseUrl(config.upstreamUrl);
|
|
190
|
+
this.config = {
|
|
191
|
+
...config,
|
|
192
|
+
localPath: normalizedLocalPath,
|
|
193
|
+
upstreamUrl: normalizedUpstreamUrl,
|
|
194
|
+
maxQueueSize,
|
|
195
|
+
concurrency,
|
|
196
|
+
respondNoContent,
|
|
197
|
+
};
|
|
198
|
+
this.queue = [];
|
|
199
|
+
this.workers = [];
|
|
200
|
+
this.isRunning = false;
|
|
201
|
+
this.isInstalled = false;
|
|
202
|
+
this.metrics = {
|
|
203
|
+
routedRequests: 0,
|
|
204
|
+
acceptedBatches: 0,
|
|
205
|
+
droppedBatches: 0,
|
|
206
|
+
forwardedBatches: 0,
|
|
207
|
+
failedBatches: 0,
|
|
208
|
+
inFlight: 0,
|
|
209
|
+
queueSize: 0,
|
|
210
|
+
lastError: null,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
getMetrics() {
|
|
214
|
+
return { ...this.metrics, queueSize: this.queue.length };
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Install the route handler and start background workers.
|
|
218
|
+
* Call this once per BrowserContext.
|
|
219
|
+
*/
|
|
220
|
+
async install(context) {
|
|
221
|
+
if (this.isInstalled) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const basePath = this.config.localPath;
|
|
225
|
+
if (!basePath.startsWith('/')) {
|
|
226
|
+
throw new Error('localPath must start with "/" (e.g. "/__mcp_otel/").');
|
|
227
|
+
}
|
|
228
|
+
// Match any origin that contains the base path in the pathname.
|
|
229
|
+
const pattern = `**${basePath}**`;
|
|
230
|
+
await context.route(pattern, async (route) => {
|
|
231
|
+
await this._handleRoute(route);
|
|
232
|
+
});
|
|
233
|
+
this.isInstalled = true;
|
|
234
|
+
if (!this.isRunning) {
|
|
235
|
+
await this.start();
|
|
236
|
+
}
|
|
237
|
+
logger.debug(`[otel-proxy] installed route pattern: ${pattern} (basePath=${basePath}, upstreamBase=${this.config.upstreamUrl})`);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Uninstall route handler and stop workers.
|
|
241
|
+
*/
|
|
242
|
+
async uninstall(context) {
|
|
243
|
+
if (!this.isInstalled) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const pattern = `**${this.config.localPath}**`;
|
|
247
|
+
try {
|
|
248
|
+
await context.unroute(pattern);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Ignore if not supported or already removed.
|
|
252
|
+
}
|
|
253
|
+
this.isInstalled = false;
|
|
254
|
+
await this.stop();
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Start worker loop(s) that flush the queue to upstream.
|
|
258
|
+
*/
|
|
259
|
+
async start() {
|
|
260
|
+
if (this.isRunning) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
this.isRunning = true;
|
|
264
|
+
const workerCount = Math.max(1, this.config.concurrency);
|
|
265
|
+
for (let i = 0; i < workerCount; i++) {
|
|
266
|
+
const w = this._workerLoop(i);
|
|
267
|
+
this.workers.push(w);
|
|
268
|
+
}
|
|
269
|
+
logger.debug(`[otel-proxy] started with concurrency=${workerCount}, maxQueueSize=${this.config.maxQueueSize}`);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Stop workers. Any queued items will be dropped.
|
|
273
|
+
*/
|
|
274
|
+
async stop() {
|
|
275
|
+
if (!this.isRunning) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
this.isRunning = false;
|
|
279
|
+
// Drop queue immediately to avoid memory growth on shutdown.
|
|
280
|
+
this.queue.length = 0;
|
|
281
|
+
try {
|
|
282
|
+
await Promise.allSettled(this.workers);
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
this.workers.length = 0;
|
|
286
|
+
}
|
|
287
|
+
logger.debug('[otel-proxy] stopped');
|
|
288
|
+
}
|
|
289
|
+
async _handleRoute(route) {
|
|
290
|
+
const req = route.request();
|
|
291
|
+
this.metrics.routedRequests++;
|
|
292
|
+
// ACK preflight quickly (do not forward).
|
|
293
|
+
// Some setups / collectors choke on OPTIONS anyway.
|
|
294
|
+
if (req.method().toUpperCase() === 'OPTIONS') {
|
|
295
|
+
await this._fulfillFast(route);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (this.config.shouldForward) {
|
|
299
|
+
const should = this.config.shouldForward(req);
|
|
300
|
+
if (!should) {
|
|
301
|
+
await this._fulfillFast(route);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const requestUrl = req.url();
|
|
306
|
+
const basePath = this.config.localPath;
|
|
307
|
+
const suffixPath = _computeSuffixPath(requestUrl, basePath);
|
|
308
|
+
if (!suffixPath) {
|
|
309
|
+
// Pattern matched but URL parsing/path extraction failed; fallback so we don't break the page.
|
|
310
|
+
await route.fallback();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const upstreamFullUrl = _appendSuffixToUpstream(this.config.upstreamUrl, suffixPath, requestUrl);
|
|
314
|
+
const buf = await req.postDataBuffer();
|
|
315
|
+
const body = buf ?? Buffer.alloc(0);
|
|
316
|
+
const contentTypeHeader = req.headers()['content-type'];
|
|
317
|
+
const contentType = contentTypeHeader ?? 'application/x-protobuf';
|
|
318
|
+
const method = req.method();
|
|
319
|
+
const headers = {
|
|
320
|
+
'content-type': contentType,
|
|
321
|
+
};
|
|
322
|
+
if (this.config.upstreamHeaders) {
|
|
323
|
+
for (const [k, v] of Object.entries(this.config.upstreamHeaders)) {
|
|
324
|
+
headers[k] = v;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (this.queue.length >= this.config.maxQueueSize) {
|
|
328
|
+
this.metrics.droppedBatches++;
|
|
329
|
+
await this._fulfillFast(route);
|
|
330
|
+
logger.warn(`[otel-proxy] dropped batch (queue full: ${this.queue.length}/${this.config.maxQueueSize}) suffix=${suffixPath}`);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const item = {
|
|
334
|
+
body,
|
|
335
|
+
contentType,
|
|
336
|
+
createdAtMs: Date.now(),
|
|
337
|
+
upstreamUrl: upstreamFullUrl,
|
|
338
|
+
method,
|
|
339
|
+
headers,
|
|
340
|
+
};
|
|
341
|
+
this.queue.push(item);
|
|
342
|
+
this.metrics.acceptedBatches++;
|
|
343
|
+
await this._fulfillFast(route);
|
|
344
|
+
}
|
|
345
|
+
async _fulfillFast(route) {
|
|
346
|
+
const status = this.config.respondNoContent ? 204 : 200;
|
|
347
|
+
if (status === 204) {
|
|
348
|
+
await route.fulfill({ status });
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
await route.fulfill({
|
|
352
|
+
status,
|
|
353
|
+
headers: { 'content-type': 'text/plain; charset=utf-8' },
|
|
354
|
+
body: '',
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
async _workerLoop(workerIndex) {
|
|
358
|
+
while (this.isRunning) {
|
|
359
|
+
const item = this.queue.shift();
|
|
360
|
+
if (!item) {
|
|
361
|
+
await this._sleep(25);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
this.metrics.inFlight++;
|
|
365
|
+
try {
|
|
366
|
+
await this._forwardUpstream(item);
|
|
367
|
+
this.metrics.forwardedBatches++;
|
|
368
|
+
}
|
|
369
|
+
catch (e) {
|
|
370
|
+
this.metrics.failedBatches++;
|
|
371
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
372
|
+
this.metrics.lastError = msg;
|
|
373
|
+
logger.warn(`[otel-proxy] worker=${workerIndex} forward failed: ${msg}`);
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
this.metrics.inFlight--;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async _forwardUpstream(item) {
|
|
381
|
+
const res = await fetch(item.upstreamUrl, {
|
|
382
|
+
method: item.method,
|
|
383
|
+
headers: item.headers,
|
|
384
|
+
body: new Uint8Array(item.body),
|
|
385
|
+
});
|
|
386
|
+
if (res.status < 200 || res.status >= 300) {
|
|
387
|
+
const text = await this._safeReadText(res);
|
|
388
|
+
throw new Error(`upstream returned ${res.status} for ${item.upstreamUrl}: ${text}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async _safeReadText(res) {
|
|
392
|
+
try {
|
|
393
|
+
const t = await res.text();
|
|
394
|
+
return t.slice(0, 500);
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
return '';
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async _sleep(ms) {
|
|
401
|
+
await new Promise((resolve) => {
|
|
402
|
+
setTimeout(() => resolve(), ms);
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
exports.OTELProxy = OTELProxy;
|
|
407
|
+
//# sourceMappingURL=otel-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel-proxy.js","sourceRoot":"","sources":["../../src/otel/otel-proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/server-info.js
CHANGED
|
@@ -1,32 +1,70 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SERVER_VERSION = exports.SERVER_NAME = void 0;
|
|
3
|
+
exports.UI_DEBUGGING_POLICY = exports.SERVER_INSTRUCTIONS = exports.SERVER_VERSION = exports.SERVER_NAME = void 0;
|
|
4
4
|
exports.getServerInstructions = getServerInstructions;
|
|
5
5
|
exports.SERVER_NAME = 'browser-devtools-mcp';
|
|
6
6
|
exports.SERVER_VERSION = require('../package.json').version;
|
|
7
|
-
|
|
8
|
-
This MCP server exposes a Playwright-powered browser runtime to AI agents,
|
|
7
|
+
exports.SERVER_INSTRUCTIONS = `
|
|
8
|
+
This MCP server exposes a Playwright-powered browser runtime to AI agents,
|
|
9
|
+
enabling deep, bidirectional debugging and interaction with live web pages.
|
|
9
10
|
|
|
10
|
-
It supports both visual understanding and code-level inspection of browser state,
|
|
11
|
+
It supports both visual understanding and code-level inspection of browser state,
|
|
12
|
+
similar to existing Playwright and Chrome DevTools–based MCP servers, with a focus on AI-driven exploration, diagnosis, and action.
|
|
11
13
|
|
|
12
14
|
Core capabilities include:
|
|
13
|
-
|
|
14
|
-
- Visual inspection of pages, layout, geometry, visibility, and styles
|
|
15
|
+
- Visual inspection of pages, layout, geometry, visibility, stacking, and styles
|
|
15
16
|
- DOM and code-level debugging, including attributes, computed styles, and accessibility data
|
|
16
|
-
- Correlation between rendered visuals and underlying DOM structure
|
|
17
|
-
- JavaScript evaluation in page context
|
|
17
|
+
- Correlation between rendered visuals and underlying DOM / accessibility structure
|
|
18
|
+
- JavaScript evaluation in page context for advanced diagnostics
|
|
18
19
|
- Browser control and automation (navigation, input, scrolling, viewport control)
|
|
19
20
|
- Long-lived, session-based debugging backed by real Playwright browser instances
|
|
20
21
|
- Streamable responses and server-initiated notifications for interactive analysis
|
|
21
22
|
- Clean lifecycle management and teardown on connection close
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
UI debugging guidance for AI agents:
|
|
25
|
+
- Prefer Accessibility (AX) and ARIA snapshots over raw DOM dumps when diagnosing UI problems.
|
|
26
|
+
These snapshots provide higher-signal, semantically meaningful anchors (roles, names, states) that
|
|
27
|
+
map more reliably to what users perceive and what assistive tech can interact with.
|
|
28
|
+
- Use the AX Tree Snapshot tool to correlate interactive semantics with runtime visual truth:
|
|
29
|
+
bounding boxes, visibility, viewport intersection, and (optionally) computed styles.
|
|
30
|
+
- If a UI control appears present but interactions fail (e.g., clicks do nothing), suspect overlap/occlusion.
|
|
31
|
+
In such cases, enable occlusion checking ("elementFromPoint") to identify which element is actually on top.
|
|
32
|
+
- Use ARIA snapshots to reason about accessibility roles/states and to validate that the intended
|
|
33
|
+
semantics (labels, roles, disabled state, focusability) match the visible UI.
|
|
34
|
+
|
|
35
|
+
This server is designed for AI coding assistants, visual debugging agents, and automated analysis tools
|
|
36
|
+
that need to reason about what a page looks like, how it is structured, and how it behaves — all through a single MCP interface.
|
|
24
37
|
|
|
25
38
|
It treats the browser as a queryable, inspectable, and controllable execution environment rather than a static screenshot source.
|
|
26
39
|
`;
|
|
40
|
+
exports.UI_DEBUGGING_POLICY = `
|
|
41
|
+
<ui_debugging_policy>
|
|
42
|
+
When asked to check for UI problems, layout issues, or visual bugs, ALWAYS follow this policy:
|
|
43
|
+
|
|
44
|
+
1. **Visual Inspection**: Take screenshot for general aesthetics and layout overview
|
|
45
|
+
2. **Accessibility Tree Analysis**: Call "a11y_take-ax-tree-snapshot" tool with "checkOcclusion:true"
|
|
46
|
+
- Provides precise bounding boxes, runtime visual data, and occlusion detection
|
|
47
|
+
- Best for detecting overlaps and measuring exact positions
|
|
48
|
+
3. **ARIA Snapshot**: Call "a11y_take-aria-snapshot" tool (full page or specific selector)
|
|
49
|
+
- Provides semantic structure and accessibility roles
|
|
50
|
+
- Best for understanding page hierarchy and accessibility issues
|
|
51
|
+
4. **Manual Verification**: Calculate bounding box overlaps:
|
|
52
|
+
- Horizontal: (element1.x + element1.width) ≤ element2.x
|
|
53
|
+
- Vertical: (element1.y + element1.height) ≤ element2.y
|
|
54
|
+
5. **Report ALL findings**: aesthetic issues, overlaps, spacing problems, alignment issues,
|
|
55
|
+
accessibility problems, semantic structure issues
|
|
56
|
+
|
|
57
|
+
**Why both tools?**
|
|
58
|
+
- AX tree: Technical measurements, occlusion, precise positioning
|
|
59
|
+
- ARIA snapshot: Semantic understanding, accessibility structure, role hierarchy
|
|
60
|
+
|
|
61
|
+
Never assume "looks good visually" = "no problems". Overlaps and accessibility issues
|
|
62
|
+
can be functionally broken while appearing visually correct.
|
|
63
|
+
</ui_debugging_policy>
|
|
64
|
+
`;
|
|
27
65
|
function getServerInstructions() {
|
|
28
66
|
const parts = [];
|
|
29
|
-
parts.push(SERVER_INSTRUCTIONS);
|
|
67
|
+
parts.push(exports.SERVER_INSTRUCTIONS);
|
|
30
68
|
const result = parts.join('\n\n');
|
|
31
69
|
return result.trim();
|
|
32
70
|
}
|
package/dist/server-info.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-info.js","sourceRoot":"","sources":["../src/server-info.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"server-info.js","sourceRoot":"","sources":["../src/server-info.ts"],"names":[],"mappings":";;;AA+DA,sDAOC;AAtEY,QAAA,WAAW,GAAG,sBAAsB,CAAC;AAC1B,sBAAc,GAAK,OAAO,CAAC,iBAAiB,CAAC,SAAC;AAEzD,QAAA,mBAAmB,GAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgC1C,CAAC;AAEW,QAAA,mBAAmB,GAAW;;;;;;;;;;;;;;;;;;;;;;;;CAwB1C,CAAC;AAEF,SAAgB,qBAAqB;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,2BAAmB,CAAC,CAAC;IAEhC,MAAM,MAAM,GAAW,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -35,19 +35,53 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.createServer = createServer;
|
|
37
37
|
exports.createSession = createSession;
|
|
38
|
-
const browser_1 = require("./browser");
|
|
39
|
-
const context_1 = require("./context");
|
|
40
38
|
const logger = __importStar(require("./logger"));
|
|
41
39
|
const server_info_1 = require("./server-info");
|
|
42
40
|
const tools_1 = require("./tools");
|
|
43
41
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
function _getImage(response) {
|
|
43
|
+
if ('image' in response &&
|
|
44
|
+
response.image !== null &&
|
|
45
|
+
typeof response.image === 'object' &&
|
|
46
|
+
'data' in response.image &&
|
|
47
|
+
'mimeType' in response.image &&
|
|
48
|
+
Buffer.isBuffer(response.image.data) &&
|
|
49
|
+
typeof response.image.mimeType === 'string') {
|
|
50
|
+
const image = response.image;
|
|
51
|
+
delete response.image;
|
|
52
|
+
return image;
|
|
53
|
+
}
|
|
49
54
|
}
|
|
50
|
-
|
|
55
|
+
function _toResponse(response) {
|
|
56
|
+
const image = _getImage(response);
|
|
57
|
+
const contents = [];
|
|
58
|
+
contents.push({
|
|
59
|
+
type: 'text',
|
|
60
|
+
text: JSON.stringify(response, null, 2),
|
|
61
|
+
});
|
|
62
|
+
if (image) {
|
|
63
|
+
if (image.mimeType === 'image/svg+xml') {
|
|
64
|
+
contents.push({
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: image.data.toString(),
|
|
67
|
+
mimeType: image.mimeType,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
contents.push({
|
|
72
|
+
type: 'image',
|
|
73
|
+
data: image.data.toString('base64'),
|
|
74
|
+
mimeType: image.mimeType,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
content: contents,
|
|
80
|
+
structuredContent: response,
|
|
81
|
+
isError: false,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async function createServer(transport, opts) {
|
|
51
85
|
const server = new mcp_js_1.McpServer({
|
|
52
86
|
name: server_info_1.SERVER_NAME,
|
|
53
87
|
version: server_info_1.SERVER_VERSION,
|
|
@@ -59,16 +93,13 @@ async function createServer(opts) {
|
|
|
59
93
|
instructions: (0, server_info_1.getServerInstructions)(),
|
|
60
94
|
});
|
|
61
95
|
const messages = [];
|
|
62
|
-
// TODO Add policies as prompts here
|
|
63
|
-
/*
|
|
64
96
|
messages.push({
|
|
65
97
|
role: 'user',
|
|
66
98
|
content: {
|
|
67
99
|
type: 'text',
|
|
68
|
-
text:
|
|
100
|
+
text: server_info_1.UI_DEBUGGING_POLICY,
|
|
69
101
|
},
|
|
70
102
|
});
|
|
71
|
-
*/
|
|
72
103
|
server.registerPrompt('default_system', {
|
|
73
104
|
title: 'Default System Prompt',
|
|
74
105
|
description: 'General behavior for the AI assistant',
|
|
@@ -76,21 +107,12 @@ async function createServer(opts) {
|
|
|
76
107
|
description: "Defines the assistant's general reasoning and tool usage rules.",
|
|
77
108
|
messages,
|
|
78
109
|
}));
|
|
79
|
-
const toolExecutor = new tools_1.ToolExecutor(
|
|
110
|
+
const toolExecutor = new tools_1.ToolExecutor(() => transport.sessionId);
|
|
80
111
|
const createToolCallback = (tool) => {
|
|
81
112
|
return async (args) => {
|
|
82
113
|
try {
|
|
83
114
|
const response = await toolExecutor.executeTool(tool, args);
|
|
84
|
-
return
|
|
85
|
-
content: [
|
|
86
|
-
{
|
|
87
|
-
type: 'text',
|
|
88
|
-
text: JSON.stringify(response, null, 2),
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
structuredContent: response,
|
|
92
|
-
isError: false,
|
|
93
|
-
};
|
|
115
|
+
return _toResponse(response);
|
|
94
116
|
}
|
|
95
117
|
catch (error) {
|
|
96
118
|
return {
|
|
@@ -110,20 +132,13 @@ async function createServer(opts) {
|
|
|
110
132
|
outputSchema: t.outputSchema(),
|
|
111
133
|
}, createToolCallback(t));
|
|
112
134
|
});
|
|
135
|
+
await server.connect(transport);
|
|
113
136
|
return server;
|
|
114
137
|
}
|
|
115
|
-
|
|
116
|
-
const sessionContext = await _createSessionContext(() => transport.sessionId);
|
|
117
|
-
const server = await createServer({
|
|
118
|
-
config,
|
|
119
|
-
context: sessionContext,
|
|
120
|
-
});
|
|
121
|
-
await server.connect(transport);
|
|
138
|
+
function createSession(transport, server) {
|
|
122
139
|
return {
|
|
123
140
|
transport,
|
|
124
141
|
server,
|
|
125
|
-
context: sessionContext,
|
|
126
|
-
initialized: false,
|
|
127
142
|
closed: false,
|
|
128
143
|
lastActiveAt: Date.now(),
|
|
129
144
|
};
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tools = void 0;
|
|
4
|
+
const take_aria_snapshot_1 = require("./take-aria-snapshot");
|
|
5
|
+
const take_ax_tree_snapshot_1 = require("./take-ax-tree-snapshot");
|
|
6
|
+
exports.tools = [new take_aria_snapshot_1.TakeAriaSnapshot(), new take_ax_tree_snapshot_1.TakeAxTreeSnapshot()];
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/a11y/index.ts"],"names":[],"mappings":";;;AACA,6DAAwD;AACxD,mEAA6D;AAEhD,QAAA,KAAK,GAAW,CAAC,IAAI,qCAAgB,EAAE,EAAE,IAAI,0CAAkB,EAAE,CAAC,CAAC"}
|