browser-devtools-mcp 0.0.2 → 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 +97 -6
- 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 -17
- 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.js +4 -19
- package/dist/server.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/README.md
CHANGED
|
@@ -16,6 +16,7 @@ Browser DevTools MCP exposes a Playwright-powered browser runtime to AI agents,
|
|
|
16
16
|
- **DOM & Code-Level Debugging**: Element inspection, computed styles, accessibility data
|
|
17
17
|
- **Browser Automation**: Navigation, input, clicking, scrolling, viewport control
|
|
18
18
|
- **Execution Monitoring**: Console message capture, HTTP request/response tracking
|
|
19
|
+
- **OpenTelemetry Integration**: Automatic trace injection into web pages, UI trace collection, and backend trace correlation via trace context propagation
|
|
19
20
|
- **JavaScript Evaluation**: Execute code in page context
|
|
20
21
|
- **Session Management**: Long-lived, session-based debugging with automatic cleanup
|
|
21
22
|
- **Multiple Transport Modes**: Supports both stdio and HTTP transports
|
|
@@ -44,6 +45,8 @@ Browser DevTools MCP exposes a Playwright-powered browser runtime to AI agents,
|
|
|
44
45
|
### Monitoring Tools
|
|
45
46
|
- **Console Messages**: Capture and filter browser console logs with advanced filtering (level, search, timestamp, sequence number)
|
|
46
47
|
- **HTTP Requests**: Monitor network traffic with detailed request/response data, filtering by resource type, status code, and more
|
|
48
|
+
- **OpenTelemetry Tracing**: Automatic trace injection into web pages, UI trace collection (document load, fetch, XMLHttpRequest, user interactions), and trace context propagation for backend correlation
|
|
49
|
+
- **Trace ID Management**: Get, set, and generate OpenTelemetry compatible trace IDs for distributed tracing across API calls
|
|
47
50
|
|
|
48
51
|
### Accessibility (A11Y) Tools
|
|
49
52
|
- **ARIA Snapshots**: Capture semantic structure and accessibility roles in YAML format
|
|
@@ -363,7 +366,19 @@ The server can be configured using environment variables:
|
|
|
363
366
|
| `SESSION_CLOSE_ON_SOCKET_CLOSE` | Close session when socket closes | `false` |
|
|
364
367
|
| `CONSOLE_MESSAGES_BUFFER_SIZE` | Maximum console messages to buffer | `1000` |
|
|
365
368
|
| `HTTP_REQUESTS_BUFFER_SIZE` | Maximum HTTP requests to buffer | `1000` |
|
|
369
|
+
| `BROWSER_HEADLESS_ENABLE` | Run browser in headless mode | `true` |
|
|
370
|
+
| `BROWSER_PERSISTENT_ENABLE` | Use persistent browser context (preserves cookies, localStorage, etc.) | `false` |
|
|
371
|
+
| `BROWSER_PERSISTENT_USER_DATA_DIR` | Directory for persistent browser context user data | `./browser-devtools-mcp` |
|
|
372
|
+
| `BROWSER_USE_INSTALLED_ON_SYSTEM` | Use system-installed Chrome browser instead of Playwright's bundled browser | `false` |
|
|
366
373
|
| `BROWSER_EXECUTABLE_PATH` | Custom browser executable path | (uses Playwright default) |
|
|
374
|
+
| `OTEL_ENABLE` | Enable OpenTelemetry integration | `false` |
|
|
375
|
+
| `OTEL_SERVICE_NAME` | OpenTelemetry service name | `frontend` |
|
|
376
|
+
| `OTEL_SERVICE_VERSION` | OpenTelemetry service version | (none) |
|
|
377
|
+
| `OTEL_ASSETS_DIR` | Directory containing OpenTelemetry bundle files | (uses default) |
|
|
378
|
+
| `OTEL_EXPORTER_TYPE` | OpenTelemetry exporter type: "otlp/http", "console", or "none" | `none` |
|
|
379
|
+
| `OTEL_EXPORTER_HTTP_URL` | OpenTelemetry collector base URL (e.g., "http://localhost:4318") | (none) |
|
|
380
|
+
| `OTEL_EXPORTER_HTTP_HEADERS` | OpenTelemetry exporter HTTP headers (comma-separated key=value pairs) | (none) |
|
|
381
|
+
| `OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS` | User interaction events to instrument (comma-separated, e.g., "click,submit") | `click` |
|
|
367
382
|
|
|
368
383
|
## Available Tools
|
|
369
384
|
|
|
@@ -529,6 +544,39 @@ Retrieves HTTP requests from the browser with detailed filtering.
|
|
|
529
544
|
**Returns:**
|
|
530
545
|
- `requests` (array): Array of HTTP requests with URL, method, headers, body, response, timing, and metadata
|
|
531
546
|
|
|
547
|
+
#### `monitoring_get-trace-id`
|
|
548
|
+
Gets the OpenTelemetry compatible trace id of the current session.
|
|
549
|
+
|
|
550
|
+
**Parameters:**
|
|
551
|
+
- No input parameters
|
|
552
|
+
|
|
553
|
+
**Returns:**
|
|
554
|
+
- `traceId` (string, optional): The OpenTelemetry compatible trace id of the current session if available
|
|
555
|
+
|
|
556
|
+
**Note:** Requires OpenTelemetry to be enabled (`OTEL_ENABLE=true`).
|
|
557
|
+
|
|
558
|
+
#### `monitoring_new-trace-id`
|
|
559
|
+
Generates a new OpenTelemetry compatible trace id and sets it to the current session.
|
|
560
|
+
|
|
561
|
+
**Parameters:**
|
|
562
|
+
- No input parameters
|
|
563
|
+
|
|
564
|
+
**Returns:**
|
|
565
|
+
- `traceId` (string): The generated new OpenTelemetry compatible trace id
|
|
566
|
+
|
|
567
|
+
**Note:** Requires OpenTelemetry to be enabled (`OTEL_ENABLE=true`). The new trace ID is automatically set and will be used for all subsequent traces in the session.
|
|
568
|
+
|
|
569
|
+
#### `monitoring_set-trace-id`
|
|
570
|
+
Sets the OpenTelemetry compatible trace id of the current session.
|
|
571
|
+
|
|
572
|
+
**Parameters:**
|
|
573
|
+
- `traceId` (string, optional): The OpenTelemetry compatible trace id to be set. Leave it empty to clear the session trace id, so no OpenTelemetry trace header will be propagated from browser throughout the API calls
|
|
574
|
+
|
|
575
|
+
**Returns:**
|
|
576
|
+
- No return value
|
|
577
|
+
|
|
578
|
+
**Note:** Requires OpenTelemetry to be enabled (`OTEL_ENABLE=true`). When a trace ID is set, it will be propagated in HTTP headers (traceparent) for all API calls, enabling correlation with backend traces.
|
|
579
|
+
|
|
532
580
|
### Accessibility (A11Y) Tools
|
|
533
581
|
|
|
534
582
|
#### `a11y_take-aria-snapshot`
|
|
@@ -597,7 +645,24 @@ The server supports multiple browser engines:
|
|
|
597
645
|
- **Firefox**
|
|
598
646
|
- **WebKit**
|
|
599
647
|
|
|
600
|
-
Browser
|
|
648
|
+
**Browser Configuration:**
|
|
649
|
+
- **Headless Mode**: By default, browsers run in headless mode (`BROWSER_HEADLESS_ENABLE=true`). Set to `false` to see the browser window.
|
|
650
|
+
- **Persistent Context**: When enabled (`BROWSER_PERSISTENT_ENABLE=true`), browser contexts persist across sessions, preserving:
|
|
651
|
+
- Cookies and session data
|
|
652
|
+
- LocalStorage and IndexedDB
|
|
653
|
+
- Browser extensions and settings
|
|
654
|
+
- User preferences
|
|
655
|
+
|
|
656
|
+
Persistent contexts are shared across sessions and are not automatically closed when sessions end.
|
|
657
|
+
|
|
658
|
+
- **System Browser**: When enabled (`BROWSER_USE_INSTALLED_ON_SYSTEM=true`), the server uses the system-installed Chrome browser instead of Playwright's bundled browser. This is useful for:
|
|
659
|
+
- Testing with the exact browser version users have
|
|
660
|
+
- Using browser extensions installed on the system
|
|
661
|
+
- Better compatibility with certain web applications
|
|
662
|
+
|
|
663
|
+
**Note:** System browser support is currently only available for Chromium/Chrome.
|
|
664
|
+
|
|
665
|
+
Browser instances are shared across sessions for efficiency. Each session gets its own isolated browser context, unless persistent context is enabled (in which case contexts are shared).
|
|
601
666
|
|
|
602
667
|
### Buffering & Filtering
|
|
603
668
|
|
|
@@ -609,6 +674,31 @@ Console messages and HTTP requests are buffered in memory with configurable buff
|
|
|
609
674
|
- **Incremental retrieval**: Use sequence numbers to fetch only new items
|
|
610
675
|
- **Pagination**: Limit results with start/end trimming
|
|
611
676
|
|
|
677
|
+
### OpenTelemetry Integration
|
|
678
|
+
|
|
679
|
+
When enabled (`OTEL_ENABLE=true`), the server automatically injects OpenTelemetry instrumentation into all web pages navigated by the browser. This enables:
|
|
680
|
+
|
|
681
|
+
- **Automatic Trace Collection**: UI traces are automatically collected for:
|
|
682
|
+
- Document load events
|
|
683
|
+
- Fetch/XHR requests
|
|
684
|
+
- User interactions (clicks, form submissions, etc.)
|
|
685
|
+
|
|
686
|
+
- **Trace Context Propagation**: Trace IDs are automatically propagated in HTTP headers (traceparent) for all API calls, enabling:
|
|
687
|
+
- Correlation between frontend and backend traces
|
|
688
|
+
- End-to-end distributed tracing across the entire application stack
|
|
689
|
+
|
|
690
|
+
- **Trace ID Management**: Tools allow you to:
|
|
691
|
+
- Get the current session's trace ID
|
|
692
|
+
- Generate new trace IDs
|
|
693
|
+
- Set custom trace IDs (e.g., from backend trace context)
|
|
694
|
+
|
|
695
|
+
- **Exporter Configuration**: Traces can be exported to:
|
|
696
|
+
- **OTLP/HTTP**: Send to OpenTelemetry collector (configure via `OTEL_EXPORTER_HTTP_URL`)
|
|
697
|
+
- **Console**: Log traces to browser console (for debugging)
|
|
698
|
+
- **None**: Collect traces but don't export (for testing)
|
|
699
|
+
|
|
700
|
+
The OpenTelemetry integration uses a proxy mechanism (`/__mcp_otel/`) to forward traces from the browser to the configured collector, ensuring proper CORS handling and trace context propagation.
|
|
701
|
+
|
|
612
702
|
## Development
|
|
613
703
|
|
|
614
704
|
### Prerequisites
|
|
@@ -649,11 +739,12 @@ This server enables AI assistants to:
|
|
|
649
739
|
|
|
650
740
|
1. **Debug Web Applications**: Capture screenshots, inspect DOM, check console errors
|
|
651
741
|
2. **Monitor Network Activity**: Track API calls, analyze request/response patterns
|
|
652
|
-
3. **
|
|
653
|
-
4. **
|
|
654
|
-
5. **
|
|
655
|
-
6. **
|
|
656
|
-
7. **
|
|
742
|
+
3. **Distributed Tracing**: Enable OpenTelemetry to correlate frontend and backend traces for end-to-end debugging
|
|
743
|
+
4. **Test User Flows**: Automate navigation and interactions
|
|
744
|
+
5. **Visual Verification**: Compare visual states, verify UI changes
|
|
745
|
+
6. **Content Extraction**: Get HTML/text content with filtering and cleaning options
|
|
746
|
+
7. **Accessibility Analysis**: Use ARIA and AX tree snapshots to understand page structure and detect UI issues
|
|
747
|
+
8. **Performance Analysis**: Monitor HTTP request timing and failures
|
|
657
748
|
|
|
658
749
|
### Example Workflow
|
|
659
750
|
|
package/dist/browser.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BrowserType = void 0;
|
|
4
|
-
exports.getBrowser = getBrowser;
|
|
6
|
+
exports.DEFAULT_BROWSER_TYPE = exports.BrowserType = void 0;
|
|
5
7
|
exports.newBrowserContext = newBrowserContext;
|
|
6
8
|
exports.newPage = newPage;
|
|
9
|
+
exports.closeBrowserContext = closeBrowserContext;
|
|
7
10
|
const config_1 = require("./config");
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
12
|
const playwright_1 = require("playwright");
|
|
9
13
|
var BrowserType;
|
|
10
14
|
(function (BrowserType) {
|
|
@@ -12,14 +16,35 @@ var BrowserType;
|
|
|
12
16
|
BrowserType["FIREFOX"] = "firefox";
|
|
13
17
|
BrowserType["WEBKIT"] = "webkit";
|
|
14
18
|
})(BrowserType || (exports.BrowserType = BrowserType = {}));
|
|
19
|
+
exports.DEFAULT_BROWSER_TYPE = BrowserType.CHROMIUM;
|
|
15
20
|
const browsers = new Map();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
const persistenceBrowserContexts = new Map();
|
|
22
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
function _browserKey(browserOptions) {
|
|
24
|
+
return JSON.stringify(browserOptions);
|
|
25
|
+
}
|
|
26
|
+
function _browserLaunchOptions(browserOptions) {
|
|
27
|
+
const launchOptions = {
|
|
28
|
+
headless: browserOptions.headless,
|
|
29
|
+
executablePath: browserOptions.executablePath,
|
|
30
|
+
handleSIGINT: false,
|
|
31
|
+
handleSIGTERM: false,
|
|
20
32
|
};
|
|
33
|
+
if (browserOptions.useInstalledOnSystem) {
|
|
34
|
+
switch (browserOptions.browserType) {
|
|
35
|
+
case BrowserType.CHROMIUM:
|
|
36
|
+
launchOptions.channel = 'chrome';
|
|
37
|
+
launchOptions.args = [
|
|
38
|
+
'--disable-blink-features=AutomationControlled',
|
|
39
|
+
];
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
throw new Error(`Browser type ${browserOptions.browserType} is not supported to be used from the one installed on the system`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return launchOptions;
|
|
21
46
|
}
|
|
22
|
-
async function _createBrowser(browserOptions
|
|
47
|
+
async function _createBrowser(browserOptions) {
|
|
23
48
|
// Use the appropriate browser engine
|
|
24
49
|
let browserInstance;
|
|
25
50
|
switch (browserOptions.browserType) {
|
|
@@ -34,34 +59,149 @@ async function _createBrowser(browserOptions = {}) {
|
|
|
34
59
|
browserInstance = playwright_1.chromium;
|
|
35
60
|
break;
|
|
36
61
|
}
|
|
37
|
-
return browserInstance.launch(
|
|
38
|
-
executablePath: browserOptions.executablePath,
|
|
39
|
-
handleSIGINT: false,
|
|
40
|
-
handleSIGTERM: false,
|
|
41
|
-
});
|
|
62
|
+
return browserInstance.launch(_browserLaunchOptions(browserOptions));
|
|
42
63
|
}
|
|
43
|
-
async function
|
|
44
|
-
|
|
64
|
+
async function _getBrowser(browserOptions) {
|
|
65
|
+
const browserKey = _browserKey(browserOptions);
|
|
66
|
+
let browserInstance = browsers.get(browserKey);
|
|
45
67
|
if (browserInstance && !browserInstance.isConnected()) {
|
|
46
68
|
try {
|
|
47
69
|
await browserInstance.close().catch(() => { });
|
|
48
70
|
}
|
|
49
|
-
catch
|
|
50
|
-
// Ignore errors when closing disconnected browser
|
|
51
|
-
}
|
|
52
|
-
// Reset browser and page references
|
|
71
|
+
catch { }
|
|
53
72
|
browserInstance = undefined;
|
|
54
73
|
}
|
|
55
74
|
if (!browserInstance) {
|
|
56
|
-
browserInstance = await _createBrowser(
|
|
57
|
-
browsers.set(
|
|
75
|
+
browserInstance = await _createBrowser(browserOptions);
|
|
76
|
+
browsers.set(browserKey, browserInstance);
|
|
58
77
|
}
|
|
59
78
|
return browserInstance;
|
|
60
79
|
}
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
81
|
+
function _persistentBrowserContextKey(browserContextOptions) {
|
|
82
|
+
// There can be one active persistent browser context in a user data directory
|
|
83
|
+
return browserContextOptions.persistent.userDataDir;
|
|
84
|
+
}
|
|
85
|
+
function _persistentBrowserContextLaunchOptions(browserContextOptions) {
|
|
86
|
+
const browserOptions = browserContextOptions.browserOptions;
|
|
87
|
+
const launchOptions = {
|
|
88
|
+
headless: browserOptions.headless,
|
|
89
|
+
executablePath: browserOptions.executablePath,
|
|
90
|
+
bypassCSP: true,
|
|
91
|
+
};
|
|
92
|
+
if (browserOptions.useInstalledOnSystem) {
|
|
93
|
+
switch (browserOptions.browserType) {
|
|
94
|
+
case BrowserType.CHROMIUM:
|
|
95
|
+
launchOptions.channel = 'chrome';
|
|
96
|
+
launchOptions.args = [
|
|
97
|
+
'--disable-blink-features=AutomationControlled',
|
|
98
|
+
];
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
throw new Error(`Browser type ${browserOptions.browserType} is not supported to be used from the one installed on the system`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return launchOptions;
|
|
105
|
+
}
|
|
106
|
+
async function _createPersistentBrowserContext(browserContextOptions) {
|
|
107
|
+
// Use the appropriate browser engine
|
|
108
|
+
let browserInstance;
|
|
109
|
+
switch (browserContextOptions.browserOptions.browserType) {
|
|
110
|
+
case BrowserType.FIREFOX:
|
|
111
|
+
browserInstance = playwright_1.firefox;
|
|
112
|
+
break;
|
|
113
|
+
case BrowserType.WEBKIT:
|
|
114
|
+
browserInstance = playwright_1.webkit;
|
|
115
|
+
break;
|
|
116
|
+
case BrowserType.CHROMIUM:
|
|
117
|
+
default:
|
|
118
|
+
browserInstance = playwright_1.chromium;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
const userDataDir = browserContextOptions.persistent.userDataDir;
|
|
122
|
+
// Be sure that user data dir is available
|
|
123
|
+
fs_1.default.mkdirSync(userDataDir, { recursive: true });
|
|
124
|
+
const browserContext = await browserInstance.launchPersistentContext(userDataDir, _persistentBrowserContextLaunchOptions(browserContextOptions));
|
|
125
|
+
// Be sure that any restored pages are closed if there is any
|
|
126
|
+
for (const p of browserContext.pages()) {
|
|
127
|
+
try {
|
|
128
|
+
await p.close();
|
|
129
|
+
}
|
|
130
|
+
catch { }
|
|
131
|
+
}
|
|
132
|
+
return browserContext;
|
|
133
|
+
}
|
|
134
|
+
async function _getPersistentBrowserContext(browserContextOptions) {
|
|
135
|
+
const persistentBrowserContextKey = _persistentBrowserContextKey(browserContextOptions);
|
|
136
|
+
let browserContext = persistenceBrowserContexts.get(persistentBrowserContextKey);
|
|
137
|
+
if (browserContext && !browserContext.browser()?.isConnected()) {
|
|
138
|
+
try {
|
|
139
|
+
await browserContext.close().catch(() => { });
|
|
140
|
+
}
|
|
141
|
+
catch { }
|
|
142
|
+
browserContext = undefined;
|
|
143
|
+
}
|
|
144
|
+
if (!browserContext) {
|
|
145
|
+
browserContext = await _createPersistentBrowserContext(browserContextOptions);
|
|
146
|
+
persistenceBrowserContexts.set(persistentBrowserContextKey, browserContext);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// There can be one active persistent browser context in a user data directory
|
|
150
|
+
throw new Error(`There is already active persistent browser context in the user data directory: ${browserContextOptions.persistent?.userDataDir}`);
|
|
151
|
+
}
|
|
152
|
+
return browserContext;
|
|
153
|
+
}
|
|
154
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
155
|
+
async function newBrowserContext(browserContextOptions = {
|
|
156
|
+
browserOptions: {
|
|
157
|
+
browserType: exports.DEFAULT_BROWSER_TYPE,
|
|
158
|
+
headless: config_1.BROWSER_HEADLESS_ENABLE,
|
|
159
|
+
executablePath: config_1.BROWSER_EXECUTABLE_PATH,
|
|
160
|
+
useInstalledOnSystem: config_1.BROWSER_USE_INSTALLED_ON_SYSTEM,
|
|
161
|
+
},
|
|
162
|
+
persistent: config_1.BROWSER_PERSISTENT_ENABLE
|
|
163
|
+
? {
|
|
164
|
+
userDataDir: config_1.BROWSER_PERSISTENT_USER_DATA_DIR,
|
|
165
|
+
}
|
|
166
|
+
: undefined,
|
|
167
|
+
}) {
|
|
168
|
+
if (browserContextOptions.persistent) {
|
|
169
|
+
const browserContext = await _getPersistentBrowserContext(browserContextOptions);
|
|
170
|
+
return {
|
|
171
|
+
browserContext,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const browser = await _getBrowser(browserContextOptions.browserOptions);
|
|
176
|
+
const browserContext = await browser.newContext({
|
|
177
|
+
bypassCSP: true,
|
|
178
|
+
});
|
|
179
|
+
return {
|
|
180
|
+
browserContext,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
63
183
|
}
|
|
64
184
|
async function newPage(browserContext, pageOptions = {}) {
|
|
185
|
+
// TODO Design page options and take care of it here for the newly created page
|
|
65
186
|
return await browserContext.newPage();
|
|
66
187
|
}
|
|
188
|
+
async function closeBrowserContext(browserContext) {
|
|
189
|
+
await browserContext.close();
|
|
190
|
+
let deleted = false;
|
|
191
|
+
for (const [key, val] of persistenceBrowserContexts.entries()) {
|
|
192
|
+
if (browserContext === val) {
|
|
193
|
+
persistenceBrowserContexts.delete(key);
|
|
194
|
+
deleted = true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return deleted;
|
|
198
|
+
}
|
|
199
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
200
|
+
async function getElementFailFast(page, selector) {
|
|
201
|
+
const element = page.locator(selector);
|
|
202
|
+
if ((await element.count()) === 0) {
|
|
203
|
+
throw new Error(`Could not find element with selector "${selector}"`);
|
|
204
|
+
}
|
|
205
|
+
return element;
|
|
206
|
+
}
|
|
67
207
|
//# sourceMappingURL=browser.js.map
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -1,11 +1,56 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BROWSER_EXECUTABLE_PATH = exports.HTTP_REQUESTS_BUFFER_SIZE = exports.CONSOLE_MESSAGES_BUFFER_SIZE = exports.SESSION_CLOSE_ON_SOCKET_CLOSE = exports.SESSION_IDLE_CHECK_SECONDS = exports.SESSION_IDLE_SECONDS = exports.PORT = void 0;
|
|
6
|
+
exports.OTEL_EXPORTER_HTTP_HEADERS = exports.OTEL_EXPORTER_HTTP_URL = exports.OTEL_EXPORTER_TYPE = exports.OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS = exports.OTEL_ASSETS_DIR = exports.OTEL_SERVICE_VERSION = exports.OTEL_SERVICE_NAME = exports.OTEL_ENABLE = exports.BROWSER_EXECUTABLE_PATH = exports.BROWSER_USE_INSTALLED_ON_SYSTEM = exports.BROWSER_PERSISTENT_USER_DATA_DIR = exports.BROWSER_PERSISTENT_ENABLE = exports.BROWSER_HEADLESS_ENABLE = exports.HTTP_REQUESTS_BUFFER_SIZE = exports.CONSOLE_MESSAGES_BUFFER_SIZE = exports.SESSION_CLOSE_ON_SOCKET_CLOSE = exports.SESSION_IDLE_CHECK_SECONDS = exports.SESSION_IDLE_SECONDS = exports.PORT = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
4
8
|
exports.PORT = Number(process.env.PORT) || 3000;
|
|
5
9
|
exports.SESSION_IDLE_SECONDS = Number(process.env.SESSION_IDLE_SECONDS) || 300;
|
|
6
10
|
exports.SESSION_IDLE_CHECK_SECONDS = Number(process.env.SESSION_IDLE_CHECK_SECONDS) || 30;
|
|
7
11
|
exports.SESSION_CLOSE_ON_SOCKET_CLOSE = process.env.SESSION_CLOSE_ON_SOCKET_CLOSE === 'true';
|
|
8
12
|
exports.CONSOLE_MESSAGES_BUFFER_SIZE = Number(process.env.CONSOLE_MESSAGES_BUFFER_SIZE) || 1_000;
|
|
9
13
|
exports.HTTP_REQUESTS_BUFFER_SIZE = Number(process.env.HTTP_REQUESTS_BUFFER_SIZE) || 1_000;
|
|
14
|
+
exports.BROWSER_HEADLESS_ENABLE = (process.env.BROWSER_HEADLESS_ENABLE || 'true') === 'true';
|
|
15
|
+
exports.BROWSER_PERSISTENT_ENABLE = process.env.BROWSER_PERSISTENT_ENABLE === 'true';
|
|
16
|
+
exports.BROWSER_PERSISTENT_USER_DATA_DIR = process.env.BROWSER_PERSISTENT_USER_DATA_DIR ||
|
|
17
|
+
path_1.default.join(process.cwd(), 'browser-devtools-mcp');
|
|
18
|
+
exports.BROWSER_USE_INSTALLED_ON_SYSTEM = process.env.BROWSER_USE_INSTALLED_ON_SYSTEM === 'true';
|
|
10
19
|
exports.BROWSER_EXECUTABLE_PATH = process.env.BROWSER_EXECUTABLE_PATH;
|
|
20
|
+
exports.OTEL_ENABLE = process.env.OTEL_ENABLE === 'true';
|
|
21
|
+
exports.OTEL_SERVICE_NAME = process.env.OTEL_SERVICE_NAME || 'frontend';
|
|
22
|
+
exports.OTEL_SERVICE_VERSION = process.env.OTEL_SERVICE_VERSION;
|
|
23
|
+
exports.OTEL_ASSETS_DIR = process.env.OTEL_ASSETS_DIR;
|
|
24
|
+
exports.OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS = process
|
|
25
|
+
.env.OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS
|
|
26
|
+
? process.env.OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS.split(',')
|
|
27
|
+
: ['click'];
|
|
28
|
+
exports.OTEL_EXPORTER_TYPE = process.env.OTEL_EXPORTER_TYPE || 'none';
|
|
29
|
+
exports.OTEL_EXPORTER_HTTP_URL = process.env.OTEL_EXPORTER_HTTP_URL;
|
|
30
|
+
exports.OTEL_EXPORTER_HTTP_HEADERS = _parseKeyValueFromEnv(process.env.OTEL_EXPORTER_HTTP_HEADERS);
|
|
31
|
+
function _parseKeyValueFromEnv(envValue) {
|
|
32
|
+
const headers = {};
|
|
33
|
+
if (!envValue) {
|
|
34
|
+
return headers;
|
|
35
|
+
}
|
|
36
|
+
const pairs = envValue.split(',');
|
|
37
|
+
for (const pair of pairs) {
|
|
38
|
+
const trimmed = pair.trim();
|
|
39
|
+
if (!trimmed) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const eqIndex = trimmed.indexOf('=');
|
|
43
|
+
if (eqIndex === -1) {
|
|
44
|
+
// Invalid entry, skip
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
48
|
+
const value = trimmed.slice(eqIndex + 1).trim();
|
|
49
|
+
if (!key || !value) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
headers[key] = value;
|
|
53
|
+
}
|
|
54
|
+
return headers;
|
|
55
|
+
}
|
|
11
56
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/context.js
CHANGED
|
@@ -34,25 +34,37 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.McpSessionContext = void 0;
|
|
37
|
+
const browser_1 = require("./browser");
|
|
37
38
|
const config_1 = require("./config");
|
|
38
39
|
const logger = __importStar(require("./logger"));
|
|
40
|
+
const otel_controller_1 = require("./otel/otel-controller");
|
|
39
41
|
const types_1 = require("./types");
|
|
42
|
+
const utils_1 = require("./utils");
|
|
40
43
|
class McpSessionContext {
|
|
44
|
+
_sessionId;
|
|
45
|
+
options;
|
|
46
|
+
otelController;
|
|
41
47
|
consoleMessages = [];
|
|
42
48
|
httpRequests = [];
|
|
43
|
-
|
|
49
|
+
initialized = false;
|
|
44
50
|
closed = false;
|
|
45
|
-
|
|
51
|
+
traceId;
|
|
46
52
|
browserContext;
|
|
47
53
|
page;
|
|
48
|
-
constructor(
|
|
49
|
-
this.
|
|
50
|
-
this.browser = browser;
|
|
54
|
+
constructor(sessionId, browserContext, page, options) {
|
|
55
|
+
this._sessionId = sessionId;
|
|
51
56
|
this.browserContext = browserContext;
|
|
52
57
|
this.page = page;
|
|
53
|
-
this.
|
|
58
|
+
this.options = options;
|
|
59
|
+
this.otelController = new otel_controller_1.OTELController(this.browserContext);
|
|
54
60
|
}
|
|
55
|
-
|
|
61
|
+
async init() {
|
|
62
|
+
if (this.closed) {
|
|
63
|
+
throw new Error('Session context is already closed');
|
|
64
|
+
}
|
|
65
|
+
if (this.initialized) {
|
|
66
|
+
throw new Error('Session context is already initialized');
|
|
67
|
+
}
|
|
56
68
|
const me = this;
|
|
57
69
|
let consoleMessageSequenceNumber = 0;
|
|
58
70
|
this.page.on('console', (msg) => {
|
|
@@ -80,6 +92,13 @@ class McpSessionContext {
|
|
|
80
92
|
me.httpRequests.splice(0, me.httpRequests.length - config_1.HTTP_REQUESTS_BUFFER_SIZE);
|
|
81
93
|
}
|
|
82
94
|
});
|
|
95
|
+
if (this.options.otelEnable) {
|
|
96
|
+
this.traceId = (0, utils_1.newTraceId)();
|
|
97
|
+
await this.otelController.init({
|
|
98
|
+
traceId: this.traceId,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
this.initialized = true;
|
|
83
102
|
}
|
|
84
103
|
_toConsoleMessageLevelName(type) {
|
|
85
104
|
switch (type) {
|
|
@@ -155,11 +174,37 @@ class McpSessionContext {
|
|
|
155
174
|
sequenceNumber,
|
|
156
175
|
};
|
|
157
176
|
}
|
|
177
|
+
_isBodyLikelyPresent(status, method) {
|
|
178
|
+
if (method === 'HEAD' || method === 'OPTIONS') {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
if (status === 204 || status === 304) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
if (status >= 300 && status < 400) {
|
|
185
|
+
// redirects
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
async _safeReadResponseBody(res) {
|
|
191
|
+
try {
|
|
192
|
+
const req = res.request();
|
|
193
|
+
const method = req.method();
|
|
194
|
+
const status = res.status();
|
|
195
|
+
if (!this._isBodyLikelyPresent(status, method)) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
const buf = await res.body(); // may throw
|
|
199
|
+
return buf.toString('utf-8');
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// This is the important part: CDP can't always provide body.
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
158
206
|
async _toHttpRequest(req, sequenceNumber) {
|
|
159
207
|
const res = await req.response();
|
|
160
|
-
const isRedirect = res
|
|
161
|
-
? res.status() >= 300 && res.status() < 400
|
|
162
|
-
: false;
|
|
163
208
|
return {
|
|
164
209
|
url: req.url(),
|
|
165
210
|
method: req.method(),
|
|
@@ -173,9 +218,7 @@ class McpSessionContext {
|
|
|
173
218
|
status: res.status(),
|
|
174
219
|
statusText: res.statusText(),
|
|
175
220
|
headers: res.headers(),
|
|
176
|
-
body:
|
|
177
|
-
? undefined
|
|
178
|
-
: (await res.body()).toString(),
|
|
221
|
+
body: await this._safeReadResponseBody(res),
|
|
179
222
|
}
|
|
180
223
|
: undefined,
|
|
181
224
|
ok: res ? res.ok() : false,
|
|
@@ -184,7 +227,17 @@ class McpSessionContext {
|
|
|
184
227
|
};
|
|
185
228
|
}
|
|
186
229
|
sessionId() {
|
|
187
|
-
return this.
|
|
230
|
+
return this._sessionId;
|
|
231
|
+
}
|
|
232
|
+
async getTraceId() {
|
|
233
|
+
return this.traceId;
|
|
234
|
+
}
|
|
235
|
+
async setTraceId(traceId) {
|
|
236
|
+
if (!this.options.otelEnable) {
|
|
237
|
+
throw new Error('OTEL is not enabled');
|
|
238
|
+
}
|
|
239
|
+
this.traceId = traceId;
|
|
240
|
+
await this.otelController.setTraceId(this.page, traceId);
|
|
188
241
|
}
|
|
189
242
|
getConsoleMessages() {
|
|
190
243
|
return this.consoleMessages;
|
|
@@ -196,13 +249,15 @@ class McpSessionContext {
|
|
|
196
249
|
if (this.closed) {
|
|
197
250
|
return false;
|
|
198
251
|
}
|
|
252
|
+
logger.debug(`Closing OTEL controller of the MCP session with id ${this._sessionId} ...`);
|
|
253
|
+
await this.otelController.close();
|
|
199
254
|
// Page(s) owned by browser context are already closed by the browser context itself
|
|
200
255
|
try {
|
|
201
|
-
logger.debug(`Closing browser context of the MCP session with id ${this.
|
|
202
|
-
await this.browserContext
|
|
256
|
+
logger.debug(`Closing browser context of the MCP session with id ${this._sessionId} ...`);
|
|
257
|
+
await (0, browser_1.closeBrowserContext)(this.browserContext);
|
|
203
258
|
}
|
|
204
259
|
catch (err) {
|
|
205
|
-
logger.debug(`Error occurred while closing browser context of the MCP session with id ${this.
|
|
260
|
+
logger.debug(`Error occurred while closing browser context of the MCP session with id ${this._sessionId} ...`, err);
|
|
206
261
|
}
|
|
207
262
|
this.consoleMessages.length = 0;
|
|
208
263
|
this.httpRequests.length = 0;
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAGkB;AAClB,iDAAmC;AACnC,mCAQiB;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|