browser-tools-mcp与TypeScript完美结合:强类型保障下的工具开发流程
browser-tools-mcp与TypeScript完美结合:强类型保障下的工具开发流程
引言
在现代前端开发中,工具链的可靠性和开发效率至关重要。browser-tools-mcp作为一个创新的浏览器工具集成方案,允许开发者直接从Cursor等MCP兼容IDE中监控浏览器日志。本文将深入探讨如何利用TypeScript的强类型特性,构建稳定、可维护的browser-tools-mcp工具,确保开发过程中的类型安全和代码质量。
项目概述
browser-tools-mcp(Model Context Protocol浏览器工具)是一个允许开发者直接从兼容MCP的IDE(如Cursor)中监控浏览器日志的工具集。该项目采用TypeScript开发,通过强类型系统提供了更可靠的开发体验和更健壮的代码质量。
项目主要包含以下模块:
- browser-tools-mcp: MCP服务器核心实现
- browser-tools-server: 浏览器连接和日志处理服务
- chrome-extension: 浏览器扩展,用于收集和发送日志
- docs: 项目文档
环境准备与项目搭建
开发环境要求
- Node.js 16.x或更高版本
- npm 7.x或更高版本
- TypeScript 5.0+
- Git
项目克隆与安装
# 克隆项目仓库
git clone https://gitcode.com/gh_mirrors/br/browser-tools-mcp
# 进入项目目录
cd browser-tools-mcp
# 安装mcp模块依赖
cd browser-tools-mcp
npm install
# 安装server模块依赖
cd ../browser-tools-server
npm install
TypeScript配置详解
browser-tools-mcp项目采用了严格的TypeScript配置,确保代码质量和类型安全。让我们深入分析核心的tsconfig.json配置:
browser-tools-mcp/tsconfig.json
{
"compilerOptions": {
"target": "ES2020", // 编译目标为ES2020
"module": "NodeNext", // 使用NodeNext模块系统
"moduleResolution": "NodeNext", // 匹配NodeNext模块解析
"esModuleInterop": true, // 启用ES模块互操作性
"outDir": "./dist", // 输出目录
"rootDir": ".", // 源代码根目录
"strict": true, // 启用所有严格类型检查选项
"skipLibCheck": true, // 跳过库文件检查
"forceConsistentCasingInFileNames": true // 强制文件名大小写一致
},
"include": ["*.ts"], // 包含的文件
"exclude": ["node_modules", "dist"] // 排除的目录
}
browser-tools-server/tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": ".",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true // 额外支持JSON模块解析
},
"include": ["**/*.ts"], // 包含所有子目录下的TS文件
"exclude": ["node_modules", "dist"]
}
关键配置项解析
| 配置项 | 作用 | 重要性 |
|---|---|---|
"strict": true |
启用所有严格类型检查选项,包括noImplicitAny、strictNullChecks等 | ★★★★★ |
"target": "ES2020" |
指定ECMAScript目标版本,平衡兼容性和新特性 | ★★★★☆ |
"moduleResolution": "NodeNext" |
使用最新的Node.js模块解析策略 | ★★★★☆ |
"forceConsistentCasingInFileNames" |
确保文件名大小写一致,避免跨平台问题 | ★★★☆☆ |
"resolveJsonModule": true |
允许导入JSON文件并自动生成类型 | ★★★☆☆ |
强类型开发流程
1. 类型定义与接口设计
在browser-tools-mcp项目中,良好的类型定义是确保系统稳定性的基础。以下是一个典型的类型定义示例:
// 假设在browser-tools-server/lighthouse/types.ts中
export interface LighthouseResult {
performance: number;
accessibility: number;
bestPractices: number;
seo: number;
firstContentfulPaint: number;
largestContentfulPaint: number;
timeToInteractive: number;
// 其他性能指标...
}
export interface AuditOptions {
url: string;
device?: 'mobile' | 'desktop';
throttling?: boolean;
logLevel?: 'info' | 'warn' | 'error';
}
export type AuditResultCallback = (result: LighthouseResult | Error) => void;
2. 类实现与强类型约束
利用TypeScript的类和接口特性,可以构建清晰的模块结构:
// 假设在browser-tools-server/puppeteer-service.ts中
import { Browser, Page, launch } from 'puppeteer';
import { AuditOptions, LighthouseResult, AuditResultCallback } from './lighthouse/types';
export class PuppeteerService {
private browser: Browser | null = null;
private pages: Map<string, Page> = new Map();
async initialize(): Promise<void> {
this.browser = await launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
}
async runLighthouseAudit(
options: AuditOptions,
callback: AuditResultCallback
): Promise<void> {
if (!this.browser) {
throw new Error('Puppeteer browser not initialized');
}
try {
// 实现审计逻辑...
const result: LighthouseResult = {
performance: 0,
accessibility: 0,
bestPractices: 0,
seo: 0,
firstContentfulPaint: 0,
largestContentfulPaint: 0,
timeToInteractive: 0
// 填充实际数据...
};
callback(result);
} catch (error) {
callback(error as Error);
}
}
async close(): Promise<void> {
if (this.browser) {
await this.browser.close();
this.browser = null;
}
this.pages.clear();
}
}
3. 模块集成与依赖注入
// 假设在browser-tools-server/index.ts中
import { PuppeteerService } from './puppeteer-service';
import { LighthouseService } from './lighthouse';
import { BrowserConnector } from './browser-connector';
export class BrowserToolsServer {
private puppeteerService: PuppeteerService;
private lighthouseService: LighthouseService;
private browserConnector: BrowserConnector;
constructor() {
this.puppeteerService = new PuppeteerService();
this.lighthouseService = new LighthouseService(this.puppeteerService);
this.browserConnector = new BrowserConnector();
}
async start(port: number): Promise<void> {
await this.puppeteerService.initialize();
await this.browserConnector.listen(port);
console.log(`Browser tools server running on port ${port}`);
}
async stop(): Promise<void> {
await this.browserConnector.close();
await this.puppeteerService.close();
}
}
4. 错误处理与类型安全
TypeScript的类型系统有助于构建更健壮的错误处理机制:
// 定义自定义错误类型
export class BrowserConnectionError extends Error {
constructor(message: string, public code: string) {
super(message);
this.name = 'BrowserConnectionError';
}
}
export class ValidationError extends Error {
constructor(message: string, public field?: string) {
super(message);
this.name = 'ValidationError';
}
}
// 使用示例
function validateAuditOptions(options: unknown): asserts options is AuditOptions {
if (typeof options !== 'object' || options === null) {
throw new ValidationError('Invalid audit options: must be an object');
}
if (typeof (options as AuditOptions).url !== 'string') {
throw new ValidationError('URL is required and must be a string', 'url');
}
// 其他验证逻辑...
}
MCP服务器实现详解
MCP(Model Context Protocol)服务器是browser-tools-mcp项目的核心组件,负责与IDE通信并提供浏览器日志监控功能。
MCP服务器架构
TypeScript实现关键部分
// 假设在browser-tools-mcp/mcp-server.ts中
import express from 'express';
import WebSocket from 'ws';
import http from 'http';
import { Server } from 'ws';
import { BrowserConnector } from '../browser-tools-server/browser-connector';
// 定义MCP消息类型
interface McpMessage {
type: 'log' | 'command' | 'response' | 'error';
id: string;
payload: any;
timestamp: number;
}
export class McpServer {
private app: express.Application;
private server: http.Server;
private wss: Server;
private browserConnector: BrowserConnector;
private port: number;
constructor(port: number = 8080) {
this.port = port;
this.app = express();
this.server = http.createServer(this.app);
this.wss = new WebSocket.Server({ server: this.server });
this.browserConnector = new BrowserConnector();
this.setupHttpRoutes();
this.setupWebSocketServer();
}
private setupHttpRoutes(): void {
this.app.use(express.json());
// 健康检查端点
this.app.get('/health', (req, res) => {
res.status(200).json({
status: 'ok',
connections: this.wss.clients.size,
browserConnections: this.browserConnector.getConnectionCount()
});
});
// 其他API端点...
}
private setupWebSocketServer(): void {
this.wss.on('connection', (ws) => {
console.log('New MCP client connected');
// 转发浏览器日志到IDE
const logHandler = (log: any) => {
const message: McpMessage = {
type: 'log',
id: Date.now().toString(),
payload: log,
timestamp: Date.now()
};
ws.send(JSON.stringify(message));
};
this.browserConnector.on('log', logHandler);
// 处理来自IDE的命令
ws.on('message', (data) => {
this.handleClientMessage(data.toString());
});
// 清理连接
ws.on('close', () => {
console.log('MCP client disconnected');
this.browserConnector.off('log', logHandler);
});
});
}
private handleClientMessage(data: string): void {
try {
const message: McpMessage = JSON.parse(data);
switch (message.type) {
case 'command':
this.handleCommand(message);
break;
// 处理其他消息类型...
default:
console.warn('Unknown message type:', message.type);
}
} catch (error) {
console.error('Error handling client message:', error);
}
}
private handleCommand(message: McpMessage): void {
// 命令处理逻辑...
switch (message.payload.command) {
case 'start-monitoring':
this.browserConnector.startMonitoring(message.payload.tabId);
break;
case 'stop-monitoring':
this.browserConnector.stopMonitoring(message.payload.tabId);
break;
case 'run-audit':
this.runLighthouseAudit(message);
break;
// 其他命令...
}
}
private async runLighthouseAudit(message: McpMessage): Promise<void> {
// 实现审计命令处理...
}
start(): void {
this.server.listen(this.port, () => {
console.log(`MCP server running on ws://localhost:${this.port}`);
});
this.browserConnector.initialize();
}
stop(): void {
this.wss.close();
this.server.close();
this.browserConnector.disconnect();
}
}
// 启动服务器
const server = new McpServer();
server.start();
构建与部署流程
构建脚本解析
browser-tools-mcp项目的package.json中定义了清晰的构建脚本:
{
"scripts": {
"inspect": "tsc && npx @modelcontextprotocol/inspector node -- dist/mcp-server.js",
"inspect-live": "npx @modelcontextprotocol/inspector npx -- @agentdeskai/browser-tools-mcp",
"build": "tsc",
"start": "tsc && node dist/mcp-server.js",
"prepublishOnly": "npm run build",
"update": "npm run build && npm version patch && npm publish"
}
}
典型构建与运行流程
# 构建项目
cd browser-tools-mcp
npm run build
# 启动MCP服务器
npm start
# 开发模式下运行并检查
npm run inspect
构建产物结构
dist/
├── mcp-server.js # 编译后的MCP服务器代码
├── mcp-server.d.ts # TypeScript类型定义文件
└── ... # 其他编译后的文件和目录
最佳实践与常见问题解决
TypeScript开发最佳实践
-
利用严格模式
- 始终启用
"strict": true配置 - 避免使用
any类型,如必须使用,添加详细注释说明原因
- 始终启用
-
模块化设计
- 按功能划分模块和文件
- 使用清晰的导入/导出结构
-
类型定义管理
- 将共享类型提取到单独的types.ts文件
- 使用接口定义数据结构,使用类型别名定义复杂类型组合
-
错误处理
- 创建自定义错误类以区分错误类型
- 使用TypeScript的类型守卫处理错误情况
常见问题与解决方案
| 问题 | 解决方案 |
|---|---|
| 类型不匹配错误 | 检查类型定义,使用类型断言或类型守卫明确类型 |
| 模块解析问题 | 确认tsconfig中的moduleResolution设置,检查导入路径大小写 |
| 第三方库类型缺失 | 安装@types/xxx类型定义包,或创建declare module声明 |
| 构建性能问题 | 使用tsconfig的exclude和include选项优化编译范围 |
| 浏览器兼容性 | 调整target选项,必要时使用polyfill |
结语
browser-tools-mcp与TypeScript的结合展示了强类型系统在工具开发中的巨大价值。通过严格的类型检查、清晰的接口设计和模块化架构,项目实现了高度的可靠性和可维护性。
本文详细介绍了从环境搭建到代码实现,再到构建部署的完整流程,展示了如何在实际项目中充分利用TypeScript的优势。无论是开发浏览器工具、MCP服务器还是其他类型的应用,这些原则和实践都能帮助开发者构建更高质量的软件。
随着项目的不断发展,browser-tools-mcp将继续利用TypeScript的新特性和最佳实践,为开发者提供更强大、更可靠的浏览器日志监控解决方案。
更多推荐

所有评论(0)