@nimbus21.ai/chrome-devtools-mcp 0.17.3 → 0.17.5
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/build/src/browser.js +31 -1
- package/build/src/main.js +43 -3
- package/package.json +1 -1
package/build/src/browser.js
CHANGED
|
@@ -13,6 +13,36 @@ import { puppeteer } from './third_party/index.js';
|
|
|
13
13
|
// Add stealth plugin
|
|
14
14
|
puppeteerExtra.use(StealthPlugin());
|
|
15
15
|
let browser;
|
|
16
|
+
/**
|
|
17
|
+
* Close the browser instance, killing the Chrome process if we launched it.
|
|
18
|
+
* Safe to call multiple times or when no browser exists.
|
|
19
|
+
*/
|
|
20
|
+
export async function closeBrowser() {
|
|
21
|
+
if (!browser) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const b = browser;
|
|
25
|
+
browser = undefined;
|
|
26
|
+
try {
|
|
27
|
+
if (b.connected) {
|
|
28
|
+
// browser.close() sends a Browser.close CDP command and kills the process
|
|
29
|
+
// if it was launched by puppeteer. For connected browsers it just disconnects.
|
|
30
|
+
await b.close();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Best-effort: if close fails, try to kill the process directly
|
|
35
|
+
try {
|
|
36
|
+
const proc = b.process();
|
|
37
|
+
if (proc && !proc.killed) {
|
|
38
|
+
proc.kill('SIGKILL');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Nothing more we can do
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
16
46
|
function makeTargetFilter() {
|
|
17
47
|
const ignoredPrefixes = new Set([
|
|
18
48
|
'chrome://',
|
|
@@ -125,7 +155,7 @@ export async function launch(options) {
|
|
|
125
155
|
];
|
|
126
156
|
const ignoreDefaultArgs = options.stealth
|
|
127
157
|
? [...(options.ignoreDefaultChromeArgs ?? []), '--enable-automation']
|
|
128
|
-
: options.ignoreDefaultChromeArgs ?? false;
|
|
158
|
+
: (options.ignoreDefaultChromeArgs ?? false);
|
|
129
159
|
// Add stealth-enhancing arguments if stealth mode is enabled
|
|
130
160
|
if (options.stealth) {
|
|
131
161
|
args.push('--disable-blink-features=AutomationControlled', '--disable-features=IsolateOrigins,site-per-process', '--no-first-run', '--no-service-autorun', '--password-store=basic');
|
package/build/src/main.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import './polyfill.js';
|
|
7
7
|
import process from 'node:process';
|
|
8
|
-
import { ensureBrowserConnected, ensureBrowserLaunched } from './browser.js';
|
|
8
|
+
import { closeBrowser, ensureBrowserConnected, ensureBrowserLaunched } from './browser.js';
|
|
9
9
|
import { cliOptions, parseArguments } from './cli.js';
|
|
10
10
|
import { loadIssueDescriptions } from './issue-descriptions.js';
|
|
11
11
|
import { logger, saveLogsToFile } from './logger.js';
|
|
@@ -20,7 +20,7 @@ import { ToolCategory } from './tools/categories.js';
|
|
|
20
20
|
import { tools } from './tools/tools.js';
|
|
21
21
|
// If moved update release-please config
|
|
22
22
|
// x-release-please-start-version
|
|
23
|
-
const VERSION = '0.17.
|
|
23
|
+
const VERSION = '0.17.4';
|
|
24
24
|
// x-release-please-end
|
|
25
25
|
export const args = parseArguments(VERSION);
|
|
26
26
|
const logFile = args.logFile ? saveLogsToFile(args.logFile) : undefined;
|
|
@@ -53,7 +53,10 @@ server.server.setRequestHandler(SetLevelRequestSchema, () => {
|
|
|
53
53
|
});
|
|
54
54
|
let context;
|
|
55
55
|
async function getContext() {
|
|
56
|
-
const chromeArgs =
|
|
56
|
+
const chromeArgs = [
|
|
57
|
+
...(args.chromeArg ?? []).map(String),
|
|
58
|
+
...(args.chromeArgs ?? []).map(String),
|
|
59
|
+
];
|
|
57
60
|
const ignoreDefaultChromeArgs = (args.ignoreDefaultChromeArg ?? []).map(String);
|
|
58
61
|
if (args.proxyServer) {
|
|
59
62
|
chromeArgs.push(`--proxy-server=${args.proxyServer}`);
|
|
@@ -192,6 +195,43 @@ await loadIssueDescriptions();
|
|
|
192
195
|
const transport = new StdioServerTransport();
|
|
193
196
|
await server.connect(transport);
|
|
194
197
|
logger('Chrome DevTools MCP Server connected');
|
|
198
|
+
// Graceful shutdown: kill Chrome when the MCP server exits for any reason.
|
|
199
|
+
let shuttingDown = false;
|
|
200
|
+
async function gracefulShutdown(reason) {
|
|
201
|
+
if (shuttingDown) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
shuttingDown = true;
|
|
205
|
+
logger(`Shutting down: ${reason}`);
|
|
206
|
+
try {
|
|
207
|
+
context?.dispose();
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// best-effort
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
await closeBrowser();
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// best-effort
|
|
217
|
+
}
|
|
218
|
+
logger('Shutdown complete');
|
|
219
|
+
process.exit(0);
|
|
220
|
+
}
|
|
221
|
+
// Handle OS signals (container stop, systemd, Ctrl+C)
|
|
222
|
+
for (const signal of ['SIGTERM', 'SIGINT', 'SIGHUP']) {
|
|
223
|
+
process.on(signal, () => {
|
|
224
|
+
void gracefulShutdown(`received ${signal}`);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
// Handle MCP client disconnect (transport/server close)
|
|
228
|
+
server.server.onclose = () => {
|
|
229
|
+
void gracefulShutdown('MCP client disconnected');
|
|
230
|
+
};
|
|
231
|
+
// Handle stdin closing (parent process died)
|
|
232
|
+
process.stdin.on('close', () => {
|
|
233
|
+
void gracefulShutdown('stdin closed');
|
|
234
|
+
});
|
|
195
235
|
logDisclaimers();
|
|
196
236
|
void clearcutLogger?.logDailyActiveIfNeeded();
|
|
197
237
|
void clearcutLogger?.logServerStart(computeFlagUsage(args, cliOptions));
|