index.ts•4.87 kB
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { exec } from "child_process";
import { promisify } from "util";
// import { startWebServer } from "./web-server.js"; // 不再自动启动Web服务器
const execAsync = promisify(exec);
// 通过HTTP API等待页面数据
async function waitForPageDataViaAPI(timeoutMs: number = 10000): Promise<any> {
try {
const response = await fetch('http://localhost:3003/api/wait-for-data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ timeoutMs })
});
console.error(`HTTP响应状态: ${response.status} ${response.statusText}`);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP请求失败 (${response.status}): ${errorText}`);
}
const result = await response.json();
console.error('解析的结果:', result);
if (result.success) {
return result.data;
} else {
throw new Error(result.message || '等待数据失败');
}
} catch (error) {
throw new Error(`HTTP API调用失败: ${error instanceof Error ? error.message : '未知错误'}`);
}
}
// Create an MCP server
const server = new McpServer({
name: "demo-server",
version: "1.0.0"
});
// Add an addition tool
server.registerTool("add",
{
title: "Addition Tool",
description: "Add two numbers",
inputSchema: { a: z.number(), b: z.number() }
},
async ({ a, b }: { a: number; b: number }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// Add a web browser tool
server.registerTool("open_web_page",
{
title: "打开网页",
description: "在IDE中打开一个新的网页窗口显示指定的URL,并自动等待接收页面发送的WebSocket数据",
inputSchema: {
url: z.string().url("请提供有效的URL地址"),
waitForData: z.boolean().optional().describe("是否等待页面发送数据,默认为true"),
timeoutMs: z.number().optional().describe("等待数据的超时时间(毫秒),默认10秒")
}
},
async ({ url, waitForData = true, timeoutMs = 10000 }: {
url: string;
waitForData?: boolean | undefined;
timeoutMs?: number | undefined;
}) => {
try {
let command: string;
// 根据操作系统选择合适的命令
if (process.platform === 'win32') {
// Windows: 使用cmd /c start来确保正确打开浏览器
command = `cmd /c start "" "${url}"`;
} else if (process.platform === 'darwin') {
command = `open "${url}"`;
} else {
command = `xdg-open "${url}"`;
}
await execAsync(command);
if (!waitForData) {
return {
content: [{
type: "text",
text: `成功打开网页: ${url}`
}]
};
}
// 给页面一些时间来加载和建立WebSocket连接
console.error("⏳ 等待页面加载并建立WebSocket连接...");
await new Promise(resolve => setTimeout(resolve, 2000));
// 等待页面发送数据
try {
console.error(`🔍 等待页面 ${url} 发送数据,超时时间: ${timeoutMs}ms`);
const receivedData = await waitForPageDataViaAPI(timeoutMs);
return {
content: [{
type: "text",
text: `成功打开网页并接收到数据: ${url}\n\n接收到的数据:\n${JSON.stringify(receivedData, null, 2)}`
}]
};
} catch (dataError) {
// 如果等待数据超时,仍然返回成功打开页面的消息
return {
content: [{
type: "text",
text: `成功打开网页: ${url}\n\n等待数据时出现问题: ${dataError instanceof Error ? dataError.message : '未知错误'}`
}]
};
}
} catch (error) {
return {
content: [{
type: "text",
text: `打开网页失败: ${error instanceof Error ? error.message : '未知错误'}`
}]
};
}
}
);
// Add a dynamic greeting resource
server.registerResource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
{
title: "Greeting Resource", // Display name for UI
description: "Dynamic greeting generator"
},
async (uri: { href: any; }, { name }: any) => ({
contents: [{
uri: uri.href,
text: `Hello, ${name}!`
}]
})
);
// 注意:需要单独启动Web服务器: npm run start:web
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);