@cloudbase/cloudbase-mcp 1.7.4 → 1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -40
- package/dist/cloudbase-manager.js +112 -70
- package/dist/index.js +13 -0
- package/dist/interactive-server.js +107 -12
- package/dist/tools/database.js +600 -1
- package/dist/tools/env.js +3 -2
- package/dist/tools/functions.js +2 -2
- package/dist/tools/interactive.js +10 -27
- package/dist/utils/logger.js +6 -6
- package/dist/utils/telemetry.js +238 -0
- package/dist/utils/tool-wrapper.js +89 -0
- package/package.json +1 -1
|
@@ -17,13 +17,25 @@ export class InteractiveServer {
|
|
|
17
17
|
sessionData = new Map();
|
|
18
18
|
// 固定端口配置
|
|
19
19
|
DEFAULT_PORT = 3721;
|
|
20
|
-
FALLBACK_PORTS = [3722, 3723, 3724, 3725];
|
|
20
|
+
FALLBACK_PORTS = [3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735];
|
|
21
21
|
constructor() {
|
|
22
22
|
this.app = express();
|
|
23
23
|
this.server = http.createServer(this.app);
|
|
24
24
|
this.wss = new WebSocketServer({ server: this.server });
|
|
25
25
|
this.setupExpress();
|
|
26
26
|
this.setupWebSocket();
|
|
27
|
+
// 确保进程退出时清理资源
|
|
28
|
+
process.on('exit', () => this.cleanup());
|
|
29
|
+
process.on('SIGINT', () => this.cleanup());
|
|
30
|
+
process.on('SIGTERM', () => this.cleanup());
|
|
31
|
+
}
|
|
32
|
+
cleanup() {
|
|
33
|
+
if (this.isRunning) {
|
|
34
|
+
debug('Cleaning up interactive server resources...');
|
|
35
|
+
this.server.close();
|
|
36
|
+
this.wss.close();
|
|
37
|
+
this.isRunning = false;
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
setupExpress() {
|
|
29
41
|
this.app.use(express.json());
|
|
@@ -148,32 +160,41 @@ export class InteractiveServer {
|
|
|
148
160
|
let currentIndex = 0;
|
|
149
161
|
const tryNextPort = () => {
|
|
150
162
|
if (currentIndex >= tryPorts.length) {
|
|
151
|
-
const err = new Error(
|
|
163
|
+
const err = new Error(`All ${tryPorts.length} ports are in use (${tryPorts.join(', ')}), failed to start server`);
|
|
152
164
|
error('Server start failed', err);
|
|
153
165
|
reject(err);
|
|
154
166
|
return;
|
|
155
167
|
}
|
|
156
168
|
const portToTry = tryPorts[currentIndex];
|
|
157
169
|
currentIndex++;
|
|
158
|
-
debug(`Trying to start server on port ${portToTry}`);
|
|
159
|
-
//
|
|
170
|
+
debug(`Trying to start server on port ${portToTry} (attempt ${currentIndex}/${tryPorts.length})`);
|
|
171
|
+
// 清除之前的所有监听器
|
|
160
172
|
this.server.removeAllListeners('error');
|
|
161
|
-
this.server.
|
|
173
|
+
this.server.removeAllListeners('listening');
|
|
174
|
+
// 设置错误处理
|
|
175
|
+
const errorHandler = (err) => {
|
|
162
176
|
if (err.code === 'EADDRINUSE') {
|
|
163
177
|
warn(`Port ${portToTry} is in use, trying next port...`);
|
|
178
|
+
// 清理当前尝试
|
|
179
|
+
this.server.removeAllListeners('error');
|
|
180
|
+
this.server.removeAllListeners('listening');
|
|
164
181
|
tryNextPort();
|
|
165
182
|
}
|
|
166
183
|
else {
|
|
167
184
|
error('Server error', err);
|
|
168
185
|
reject(err);
|
|
169
186
|
}
|
|
170
|
-
}
|
|
171
|
-
|
|
187
|
+
};
|
|
188
|
+
// 设置成功监听处理
|
|
189
|
+
const listeningHandler = () => {
|
|
172
190
|
const address = this.server.address();
|
|
173
191
|
if (address && typeof address === 'object') {
|
|
174
192
|
this.port = address.port;
|
|
175
193
|
this.isRunning = true;
|
|
176
194
|
info(`Interactive server started successfully on http://localhost:${this.port}`);
|
|
195
|
+
// 移除临时监听器
|
|
196
|
+
this.server.removeListener('error', errorHandler);
|
|
197
|
+
this.server.removeListener('listening', listeningHandler);
|
|
177
198
|
resolve(this.port);
|
|
178
199
|
}
|
|
179
200
|
else {
|
|
@@ -181,19 +202,61 @@ export class InteractiveServer {
|
|
|
181
202
|
error('Server start error', err);
|
|
182
203
|
reject(err);
|
|
183
204
|
}
|
|
184
|
-
}
|
|
205
|
+
};
|
|
206
|
+
this.server.once('error', errorHandler);
|
|
207
|
+
this.server.once('listening', listeningHandler);
|
|
208
|
+
try {
|
|
209
|
+
this.server.listen(portToTry, '127.0.0.1');
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
error(`Failed to bind to port ${portToTry}:`, err);
|
|
213
|
+
tryNextPort();
|
|
214
|
+
}
|
|
185
215
|
};
|
|
186
216
|
tryNextPort();
|
|
187
217
|
});
|
|
188
218
|
}
|
|
189
219
|
async stop() {
|
|
190
|
-
if (!this.isRunning)
|
|
220
|
+
if (!this.isRunning) {
|
|
221
|
+
debug('Interactive server is not running, nothing to stop');
|
|
191
222
|
return;
|
|
192
|
-
|
|
193
|
-
|
|
223
|
+
}
|
|
224
|
+
info('Stopping interactive server...');
|
|
225
|
+
return new Promise((resolve, reject) => {
|
|
226
|
+
// 设置超时,防止无限等待
|
|
227
|
+
const timeout = setTimeout(() => {
|
|
228
|
+
warn('Server close timeout, forcing cleanup');
|
|
194
229
|
this.isRunning = false;
|
|
230
|
+
this.port = 0;
|
|
195
231
|
resolve();
|
|
196
|
-
});
|
|
232
|
+
}, 5000);
|
|
233
|
+
try {
|
|
234
|
+
// 首先关闭WebSocket服务器
|
|
235
|
+
this.wss.close(() => {
|
|
236
|
+
debug('WebSocket server closed');
|
|
237
|
+
});
|
|
238
|
+
// 然后关闭HTTP服务器
|
|
239
|
+
this.server.close((err) => {
|
|
240
|
+
clearTimeout(timeout);
|
|
241
|
+
if (err) {
|
|
242
|
+
error('Error closing server:', err);
|
|
243
|
+
reject(err);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
info('Interactive server stopped successfully');
|
|
247
|
+
this.isRunning = false;
|
|
248
|
+
this.port = 0;
|
|
249
|
+
resolve();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
clearTimeout(timeout);
|
|
255
|
+
error('Error stopping server:', err);
|
|
256
|
+
this.isRunning = false;
|
|
257
|
+
this.port = 0;
|
|
258
|
+
reject(err);
|
|
259
|
+
}
|
|
197
260
|
});
|
|
198
261
|
}
|
|
199
262
|
async collectEnvId(availableEnvs) {
|
|
@@ -2438,6 +2501,14 @@ export class InteractiveServer {
|
|
|
2438
2501
|
</body>
|
|
2439
2502
|
</html>`;
|
|
2440
2503
|
}
|
|
2504
|
+
// 公共方法获取运行状态
|
|
2505
|
+
get running() {
|
|
2506
|
+
return this.isRunning;
|
|
2507
|
+
}
|
|
2508
|
+
// 公共方法获取端口
|
|
2509
|
+
get currentPort() {
|
|
2510
|
+
return this.port;
|
|
2511
|
+
}
|
|
2441
2512
|
}
|
|
2442
2513
|
// 单例实例
|
|
2443
2514
|
let interactiveServerInstance = null;
|
|
@@ -2447,3 +2518,27 @@ export function getInteractiveServer() {
|
|
|
2447
2518
|
}
|
|
2448
2519
|
return interactiveServerInstance;
|
|
2449
2520
|
}
|
|
2521
|
+
export async function resetInteractiveServer() {
|
|
2522
|
+
if (interactiveServerInstance) {
|
|
2523
|
+
try {
|
|
2524
|
+
await interactiveServerInstance.stop();
|
|
2525
|
+
}
|
|
2526
|
+
catch (err) {
|
|
2527
|
+
error('Error stopping existing server instance:', err);
|
|
2528
|
+
}
|
|
2529
|
+
interactiveServerInstance = null;
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
export async function getInteractiveServerSafe() {
|
|
2533
|
+
// 如果当前实例存在但不在运行状态,先清理
|
|
2534
|
+
if (interactiveServerInstance && !interactiveServerInstance.running) {
|
|
2535
|
+
try {
|
|
2536
|
+
await interactiveServerInstance.stop();
|
|
2537
|
+
}
|
|
2538
|
+
catch (err) {
|
|
2539
|
+
debug('Error stopping non-running server:', err);
|
|
2540
|
+
}
|
|
2541
|
+
interactiveServerInstance = null;
|
|
2542
|
+
}
|
|
2543
|
+
return getInteractiveServer();
|
|
2544
|
+
}
|