browser-tools-mcp源码解析:mcp-server.ts中的协议处理核心逻辑
引言
在现代Web开发中,开发者需要高效地监控和调试浏览器行为。browser-tools-mcp项目通过MCP(Model Context Protocol)协议,允许开发者直接从兼容MCP的IDE中监控浏览器日志。本文将深入解析该项目核心文件mcp-server.ts中的协议处理逻辑,帮助开发者理解其工作原理并进行二次开发。
MCP服务器初始化
mcp-server.ts的核心功能是创建MCP服务器并实现与浏览器工具的通信协议。让我们从服务器初始化开始分析:
// Create the MCP server
const server = new McpServer({
name: "Browser Tools MCP",
version: "1.2.0",
});
这段代码初始化了一个MCP服务器实例,指定了服务器名称和版本号。MCP(Model Context Protocol)是一种允许IDE与各种工具通信的协议,通过标准化的接口实现不同工具之间的数据交换。
服务器发现机制
在MCP服务器与浏览器工具通信之前,需要先发现并建立连接。mcp-server.ts实现了一套完整的服务器发现机制:
// Server discovery function
async function discoverServer(): Promise<boolean> {
console.log("Starting server discovery process");
// Common hosts to try
const hosts = [getDefaultServerHost(), "127.0.0.1", "localhost"];
// Ports to try (start with default, then try others)
const defaultPort = getDefaultServerPort();
const ports = [defaultPort];
// Add additional ports (fallback range)
for (let p = 3025; p <= 3035; p++) {
if (p !== defaultPort) {
ports.push(p);
}
}
// Try to find the server
for (const host of hosts) {
for (const port of ports) {
try {
console.log(`Checking ${host}:${port}...`);
// Use the identity endpoint for validation
const response = await fetch(`http://${host}:${port}/.identity`, {
signal: AbortSignal.timeout(1000), // 1 second timeout
});
if (response.ok) {
const identity = await response.json();
// Verify this is actually our server by checking the signature
if (identity.signature === "mcp-browser-connector-24x7") {
console.log(`Successfully found server at ${host}:${port}`);
// Save the discovered connection
discoveredHost = host;
discoveredPort = port;
serverDiscovered = true;
return true;
}
}
} catch (error: any) {
// Ignore connection errors during discovery
console.error(`Error checking ${host}:${port}: ${error.message}`);
}
}
}
console.error("No server found during discovery");
return false;
}
服务器发现流程
服务器发现机制的工作流程如下:
- 首先尝试从环境变量或.port文件获取默认主机和端口
- 定义要尝试连接的主机列表(默认主机、127.0.0.1、localhost)
- 定义要尝试的端口范围(默认端口+3025-3035范围内的其他端口)
- 对每个主机和端口组合尝试连接
- 通过访问/.identity端点验证服务器身份
- 检查返回的签名是否匹配预期值"mcp-browser-connector-24x7"
- 成功发现后保存连接信息并返回
这种多主机、多端口的探测机制提高了服务器发现的可靠性,确保在不同配置环境下都能成功建立连接。
连接管理与请求封装
为了确保所有API调用都在服务器连接建立后执行,mcp-server.ts实现了一个连接管理包装函数:
// Wrapper function to ensure server connection before making requests
async function withServerConnection<T>(
apiCall: () => Promise<T>
): Promise<T | any> {
// Attempt to discover server if not already discovered
if (!serverDiscovered) {
const discovered = await discoverServer();
if (!discovered) {
return {
content: [
{
type: "text",
text: "Failed to discover browser connector server. Please ensure it's running.",
},
],
isError: true,
};
}
}
// Now make the actual API call with discovered host/port
try {
return await apiCall();
} catch (error: any) {
// If the request fails, try rediscovering the server once
console.error(
`API call failed: ${error.message}. Attempting rediscovery...`
);
serverDiscovered = false;
if (await discoverServer()) {
console.error("Rediscovery successful. Retrying API call...");
try {
// Retry the API call with the newly discovered connection
return await apiCall();
} catch (retryError: any) {
console.error(`Retry failed: ${retryError.message}`);
return {
content: [
{
type: "text",
text: `Error after reconnection attempt: ${retryError.message}`,
},
],
isError: true,
};
}
} else {
console.error("Rediscovery failed. Could not reconnect to server.");
return {
content: [
{
type: "text",
text: `Failed to reconnect to server: ${error.message}`,
},
],
isError: true,
};
}
}
}
withServerConnection函数的核心功能
这个高阶函数提供了以下关键特性:
- 连接前置检查:在执行API调用前确保服务器已被发现
- 自动重连机制:当API调用失败时,自动尝试重新发现服务器并重试
- 错误处理:统一的错误响应格式,便于客户端处理
这种设计确保了所有与浏览器工具的通信都具备可靠的连接保障,即使在网络不稳定或服务器重启的情况下也能自动恢复。
MCP工具定义与协议实现
mcp-server.ts的核心功能是通过定义一系列MCP工具来实现与浏览器的交互协议。每个工具对应一个特定的浏览器操作或信息获取功能。
基础日志工具
以下是几个基础日志相关工具的定义:
// 获取控制台日志
server.tool("getConsoleLogs", "Check our browser logs", async () => {
return await withServerConnection(async () => {
const response = await fetch(
`http://${discoveredHost}:${discoveredPort}/console-logs`
);
const json = await response.json();
return {
content: [
{
type: "text",
text: JSON.stringify(json, null, 2),
},
],
};
});
});
// 获取控制台错误
server.tool(
"getConsoleErrors",
"Check our browsers console errors",
async () => {
return await withServerConnection(async () => {
const response = await fetch(
`http://${discoveredHost}:${discoveredPort}/console-errors`
);
const json = await response.json();
return {
content: [
{
type: "text",
text: JSON.stringify(json, null, 2),
},
],
};
});
}
);
// 获取网络错误日志
server.tool("getNetworkErrors", "Check our network ERROR logs", async () => {
return await withServerConnection(async () => {
const response = await fetch(
`http://${discoveredHost}:${discoveredPort}/network-errors`
);
const json = await response.json();
return {
content: [
{
type: "text",
text: JSON.stringify(json, null, 2),
},
],
isError: true,
};
});
});
这些工具实现了基本的日志获取功能,通过HTTP请求从浏览器连接器获取不同类型的日志数据,并将结果格式化为MCP协议要求的响应格式。
高级检测工具
mcp-server.ts还实现了更复杂的网页检测功能,如可访问性检测、性能检测和SEO检测等:
// 可访问性检测工具
server.tool(
"runAccessibilityCheck",
"Run an accessibility check on the current page",
{},
async () => {
return await withServerConnection(async () => {
try {
// Simplified approach - let the browser connector handle the current tab and URL
console.log(
`Sending POST request to http://${discoveredHost}:${discoveredPort}/accessibility-check`
);
const response = await fetch(
`http://${discoveredHost}:${discoveredPort}/accessibility-check`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
category: CheckCategory.ACCESSIBILITY,
source: "mcp_tool",
timestamp: Date.now(),
}),
}
);
// Log the response status
console.log(`Accessibility check response status: ${response.status}`);
if (!response.ok) {
const errorText = await response.text();
console.error(`Accessibility check error: ${errorText}`);
throw new Error(`Server returned ${response.status}: ${errorText}`);
}
const json = await response.json();
// flatten it by merging metadata with the report contents
if (json.report) {
const { metadata, report } = json;
const flattened = {
...metadata,
...report,
};
return {
content: [
{
type: "text",
text: JSON.stringify(flattened, null, 2),
},
],
};
} else {
// Return as-is if it's not in the new format
return {
content: [
{
type: "text",
text: JSON.stringify(json, null, 2),
},
],
};
}
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error("Error in accessibility check:", errorMessage);
return {
content: [
{
type: "text",
text: `Failed to run accessibility check: ${errorMessage}`,
},
],
};
}
});
}
);
检测工具的协议设计
检测工具的协议设计比基础日志工具更复杂,包含以下特点:
- 使用POST方法:传递更复杂的检测参数
- 结构化请求体:包含检测类别、来源和时间戳
- 响应处理:支持不同版本的响应格式,兼容新旧服务器实现
- 详细错误处理:捕获并返回检测过程中的各种可能错误
协议处理流程分析
为了更清晰地理解mcp-server.ts中的协议处理逻辑,我们可以通过流程图来展示整个过程:
关键协议交互点
从上述流程图中可以看出,整个协议处理过程有几个关键交互点:
- 服务器发现:确保MCP服务器能找到浏览器连接器
- 连接管理:保证所有API调用都有有效的服务器连接
- 工具调用:实现具体的浏览器操作协议
- 错误恢复:处理连接中断和服务器不可用的情况
数据格式与协议规范
mcp-server.ts中实现的MCP协议遵循特定的数据格式规范,确保与客户端的互操作性。
响应格式
所有工具调用都返回统一的响应格式:
{
content: [
{
type: "text",
text: "响应内容,通常是JSON字符串"
}
],
isError?: boolean // 可选,指示是否为错误响应
}
这种统一的格式使得客户端可以一致地处理各种工具的返回结果,无论是日志数据、检测报告还是错误信息。
检测请求协议
以可访问性检测为例,请求协议包含以下字段:
{
category: CheckCategory.ACCESSIBILITY, // 检测类别
source: "mcp_tool", // 请求来源标识
timestamp: Date.now() // 请求时间戳
}
这种结构化的请求格式使得浏览器连接器能够正确识别和处理不同类型的检测请求。
扩展性设计
mcp-server.ts的设计考虑了良好的扩展性,使得添加新的MCP工具变得简单。通过分析现有工具的实现,我们可以总结出添加新工具的标准步骤:
添加新MCP工具的步骤
- 使用
server.tool()方法注册新工具,指定工具名称和描述 - 在工具实现中使用
withServerConnection包装API调用 - 构造适当的HTTP请求与浏览器连接器通信
- 处理响应并格式化为标准的MCP响应格式
- 添加适当的错误处理逻辑
这种模块化设计确保了代码的可维护性和可扩展性,符合开源项目的最佳实践。
总结
mcp-server.ts作为browser-tools-mcp项目的核心文件,实现了MCP协议与浏览器工具的通信逻辑。通过深入分析其源代码,我们可以看到其设计的几个关键特点:
- 可靠的连接管理:多主机多端口的服务器发现机制,配合自动重连逻辑,确保了连接的可靠性
- 模块化工具设计:每个功能点被封装为独立的MCP工具,便于维护和扩展
- 统一的协议格式:标准化的请求和响应格式,确保了与客户端的兼容性
- 健壮的错误处理:全面的错误捕获和恢复机制,提升了系统的稳定性
这些设计特点共同构成了一个高效、可靠的浏览器监控协议实现,为开发者提供了从IDE直接监控浏览器行为的强大能力。
对于希望扩展此项目的开发者,可以参考本文分析的协议处理逻辑,遵循现有的模块化设计原则,添加新的MCP工具来扩展项目功能。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



