File size: 6,350 Bytes
f044ea5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
// MCP 服务器管理器
import { spawn } from 'child_process';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const MCP_SERVERS_DIR = path.join(__dirname, 'mcp-servers');

// 确保 MCP 服务器目录存在
if (!fs.existsSync(MCP_SERVERS_DIR)) {
  fs.mkdirSync(MCP_SERVERS_DIR, { recursive: true });
}

// 存储运行中的 MCP 服务器进程
const runningServers = new Map();

/**
 * 获取可用的内置 MCP 服务器列表
 */
export function getAvailableMcpServers() {
  try {
    // 读取 mcp-servers 目录中的所有 .js 文件
    const files = fs.readdirSync(MCP_SERVERS_DIR).filter(file => file.endsWith('.js'));
    
    return files.map(file => {
      const name = file.replace('.js', '');
      const isRunning = runningServers.has(name);
      
      return {
        id: name,
        name: formatServerName(name),
        description: `Built-in MCP server: ${formatServerName(name)}`,
        isBuiltIn: true,
        isRunning
      };
    });
  } catch (error) {
    console.error('Error getting available MCP servers:', error);
    return [];
  }
}

/**
 * 格式化服务器名称,将连字符和下划线替换为空格,并将每个单词首字母大写
 */
function formatServerName(name) {
  return name
    .replace(/[-_]/g, ' ')
    .replace(/\w\S*/g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
}

/**
 * 启动 MCP 服务器
 * @param {string} serverId - 服务器 ID
 * @returns {Promise<{success: boolean, port: number, error: string|null}>}
 */
export async function startMcpServer(serverId) {
  try {
    // 如果服务器已经在运行,返回成功
    if (runningServers.has(serverId)) {
      const serverInfo = runningServers.get(serverId);
      return { 
        success: true, 
        port: serverInfo.port,
        error: null
      };
    }
    
    // 检查服务器文件是否存在
    const serverFile = path.join(MCP_SERVERS_DIR, `${serverId}.js`);
    if (!fs.existsSync(serverFile)) {
      return { 
        success: false, 
        port: null,
        error: `Server file not found: ${serverFile}`
      };
    }
    
    // 分配一个端口(这里简单地使用 8000-8999 范围内的随机端口)
    const port = 8000 + Math.floor(Math.random() * 1000);
    
    // 启动服务器进程
    const serverProcess = spawn('node', [serverFile], {
      env: { ...process.env, PORT: port.toString() },
      detached: true
    });
    
    // 等待服务器启动
    const startPromise = new Promise((resolve, reject) => {
      let output = '';
      let errorOutput = '';
      
      serverProcess.stdout.on('data', (data) => {
        output += data.toString();
        if (output.includes('MCP server running')) {
          resolve();
        }
      });
      
      serverProcess.stderr.on('data', (data) => {
        errorOutput += data.toString();
        console.error(`MCP server ${serverId} error:`, data.toString());
      });
      
      serverProcess.on('error', (error) => {
        reject(new Error(`Failed to start MCP server: ${error.message}`));
      });
      
      serverProcess.on('exit', (code) => {
        if (code !== 0 && !output.includes('MCP server running')) {
          reject(new Error(`MCP server exited with code ${code}: ${errorOutput}`));
        }
      });
      
      // 设置超时
      setTimeout(() => {
        if (!output.includes('MCP server running')) {
          reject(new Error('Timeout waiting for MCP server to start'));
        }
      }, 5000);
    });
    
    try {
      await startPromise;
      
      // 存储服务器信息
      runningServers.set(serverId, {
        process: serverProcess,
        port
      });
      
      console.log(`MCP server ${serverId} started on port ${port}`);
      
      return { 
        success: true, 
        port,
        error: null
      };
    } catch (error) {
      // 如果启动失败,杀死进程
      serverProcess.kill();
      return { 
        success: false, 
        port: null,
        error: error.message
      };
    }
  } catch (error) {
    console.error(`Error starting MCP server ${serverId}:`, error);
    return { 
      success: false, 
      port: null,
      error: error.message
    };
  }
}

/**
 * 停止 MCP 服务器
 * @param {string} serverId - 服务器 ID
 * @returns {Promise<{success: boolean, error: string|null}>}
 */
export async function stopMcpServer(serverId) {
  try {
    if (!runningServers.has(serverId)) {
      return { 
        success: false, 
        error: `Server ${serverId} is not running`
      };
    }
    
    const serverInfo = runningServers.get(serverId);
    
    // 杀死进程
    serverInfo.process.kill();
    runningServers.delete(serverId);
    
    console.log(`MCP server ${serverId} stopped`);
    
    return { 
      success: true, 
      error: null
    };
  } catch (error) {
    console.error(`Error stopping MCP server ${serverId}:`, error);
    return { 
      success: false, 
      error: error.message
    };
  }
}

/**
 * 获取 MCP 服务器状态
 * @param {string} serverId - 服务器 ID
 * @returns {{isRunning: boolean, port: number|null}}
 */
export function getMcpServerStatus(serverId) {
  if (runningServers.has(serverId)) {
    const serverInfo = runningServers.get(serverId);
    return {
      isRunning: true,
      port: serverInfo.port
    };
  }
  
  return {
    isRunning: false,
    port: null
  };
}

/**
 * 停止所有运行中的 MCP 服务器
 */
export function stopAllMcpServers() {
  for (const [serverId, serverInfo] of runningServers.entries()) {
    try {
      serverInfo.process.kill();
      console.log(`MCP server ${serverId} stopped`);
    } catch (error) {
      console.error(`Error stopping MCP server ${serverId}:`, error);
    }
  }
  
  runningServers.clear();
}

// 确保在进程退出时停止所有 MCP 服务器
process.on('exit', () => {
  stopAllMcpServers();
});

// 处理未捕获的异常
process.on('uncaughtException', (error) => {
  console.error('Uncaught exception:', error);
  stopAllMcpServers();
  process.exit(1);
});

// 处理未处理的 Promise 拒绝
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled rejection at:', promise, 'reason:', reason);
});