豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit a8bf3e5

Browse files
authored
refactor: move server to a separate file (#1043)
Refs #1038 by importing server.ts and calling calling `createMcpServer` the server can be instantiated without a transport.
1 parent 9ddb7da commit a8bf3e5

File tree

3 files changed

+237
-209
lines changed

3 files changed

+237
-209
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "MCP server for Chrome DevTools",
55
"type": "module",
66
"bin": "./build/src/index.js",
7-
"main": "index.js",
7+
"main": "./build/src/server.js",
88
"scripts": {
99
"clean": "node -e \"require('fs').rmSync('build', {recursive: true, force: true})\"",
1010
"bundle": "npm run clean && npm run build && rollup -c rollup.config.mjs && node -e \"require('fs').rmSync('build/node_modules', {recursive: true, force: true})\"",

src/main.ts

Lines changed: 5 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,11 @@ import './polyfill.js';
88

99
import process from 'node:process';
1010

11-
import type {Channel} from './browser.js';
12-
import {ensureBrowserConnected, ensureBrowserLaunched} from './browser.js';
1311
import {cliOptions, parseArguments} from './cli.js';
14-
import {loadIssueDescriptions} from './issue-descriptions.js';
1512
import {logger, saveLogsToFile} from './logger.js';
16-
import {McpContext} from './McpContext.js';
17-
import {McpResponse} from './McpResponse.js';
18-
import {Mutex} from './Mutex.js';
19-
import {SlimMcpResponse} from './SlimMcpResponse.js';
20-
import {ClearcutLogger} from './telemetry/ClearcutLogger.js';
13+
import {createMcpServer} from './server.js';
2114
import {computeFlagUsage} from './telemetry/flagUtils.js';
22-
import {bucketizeLatency} from './telemetry/metricUtils.js';
23-
import {
24-
McpServer,
25-
StdioServerTransport,
26-
type CallToolResult,
27-
SetLevelRequestSchema,
28-
} from './third_party/index.js';
29-
import {ToolCategory} from './tools/categories.js';
30-
import type {ToolDefinition} from './tools/ToolDefinition.js';
31-
import {createTools} from './tools/tools.js';
15+
import {StdioServerTransport} from './third_party/index.js';
3216
import {VERSION} from './version.js';
3317

3418
export const args = parseArguments(VERSION);
@@ -44,81 +28,13 @@ if (
4428
args.usageStatistics = false;
4529
}
4630

47-
let clearcutLogger: ClearcutLogger | undefined;
48-
if (args.usageStatistics) {
49-
clearcutLogger = new ClearcutLogger({
50-
logFile: args.logFile,
51-
appVersion: VERSION,
52-
clearcutEndpoint: args.clearcutEndpoint,
53-
clearcutForceFlushIntervalMs: args.clearcutForceFlushIntervalMs,
54-
clearcutIncludePidHeader: args.clearcutIncludePidHeader,
55-
});
56-
}
57-
5831
if (process.env['CHROME_DEVTOOLS_MCP_CRASH_ON_UNCAUGHT'] !== 'true') {
5932
process.on('unhandledRejection', (reason, promise) => {
6033
logger('Unhandled promise rejection', promise, reason);
6134
});
6235
}
6336

6437
logger(`Starting Chrome DevTools MCP Server v${VERSION}`);
65-
const server = new McpServer(
66-
{
67-
name: 'chrome_devtools',
68-
title: 'Chrome DevTools MCP server',
69-
version: VERSION,
70-
},
71-
{capabilities: {logging: {}}},
72-
);
73-
server.server.setRequestHandler(SetLevelRequestSchema, () => {
74-
return {};
75-
});
76-
77-
let context: McpContext;
78-
async function getContext(): Promise<McpContext> {
79-
const chromeArgs: string[] = (args.chromeArg ?? []).map(String);
80-
const ignoreDefaultChromeArgs: string[] = (
81-
args.ignoreDefaultChromeArg ?? []
82-
).map(String);
83-
if (args.proxyServer) {
84-
chromeArgs.push(`--proxy-server=${args.proxyServer}`);
85-
}
86-
const devtools = args.experimentalDevtools ?? false;
87-
const browser =
88-
args.browserUrl || args.wsEndpoint || args.autoConnect
89-
? await ensureBrowserConnected({
90-
browserURL: args.browserUrl,
91-
wsEndpoint: args.wsEndpoint,
92-
wsHeaders: args.wsHeaders,
93-
// Important: only pass channel, if autoConnect is true.
94-
channel: args.autoConnect ? (args.channel as Channel) : undefined,
95-
userDataDir: args.userDataDir,
96-
devtools,
97-
})
98-
: await ensureBrowserLaunched({
99-
headless: args.headless,
100-
executablePath: args.executablePath,
101-
channel: args.channel as Channel,
102-
isolated: args.isolated ?? false,
103-
userDataDir: args.userDataDir,
104-
logFile,
105-
viewport: args.viewport,
106-
chromeArgs,
107-
ignoreDefaultChromeArgs,
108-
acceptInsecureCerts: args.acceptInsecureCerts,
109-
devtools,
110-
enableExtensions: args.categoryExtensions,
111-
});
112-
113-
if (context?.browser !== browser) {
114-
context = await McpContext.from(browser, logger, {
115-
experimentalDevToolsDebugging: devtools,
116-
experimentalIncludeAllPages: args.experimentalIncludeAllPages,
117-
performanceCrux: args.performanceCrux,
118-
});
119-
}
120-
return context;
121-
}
12238

12339
const logDisclaimers = () => {
12440
console.error(
@@ -142,128 +58,9 @@ For more details, visit: https://github.com/ChromeDevTools/chrome-devtools-mcp#u
14258
}
14359
};
14460

145-
const toolMutex = new Mutex();
146-
147-
function registerTool(tool: ToolDefinition): void {
148-
if (
149-
tool.annotations.category === ToolCategory.EMULATION &&
150-
args.categoryEmulation === false
151-
) {
152-
return;
153-
}
154-
if (
155-
tool.annotations.category === ToolCategory.PERFORMANCE &&
156-
args.categoryPerformance === false
157-
) {
158-
return;
159-
}
160-
if (
161-
tool.annotations.category === ToolCategory.NETWORK &&
162-
args.categoryNetwork === false
163-
) {
164-
return;
165-
}
166-
if (
167-
tool.annotations.category === ToolCategory.EXTENSIONS &&
168-
args.categoryExtensions === false
169-
) {
170-
return;
171-
}
172-
if (
173-
tool.annotations.conditions?.includes('computerVision') &&
174-
!args.experimentalVision
175-
) {
176-
return;
177-
}
178-
if (
179-
tool.annotations.conditions?.includes('experimentalInteropTools') &&
180-
!args.experimentalInteropTools
181-
) {
182-
return;
183-
}
184-
if (
185-
tool.annotations.conditions?.includes('screencast') &&
186-
!args.experimentalScreencast
187-
) {
188-
return;
189-
}
190-
server.registerTool(
191-
tool.name,
192-
{
193-
description: tool.description,
194-
inputSchema: tool.schema,
195-
annotations: tool.annotations,
196-
},
197-
async (params): Promise<CallToolResult> => {
198-
const guard = await toolMutex.acquire();
199-
const startTime = Date.now();
200-
let success = false;
201-
try {
202-
logger(`${tool.name} request: ${JSON.stringify(params, null, ' ')}`);
203-
const context = await getContext();
204-
logger(`${tool.name} context: resolved`);
205-
await context.detectOpenDevToolsWindows();
206-
const response = args.slim
207-
? new SlimMcpResponse(args)
208-
: new McpResponse(args);
209-
210-
await tool.handler(
211-
{
212-
params,
213-
},
214-
response,
215-
context,
216-
);
217-
const {content, structuredContent} = await response.handle(
218-
tool.name,
219-
context,
220-
);
221-
const result: CallToolResult & {
222-
structuredContent?: Record<string, unknown>;
223-
} = {
224-
content,
225-
};
226-
success = true;
227-
if (args.experimentalStructuredContent) {
228-
result.structuredContent = structuredContent as Record<
229-
string,
230-
unknown
231-
>;
232-
}
233-
return result;
234-
} catch (err) {
235-
logger(`${tool.name} error:`, err, err?.stack);
236-
let errorText = err && 'message' in err ? err.message : String(err);
237-
if ('cause' in err && err.cause) {
238-
errorText += `\nCause: ${err.cause.message}`;
239-
}
240-
return {
241-
content: [
242-
{
243-
type: 'text',
244-
text: errorText,
245-
},
246-
],
247-
isError: true,
248-
};
249-
} finally {
250-
void clearcutLogger?.logToolInvocation({
251-
toolName: tool.name,
252-
success,
253-
latencyMs: bucketizeLatency(Date.now() - startTime),
254-
});
255-
guard.dispose();
256-
}
257-
},
258-
);
259-
}
260-
261-
const tools = createTools(args);
262-
for (const tool of tools) {
263-
registerTool(tool);
264-
}
265-
266-
await loadIssueDescriptions();
61+
const {server, clearcutLogger} = await createMcpServer(args, {
62+
logFile,
63+
});
26764
const transport = new StdioServerTransport();
26865
await server.connect(transport);
26966
logger('Chrome DevTools MCP Server connected');

0 commit comments

Comments
 (0)