xiaozhi-client 1.6.1-beta.3 → 1.6.2
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/dist/ProxyMCPServer.d.ts +172 -0
- package/dist/ProxyMCPServer.js +3 -0
- package/dist/ProxyMCPServer.js.map +1 -0
- package/dist/WebServer.d.ts +72 -0
- package/dist/WebServer.js +34 -0
- package/dist/WebServer.js.map +1 -0
- package/dist/WebServerStandalone.d.ts +1 -0
- package/dist/WebServerStandalone.js +35 -0
- package/dist/WebServerStandalone.js.map +1 -0
- package/dist/mcpServerProxy.js +0 -0
- package/dist/services/MCPServer.d.ts +485 -0
- package/dist/services/MCPServer.js +8 -0
- package/dist/services/MCPServer.js.map +1 -0
- package/package.json +31 -24
- package/web/README.md +169 -0
package/dist/mcpServerProxy.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
|
|
4
|
+
declare enum MCPTransportType {
|
|
5
|
+
STDIO = "stdio",
|
|
6
|
+
SSE = "sse",
|
|
7
|
+
STREAMABLE_HTTP = "streamable-http",
|
|
8
|
+
MODELSCOPE_SSE = "modelscope-sse"
|
|
9
|
+
}
|
|
10
|
+
declare enum ConnectionState {
|
|
11
|
+
DISCONNECTED = "disconnected",
|
|
12
|
+
CONNECTING = "connecting",
|
|
13
|
+
CONNECTED = "connected",
|
|
14
|
+
RECONNECTING = "reconnecting",
|
|
15
|
+
FAILED = "failed"
|
|
16
|
+
}
|
|
17
|
+
interface ReconnectOptions {
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
maxAttempts: number;
|
|
20
|
+
initialInterval: number;
|
|
21
|
+
maxInterval: number;
|
|
22
|
+
backoffStrategy: "linear" | "exponential" | "fixed";
|
|
23
|
+
backoffMultiplier: number;
|
|
24
|
+
timeout: number;
|
|
25
|
+
jitter: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface PingOptions {
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
interval: number;
|
|
30
|
+
timeout: number;
|
|
31
|
+
maxFailures: number;
|
|
32
|
+
startDelay: number;
|
|
33
|
+
}
|
|
34
|
+
interface ModelScopeSSEOptions {
|
|
35
|
+
eventSourceInit?: {
|
|
36
|
+
fetch?: (url: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
37
|
+
};
|
|
38
|
+
requestInit?: RequestInit;
|
|
39
|
+
}
|
|
40
|
+
interface MCPServiceConfig {
|
|
41
|
+
name: string;
|
|
42
|
+
type: MCPTransportType;
|
|
43
|
+
command?: string;
|
|
44
|
+
args?: string[];
|
|
45
|
+
url?: string;
|
|
46
|
+
apiKey?: string;
|
|
47
|
+
headers?: Record<string, string>;
|
|
48
|
+
modelScopeAuth?: boolean;
|
|
49
|
+
customSSEOptions?: ModelScopeSSEOptions;
|
|
50
|
+
reconnect?: Partial<ReconnectOptions>;
|
|
51
|
+
ping?: Partial<PingOptions>;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
retryAttempts?: number;
|
|
54
|
+
}
|
|
55
|
+
interface MCPServiceStatus {
|
|
56
|
+
name: string;
|
|
57
|
+
connected: boolean;
|
|
58
|
+
initialized: boolean;
|
|
59
|
+
transportType: MCPTransportType;
|
|
60
|
+
toolCount: number;
|
|
61
|
+
lastError?: string;
|
|
62
|
+
reconnectAttempts: number;
|
|
63
|
+
connectionState: ConnectionState;
|
|
64
|
+
pingEnabled: boolean;
|
|
65
|
+
lastPingTime?: Date;
|
|
66
|
+
pingFailureCount: number;
|
|
67
|
+
isPinging: boolean;
|
|
68
|
+
}
|
|
69
|
+
interface MCPServiceOptions {
|
|
70
|
+
reconnect?: Partial<ReconnectOptions>;
|
|
71
|
+
}
|
|
72
|
+
interface ToolCallResult$1 {
|
|
73
|
+
content: Array<{
|
|
74
|
+
type: string;
|
|
75
|
+
text: string;
|
|
76
|
+
}>;
|
|
77
|
+
isError?: boolean;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* MCP 服务类
|
|
81
|
+
* 负责管理单个 MCP 服务的连接、工具管理和调用
|
|
82
|
+
*/
|
|
83
|
+
declare class MCPService {
|
|
84
|
+
private config;
|
|
85
|
+
private client;
|
|
86
|
+
private transport;
|
|
87
|
+
private tools;
|
|
88
|
+
private connectionState;
|
|
89
|
+
private reconnectOptions;
|
|
90
|
+
private reconnectState;
|
|
91
|
+
private logger;
|
|
92
|
+
private connectionTimeout;
|
|
93
|
+
private initialized;
|
|
94
|
+
private pingOptions;
|
|
95
|
+
private pingTimer;
|
|
96
|
+
private pingFailureCount;
|
|
97
|
+
private lastPingTime;
|
|
98
|
+
private isPinging;
|
|
99
|
+
constructor(config: MCPServiceConfig, options?: MCPServiceOptions);
|
|
100
|
+
/**
|
|
101
|
+
* 验证配置
|
|
102
|
+
*/
|
|
103
|
+
private validateConfig;
|
|
104
|
+
/**
|
|
105
|
+
* 连接到 MCP 服务
|
|
106
|
+
*/
|
|
107
|
+
connect(): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* 尝试建立连接
|
|
110
|
+
*/
|
|
111
|
+
private attemptConnection;
|
|
112
|
+
/**
|
|
113
|
+
* 处理连接成功
|
|
114
|
+
*/
|
|
115
|
+
private handleConnectionSuccess;
|
|
116
|
+
/**
|
|
117
|
+
* 处理连接错误
|
|
118
|
+
*/
|
|
119
|
+
private handleConnectionError;
|
|
120
|
+
/**
|
|
121
|
+
* 检查是否应该重连
|
|
122
|
+
*/
|
|
123
|
+
private shouldReconnect;
|
|
124
|
+
/**
|
|
125
|
+
* 安排重连
|
|
126
|
+
*/
|
|
127
|
+
private scheduleReconnect;
|
|
128
|
+
/**
|
|
129
|
+
* 计算下次重连间隔
|
|
130
|
+
*/
|
|
131
|
+
private calculateNextInterval;
|
|
132
|
+
/**
|
|
133
|
+
* 清理连接资源
|
|
134
|
+
*/
|
|
135
|
+
private cleanupConnection;
|
|
136
|
+
/**
|
|
137
|
+
* 停止重连
|
|
138
|
+
*/
|
|
139
|
+
private stopReconnect;
|
|
140
|
+
/**
|
|
141
|
+
* 刷新工具列表
|
|
142
|
+
*/
|
|
143
|
+
private refreshTools;
|
|
144
|
+
/**
|
|
145
|
+
* 断开连接
|
|
146
|
+
*/
|
|
147
|
+
disconnect(): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* 手动重连
|
|
150
|
+
*/
|
|
151
|
+
reconnect(): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* 获取工具列表
|
|
154
|
+
*/
|
|
155
|
+
getTools(): Tool[];
|
|
156
|
+
/**
|
|
157
|
+
* 调用工具
|
|
158
|
+
*/
|
|
159
|
+
callTool(name: string, arguments_: any): Promise<ToolCallResult$1>;
|
|
160
|
+
/**
|
|
161
|
+
* 获取服务配置
|
|
162
|
+
*/
|
|
163
|
+
getConfig(): MCPServiceConfig;
|
|
164
|
+
/**
|
|
165
|
+
* 获取服务状态
|
|
166
|
+
*/
|
|
167
|
+
getStatus(): MCPServiceStatus;
|
|
168
|
+
/**
|
|
169
|
+
* 检查是否已连接
|
|
170
|
+
*/
|
|
171
|
+
isConnected(): boolean;
|
|
172
|
+
/**
|
|
173
|
+
* 启用自动重连
|
|
174
|
+
*/
|
|
175
|
+
enableReconnect(): void;
|
|
176
|
+
/**
|
|
177
|
+
* 禁用自动重连
|
|
178
|
+
*/
|
|
179
|
+
disableReconnect(): void;
|
|
180
|
+
/**
|
|
181
|
+
* 更新重连配置
|
|
182
|
+
*/
|
|
183
|
+
updateReconnectOptions(options: Partial<ReconnectOptions>): void;
|
|
184
|
+
/**
|
|
185
|
+
* 获取重连配置
|
|
186
|
+
*/
|
|
187
|
+
getReconnectOptions(): ReconnectOptions;
|
|
188
|
+
/**
|
|
189
|
+
* 重置重连状态
|
|
190
|
+
*/
|
|
191
|
+
resetReconnectState(): void;
|
|
192
|
+
/**
|
|
193
|
+
* 启动ping监控
|
|
194
|
+
*/
|
|
195
|
+
private startPingMonitoring;
|
|
196
|
+
/**
|
|
197
|
+
* 停止ping监控
|
|
198
|
+
*/
|
|
199
|
+
private stopPingMonitoring;
|
|
200
|
+
/**
|
|
201
|
+
* 执行ping检查
|
|
202
|
+
*/
|
|
203
|
+
private performPing;
|
|
204
|
+
/**
|
|
205
|
+
* 处理ping成功
|
|
206
|
+
*/
|
|
207
|
+
private handlePingSuccess;
|
|
208
|
+
/**
|
|
209
|
+
* 处理ping失败
|
|
210
|
+
*/
|
|
211
|
+
private handlePingFailure;
|
|
212
|
+
/**
|
|
213
|
+
* 重置ping状态
|
|
214
|
+
*/
|
|
215
|
+
private resetPingState;
|
|
216
|
+
/**
|
|
217
|
+
* 启用ping监控
|
|
218
|
+
*/
|
|
219
|
+
enablePing(): void;
|
|
220
|
+
/**
|
|
221
|
+
* 禁用ping监控
|
|
222
|
+
*/
|
|
223
|
+
disablePing(): void;
|
|
224
|
+
/**
|
|
225
|
+
* 更新ping配置
|
|
226
|
+
*/
|
|
227
|
+
updatePingOptions(options: Partial<PingOptions>): void;
|
|
228
|
+
/**
|
|
229
|
+
* 获取ping配置
|
|
230
|
+
*/
|
|
231
|
+
getPingOptions(): PingOptions;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* MCP 服务管理器
|
|
236
|
+
* 使用 MCPService 实例管理多个 MCP 服务
|
|
237
|
+
* 专注于实例管理、工具聚合和路由调用
|
|
238
|
+
*/
|
|
239
|
+
|
|
240
|
+
interface ServiceStatus {
|
|
241
|
+
connected: boolean;
|
|
242
|
+
clientName: string;
|
|
243
|
+
}
|
|
244
|
+
interface ManagerStatus {
|
|
245
|
+
services: Record<string, ServiceStatus>;
|
|
246
|
+
totalTools: number;
|
|
247
|
+
availableTools: string[];
|
|
248
|
+
}
|
|
249
|
+
interface ToolCallResult {
|
|
250
|
+
content: Array<{
|
|
251
|
+
type: string;
|
|
252
|
+
text: string;
|
|
253
|
+
}>;
|
|
254
|
+
isError?: boolean;
|
|
255
|
+
}
|
|
256
|
+
declare class MCPServiceManager {
|
|
257
|
+
private services;
|
|
258
|
+
private configs;
|
|
259
|
+
private logger;
|
|
260
|
+
private tools;
|
|
261
|
+
/**
|
|
262
|
+
* 创建 MCPServiceManager 实例
|
|
263
|
+
* @param configs 可选的初始服务配置
|
|
264
|
+
*/
|
|
265
|
+
constructor(configs?: Record<string, MCPServiceConfig>);
|
|
266
|
+
/**
|
|
267
|
+
* 启动所有 MCP 服务
|
|
268
|
+
*/
|
|
269
|
+
startAllServices(): Promise<void>;
|
|
270
|
+
/**
|
|
271
|
+
* 启动单个 MCP 服务
|
|
272
|
+
*/
|
|
273
|
+
startService(serviceName: string): Promise<void>;
|
|
274
|
+
/**
|
|
275
|
+
* 停止单个服务
|
|
276
|
+
*/
|
|
277
|
+
stopService(serviceName: string): Promise<void>;
|
|
278
|
+
/**
|
|
279
|
+
* 刷新工具缓存
|
|
280
|
+
*/
|
|
281
|
+
private refreshToolsCache;
|
|
282
|
+
/**
|
|
283
|
+
* 获取所有可用工具
|
|
284
|
+
*/
|
|
285
|
+
getAllTools(): Array<{
|
|
286
|
+
name: string;
|
|
287
|
+
description: string;
|
|
288
|
+
inputSchema: any;
|
|
289
|
+
serviceName: string;
|
|
290
|
+
originalName: string;
|
|
291
|
+
}>;
|
|
292
|
+
/**
|
|
293
|
+
* 调用 MCP 工具
|
|
294
|
+
*/
|
|
295
|
+
callTool(toolName: string, arguments_: any): Promise<ToolCallResult>;
|
|
296
|
+
/**
|
|
297
|
+
* 停止所有服务
|
|
298
|
+
*/
|
|
299
|
+
stopAllServices(): Promise<void>;
|
|
300
|
+
/**
|
|
301
|
+
* 获取服务状态
|
|
302
|
+
*/
|
|
303
|
+
getStatus(): ManagerStatus;
|
|
304
|
+
/**
|
|
305
|
+
* 获取指定服务实例
|
|
306
|
+
*/
|
|
307
|
+
getService(name: string): MCPService | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* 获取所有服务实例
|
|
310
|
+
*/
|
|
311
|
+
getAllServices(): Map<string, MCPService>;
|
|
312
|
+
/**
|
|
313
|
+
* 增强服务配置
|
|
314
|
+
* 根据服务类型添加必要的全局配置
|
|
315
|
+
*/
|
|
316
|
+
private enhanceServiceConfig;
|
|
317
|
+
/**
|
|
318
|
+
* 添加服务配置(重载方法以支持两种调用方式)
|
|
319
|
+
*/
|
|
320
|
+
addServiceConfig(name: string, config: MCPServiceConfig): void;
|
|
321
|
+
addServiceConfig(config: MCPServiceConfig): void;
|
|
322
|
+
/**
|
|
323
|
+
* 更新服务配置
|
|
324
|
+
*/
|
|
325
|
+
updateServiceConfig(name: string, config: MCPServiceConfig): void;
|
|
326
|
+
/**
|
|
327
|
+
* 移除服务配置
|
|
328
|
+
*/
|
|
329
|
+
removeServiceConfig(name: string): void;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* 统一的 MCP 消息处理器
|
|
334
|
+
* 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call 等
|
|
335
|
+
* 这是阶段一重构的核心组件,用于消除双层代理架构
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
interface MCPMessage {
|
|
339
|
+
jsonrpc: "2.0";
|
|
340
|
+
method: string;
|
|
341
|
+
params?: any;
|
|
342
|
+
id?: string | number;
|
|
343
|
+
}
|
|
344
|
+
interface MCPResponse {
|
|
345
|
+
jsonrpc: "2.0";
|
|
346
|
+
result?: any;
|
|
347
|
+
error?: MCPError;
|
|
348
|
+
id: string | number | null;
|
|
349
|
+
}
|
|
350
|
+
interface MCPError {
|
|
351
|
+
code: number;
|
|
352
|
+
message: string;
|
|
353
|
+
data?: any;
|
|
354
|
+
}
|
|
355
|
+
declare class MCPMessageHandler {
|
|
356
|
+
private logger;
|
|
357
|
+
private serviceManager;
|
|
358
|
+
constructor(serviceManager: MCPServiceManager);
|
|
359
|
+
/**
|
|
360
|
+
* 处理 MCP 消息的统一入口
|
|
361
|
+
* @param message MCP 消息
|
|
362
|
+
* @returns MCP 响应
|
|
363
|
+
*/
|
|
364
|
+
handleMessage(message: MCPMessage): Promise<MCPResponse>;
|
|
365
|
+
/**
|
|
366
|
+
* 处理 initialize 请求
|
|
367
|
+
* @param params 初始化参数
|
|
368
|
+
* @param id 消息ID
|
|
369
|
+
* @returns 初始化响应
|
|
370
|
+
*/
|
|
371
|
+
private handleInitialize;
|
|
372
|
+
/**
|
|
373
|
+
* 处理 tools/list 请求
|
|
374
|
+
* @param id 消息ID
|
|
375
|
+
* @returns 工具列表响应
|
|
376
|
+
*/
|
|
377
|
+
private handleToolsList;
|
|
378
|
+
/**
|
|
379
|
+
* 处理 tools/call 请求
|
|
380
|
+
* @param params 工具调用参数
|
|
381
|
+
* @param id 消息ID
|
|
382
|
+
* @returns 工具调用响应
|
|
383
|
+
*/
|
|
384
|
+
private handleToolCall;
|
|
385
|
+
/**
|
|
386
|
+
* 处理 ping 请求
|
|
387
|
+
* @param id 消息ID
|
|
388
|
+
* @returns ping 响应
|
|
389
|
+
*/
|
|
390
|
+
private handlePing;
|
|
391
|
+
/**
|
|
392
|
+
* 创建错误响应
|
|
393
|
+
* @param error 错误对象
|
|
394
|
+
* @param id 消息ID
|
|
395
|
+
* @returns 错误响应
|
|
396
|
+
*/
|
|
397
|
+
private createErrorResponse;
|
|
398
|
+
/**
|
|
399
|
+
* 获取服务管理器实例
|
|
400
|
+
* @returns MCPServiceManager 实例
|
|
401
|
+
*/
|
|
402
|
+
getServiceManager(): MCPServiceManager;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* 统一 MCP 服务器
|
|
407
|
+
* 阶段三重构:整合所有传输协议和服务管理的统一服务器实现
|
|
408
|
+
*
|
|
409
|
+
* 这是整个 MCP 系统的核心类,负责:
|
|
410
|
+
* 1. 管理多种传输适配器(HTTP、Stdio、WebSocket等)
|
|
411
|
+
* 2. 统一的工具注册和管理
|
|
412
|
+
* 3. 连接生命周期管理
|
|
413
|
+
* 4. 消息路由和处理
|
|
414
|
+
*/
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* 服务器配置接口
|
|
418
|
+
*/
|
|
419
|
+
interface UnifiedServerConfig {
|
|
420
|
+
name?: string;
|
|
421
|
+
enableLogging?: boolean;
|
|
422
|
+
logLevel?: string;
|
|
423
|
+
maxConnections?: number;
|
|
424
|
+
connectionTimeout?: number;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* MCP 服务器类(重构版)
|
|
429
|
+
* 现在基于 UnifiedMCPServer 和传输层抽象实现
|
|
430
|
+
* 保持向后兼容的 API,但内部使用新的统一架构
|
|
431
|
+
*/
|
|
432
|
+
declare class MCPServer extends EventEmitter {
|
|
433
|
+
private unifiedServer;
|
|
434
|
+
private proxyMCPServer;
|
|
435
|
+
private port;
|
|
436
|
+
private isStarted;
|
|
437
|
+
constructor(port?: number);
|
|
438
|
+
/**
|
|
439
|
+
* 初始化统一服务器
|
|
440
|
+
*/
|
|
441
|
+
private initializeUnifiedServer;
|
|
442
|
+
/**
|
|
443
|
+
* 初始化小智接入点连接
|
|
444
|
+
*/
|
|
445
|
+
private initializeMCPClient;
|
|
446
|
+
/**
|
|
447
|
+
* 启动服务器
|
|
448
|
+
*/
|
|
449
|
+
start(): Promise<void>;
|
|
450
|
+
/**
|
|
451
|
+
* 停止服务器
|
|
452
|
+
*/
|
|
453
|
+
stop(): Promise<void>;
|
|
454
|
+
/**
|
|
455
|
+
* 获取服务管理器(向后兼容)
|
|
456
|
+
*/
|
|
457
|
+
getServiceManager(): MCPServiceManager | null;
|
|
458
|
+
/**
|
|
459
|
+
* 获取消息处理器(向后兼容)
|
|
460
|
+
*/
|
|
461
|
+
getMessageHandler(): MCPMessageHandler | null;
|
|
462
|
+
/**
|
|
463
|
+
* 获取服务器状态
|
|
464
|
+
*/
|
|
465
|
+
getStatus(): {
|
|
466
|
+
isRunning: boolean;
|
|
467
|
+
port: number;
|
|
468
|
+
mode: string;
|
|
469
|
+
} | {
|
|
470
|
+
port: number;
|
|
471
|
+
mode: string;
|
|
472
|
+
proxyConnected: boolean;
|
|
473
|
+
isRunning: boolean;
|
|
474
|
+
transportCount: number;
|
|
475
|
+
activeConnections: number;
|
|
476
|
+
toolCount: number;
|
|
477
|
+
config: UnifiedServerConfig;
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* 检查服务器是否正在运行
|
|
481
|
+
*/
|
|
482
|
+
isRunning(): boolean;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export { MCPServer };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var B=Object.defineProperty;var s=(o,e)=>B(o,"name",{value:e,configurable:!0});import{EventEmitter as ve}from"events";import S from"ws";import m from"fs";import K from"path";import d from"chalk";import{createConsola as J}from"consola";function G(o){let e=o.getFullYear(),t=String(o.getMonth()+1).padStart(2,"0"),n=String(o.getDate()).padStart(2,"0"),i=String(o.getHours()).padStart(2,"0"),r=String(o.getMinutes()).padStart(2,"0"),c=String(o.getSeconds()).padStart(2,"0");return`${e}-${t}-${n} ${i}:${r}:${c}`}s(G,"formatDateTime");var a=class{static{s(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=J({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:s(t=>{let n={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},i={info:d.blue,success:d.green,warn:d.yellow,error:d.red,debug:d.gray,log:s(h=>h,"log")},r=n[t.type]||t.type.toUpperCase(),c=i[t.type]||(h=>h),g=G(new Date),L=c(`[${r}]`),_=`[${g}] ${L} ${t.args.join(" ")}`;if(!e)try{console.error(_)}catch(h){if(h instanceof Error&&h.message?.includes("EPIPE"))return;throw h}},"log")}])}initLogFile(e){this.logFilePath=K.join(e,"xiaozhi.log"),m.existsSync(this.logFilePath)||m.writeFileSync(this.logFilePath,""),this.writeStream=m.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,t,...n){if(this.writeStream){let r=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${t}`,c=n.length>0?`${r} ${n.map(g=>typeof g=="object"?JSON.stringify(g):String(g)).join(" ")}`:r;this.writeStream.write(`${c}
|
|
2
|
+
`)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=m.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"}):!e&&this.writeStream&&(this.writeStream.end(),this.writeStream=null)}info(e,...t){this.consolaInstance.info(e,...t),this.logToFile("info",e,...t)}success(e,...t){this.consolaInstance.success(e,...t),this.logToFile("success",e,...t)}warn(e,...t){this.consolaInstance.warn(e,...t),this.logToFile("warn",e,...t)}error(e,...t){this.consolaInstance.error(e,...t),this.logToFile("error",e,...t)}debug(e,...t){this.consolaInstance.debug(e,...t),this.logToFile("debug",e,...t)}log(e,...t){this.consolaInstance.log(e,...t),this.logToFile("log",e,...t)}withTag(e){return this}close(){this.writeStream&&(this.writeStream.end(),this.writeStream=null)}},E=new a;var C=class{static{s(this,"ProxyMCPServer")}endpointUrl;ws=null;logger;isConnected=!1;serverInitialized=!1;tools=new Map;connectionState="disconnected";reconnectOptions;reconnectState={attempts:0,nextInterval:0,timer:null,lastError:null,isManualDisconnect:!1};connectionTimeout=null;constructor(e,t){this.endpointUrl=e,this.logger=new a,this.reconnectOptions={enabled:!0,maxAttempts:10,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:1e4,jitter:!0,...t?.reconnect},this.reconnectState.nextInterval=this.reconnectOptions.initialInterval}setServiceManager(e){this.serviceManager=e,this.logger.info("\u5DF2\u8BBE\u7F6E MCPServiceManager"),this.syncToolsFromServiceManager()}syncToolsFromServiceManager(){let e=this.serviceManager;if(!e){this.logger.debug("MCPServiceManager \u672A\u8BBE\u7F6E\uFF0C\u8DF3\u8FC7\u5DE5\u5177\u540C\u6B65");return}try{let t=e.getAllTools(),n=new Map;for(let i of t)n.set(i.name,{name:i.name,description:i.description,inputSchema:i.inputSchema});this.tools=n,this.logger.info(`\u5DF2\u4ECE MCPServiceManager \u540C\u6B65 ${this.tools.size} \u4E2A\u5DE5\u5177`)}catch(t){this.logger.error(`\u540C\u6B65\u5DE5\u5177\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}addTool(e,t){return this.validateTool(e,t),this.tools.set(e,t),this.logger.debug(`\u5DE5\u5177 '${e}' \u5DF2\u6DFB\u52A0`),this}addTools(e){for(let[t,n]of Object.entries(e))this.addTool(t,n);return this}removeTool(e){return this.tools.delete(e)?this.logger.debug(`\u5DE5\u5177 '${e}' \u5DF2\u79FB\u9664`):this.logger.warn(`\u5C1D\u8BD5\u79FB\u9664\u4E0D\u5B58\u5728\u7684\u5DE5\u5177: '${e}'`),this}getTools(){try{this.syncToolsFromServiceManager()}catch{}return Array.from(this.tools.values())}hasTool(e){return this.tools.has(e)}validateTool(e,t){if(!e||typeof e!="string"||e.trim()==="")throw new Error("\u5DE5\u5177\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(this.tools.has(e))throw new Error(`\u5DE5\u5177 '${e}' \u5DF2\u5B58\u5728`);if(!t||typeof t!="object")throw new Error("\u5DE5\u5177\u5FC5\u987B\u662F\u6709\u6548\u7684\u5BF9\u8C61");if(!t.name||typeof t.name!="string")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'name' \u5B57\u6BB5");if(!t.description||typeof t.description!="string")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'description' \u5B57\u6BB5");if(!t.inputSchema||typeof t.inputSchema!="object")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'inputSchema' \u5B57\u6BB5");if(!t.inputSchema.type||!t.inputSchema.properties)throw new Error("\u5DE5\u5177\u7684 inputSchema \u5FC5\u987B\u5305\u542B 'type' \u548C 'properties' \u5B57\u6BB5")}async connect(){if(this.tools.size===0)throw new Error("\u672A\u914D\u7F6E\u4EFB\u4F55\u5DE5\u5177\u3002\u8BF7\u5728\u8FDE\u63A5\u524D\u81F3\u5C11\u6DFB\u52A0\u4E00\u4E2A\u5DE5\u5177\u3002");if(this.connectionState==="connecting")throw new Error("\u8FDE\u63A5\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u8FDE\u63A5\u5B8C\u6210");return this.cleanupConnection(),this.reconnectState.isManualDisconnect=!1,this.attemptConnection()}async attemptConnection(){return this.connectionState="connecting",this.logger.info(`\u6B63\u5728\u8FDE\u63A5 MCP \u63A5\u5165\u70B9: ${this.endpointUrl} (\u5C1D\u8BD5 ${this.reconnectState.attempts+1}/${this.reconnectOptions.maxAttempts})`),new Promise((e,t)=>{this.connectionTimeout=setTimeout(()=>{let n=new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.reconnectOptions.timeout}ms)`);this.handleConnectionError(n),t(n)},this.reconnectOptions.timeout),this.ws=new S(this.endpointUrl),this.ws.on("open",()=>{this.handleConnectionSuccess(),e()}),this.ws.on("message",n=>{try{let i=JSON.parse(n.toString());this.handleMessage(i)}catch(i){this.logger.error("MCP \u6D88\u606F\u89E3\u6790\u9519\u8BEF:",i)}}),this.ws.on("close",(n,i)=>{this.handleConnectionClose(n,i.toString())}),this.ws.on("error",n=>{this.handleConnectionError(n),t(n)})})}handleConnectionSuccess(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.isConnected=!0,this.connectionState="connected",this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.logger.info("MCP WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB")}handleConnectionError(e){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.reconnectState.lastError=e,this.logger.error("MCP WebSocket \u9519\u8BEF:",e.message),this.cleanupConnection()}handleConnectionClose(e,t){if(this.isConnected=!1,this.serverInitialized=!1,this.logger.info(`MCP \u8FDE\u63A5\u5DF2\u5173\u95ED (\u4EE3\u7801: ${e}, \u539F\u56E0: ${t})`),this.reconnectState.isManualDisconnect){this.connectionState="disconnected";return}this.shouldReconnect()?this.scheduleReconnect():(this.connectionState="failed",this.logger.warn(`\u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570 (${this.reconnectOptions.maxAttempts})\uFF0C\u505C\u6B62\u91CD\u8FDE`))}shouldReconnect(){return this.reconnectOptions.enabled&&this.reconnectState.attempts<this.reconnectOptions.maxAttempts&&!this.reconnectState.isManualDisconnect}scheduleReconnect(){this.connectionState="reconnecting",this.reconnectState.attempts++,this.calculateNextInterval(),this.logger.info(`\u5C06\u5728 ${this.reconnectState.nextInterval}ms \u540E\u8FDB\u884C\u7B2C ${this.reconnectState.attempts} \u6B21\u91CD\u8FDE`),this.reconnectState.timer&&clearTimeout(this.reconnectState.timer),this.reconnectState.timer=setTimeout(async()=>{try{await this.attemptConnection()}catch{}},this.reconnectState.nextInterval)}calculateNextInterval(){let e;switch(this.reconnectOptions.backoffStrategy){case"fixed":e=this.reconnectOptions.initialInterval;break;case"linear":e=this.reconnectOptions.initialInterval+this.reconnectState.attempts*this.reconnectOptions.backoffMultiplier*1e3;break;case"exponential":e=this.reconnectOptions.initialInterval*this.reconnectOptions.backoffMultiplier**(this.reconnectState.attempts-1);break;default:e=this.reconnectOptions.initialInterval}if(e=Math.min(e,this.reconnectOptions.maxInterval),this.reconnectOptions.jitter){let t=e*.1,n=(Math.random()-.5)*2*t;e+=n}this.reconnectState.nextInterval=Math.max(e,1e3)}cleanupConnection(){if(this.ws){this.ws.removeAllListeners();try{this.ws.readyState===S.OPEN?this.ws.close(1e3,"Cleaning up connection"):this.ws.readyState===S.CONNECTING&&this.ws.terminate()}catch(e){this.logger.debug("WebSocket \u5173\u95ED\u65F6\u51FA\u73B0\u9519\u8BEF\uFF08\u5DF2\u5FFD\u7565\uFF09:",e)}this.ws=null}this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.isConnected=!1,this.serverInitialized=!1}stopReconnect(){this.reconnectState.timer&&(clearTimeout(this.reconnectState.timer),this.reconnectState.timer=null)}handleMessage(e){this.logger.debug("\u6536\u5230 MCP \u6D88\u606F:",JSON.stringify(e,null,2)),e.method&&this.handleServerRequest(e)}handleServerRequest(e){switch(e.method){case"initialize":this.sendResponse(e.id,{protocolVersion:"2024-11-05",capabilities:{tools:{listChanged:!0},logging:{}},serverInfo:{name:"xiaozhi-mcp-server",version:"1.0.0"}}),this.serverInitialized=!0,this.logger.info("MCP \u670D\u52A1\u5668\u521D\u59CB\u5316\u5B8C\u6210");break;case"tools/list":{let t=this.getTools();this.sendResponse(e.id,{tools:t}),this.logger.info(`MCP \u5DE5\u5177\u5217\u8868\u5DF2\u53D1\u9001 (${t.length}\u4E2A\u5DE5\u5177)`);break}case"ping":this.sendResponse(e.id,{}),this.logger.debug("\u56DE\u5E94 MCP ping \u6D88\u606F");break;default:this.logger.warn(`\u672A\u77E5\u7684 MCP \u8BF7\u6C42: ${e.method}`)}}sendResponse(e,t){if(this.isConnected&&this.ws?.readyState===S.OPEN){let n={jsonrpc:"2.0",id:e,result:t};this.ws.send(JSON.stringify(n))}}getStatus(){return{connected:this.isConnected,initialized:this.serverInitialized,url:this.endpointUrl,availableTools:this.tools.size,connectionState:this.connectionState,reconnectAttempts:this.reconnectState.attempts,lastError:this.reconnectState.lastError?.message||null}}disconnect(){this.logger.info("\u4E3B\u52A8\u65AD\u5F00 MCP \u8FDE\u63A5"),this.reconnectState.isManualDisconnect=!0,this.stopReconnect(),this.cleanupConnection(),this.connectionState="disconnected"}async reconnect(){this.logger.info("\u624B\u52A8\u91CD\u8FDE MCP \u63A5\u5165\u70B9"),this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.isManualDisconnect=!1,this.cleanupConnection(),await this.connect()}enableReconnect(){this.reconnectOptions.enabled=!0,this.logger.info("\u81EA\u52A8\u91CD\u8FDE\u5DF2\u542F\u7528")}disableReconnect(){this.reconnectOptions.enabled=!1,this.stopReconnect(),this.logger.info("\u81EA\u52A8\u91CD\u8FDE\u5DF2\u7981\u7528")}updateReconnectOptions(e){this.reconnectOptions={...this.reconnectOptions,...e},this.logger.info("\u91CD\u8FDE\u914D\u7F6E\u5DF2\u66F4\u65B0",e)}getReconnectOptions(){return{...this.reconnectOptions}}resetReconnectState(){this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.logger.info("\u91CD\u8FDE\u72B6\u6001\u5DF2\u91CD\u7F6E")}};import{copyFileSync as q,existsSync as R,readFileSync as Y,writeFileSync as V}from"fs";import{dirname as X,resolve as f}from"path";import{fileURLToPath as Z}from"url";import*as v from"comment-json";import ee from"dayjs";import I from"json5";import*as H from"json5-writer";function Q(o){if(!o||typeof o!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u6709\u6548\u7684\u5BF9\u8C61");if("command"in o&&typeof o.command=="string")return"stdio";if("type"in o&&o.type==="sse")return"sse";if("type"in o&&o.type==="streamable-http"||"url"in o&&typeof o.url=="string")return"streamable-http";throw new Error("\u65E0\u6CD5\u8BC6\u522B\u7684 MCP \u670D\u52A1\u914D\u7F6E\u7C7B\u578B\u3002\u914D\u7F6E\u5FC5\u987B\u5305\u542B command \u5B57\u6BB5\uFF08stdio\uFF09\u3001type: 'sse' \u5B57\u6BB5\uFF08sse\uFF09\u6216 url \u5B57\u6BB5\uFF08streamable-http\uFF09")}s(Q,"getMcpServerCommunicationType");function y(o,e){if(!e||typeof e!="object")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61`};try{switch(Q(e)){case"stdio":if(!e.command||typeof e.command!="string")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7F3A\u5C11\u5FC5\u9700\u7684 command \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(!Array.isArray(e.args))return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4`};if(e.env&&typeof e.env!="object")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;case"sse":if(e.type!=="sse")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684 type \u5B57\u6BB5\u5FC5\u987B\u662F "sse"`};if(!e.url||typeof e.url!="string")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};break;case"streamable-http":if(!e.url||typeof e.url!="string")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(e.type&&e.type!=="streamable-http")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684 type \u5B57\u6BB5\u5982\u679C\u5B58\u5728\uFF0C\u5FC5\u987B\u662F "streamable-http"`};break;default:return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684\u914D\u7F6E\u7C7B\u578B\u65E0\u6CD5\u8BC6\u522B`}}return{valid:!0}}catch(t){return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684\u914D\u7F6E\u65E0\u6548: ${t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF"}`}}}s(y,"validateMcpServerConfig");var te=X(Z(import.meta.url)),O={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},x=class o{static{s(this,"ConfigManager")}static instance;defaultConfigPath;config=null;currentConfigPath=null;json5Writer=null;constructor(){this.defaultConfigPath=f(te,"xiaozhi.config.default.json")}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let n of t){let i=f(e,n);if(R(i))return i}return f(e,"xiaozhi.config.json")}getConfigFileFormat(e){return e.endsWith(".json5")?"json5":e.endsWith(".jsonc")?"jsonc":"json"}static getInstance(){return o.instance||(o.instance=new o),o.instance}configExists(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let n of t){let i=f(e,n);if(R(i))return!0}return!1}initConfig(e="json"){if(!R(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),n=`xiaozhi.config.${e}`,i=f(t,n);q(this.defaultConfigPath,i),this.config=null,this.json5Writer=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath();this.currentConfigPath=e;let t=this.getConfigFileFormat(e),i=Y(e,"utf8").replace(/^\uFEFF/,""),r;switch(t){case"json5":r=I.parse(i),this.json5Writer=H.load(i);break;case"jsonc":r=v.parse(i);break;default:r=JSON.parse(i);break}return this.validateConfig(r),r}catch(e){throw e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(t.mcpEndpoint===void 0||t.mcpEndpoint===null)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(typeof t.mcpEndpoint!="string")if(Array.isArray(t.mcpEndpoint)){if(t.mcpEndpoint.length===0)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let n of t.mcpEndpoint)if(typeof n!="string"||n.trim()==="")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5B57\u7B26\u4E32\u6570\u7EC4");if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[n,i]of Object.entries(t.mcpServers)){if(!i||typeof i!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${n} \u65E0\u6548`);let r=y(n,i);if(!r.valid)throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A${r.error}`)}}getConfig(){return this.config=this.loadConfig(),JSON.parse(JSON.stringify(this.config))}getMutableConfig(){return this.config||(this.config=this.loadConfig()),this.config}getMcpEndpoint(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?e.mcpEndpoint[0]||"":e.mcpEndpoint}getMcpEndpoints(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?[...e.mcpEndpoint]:e.mcpEndpoint?[e.mcpEndpoint]:[]}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,t){return this.getServerToolsConfig(e)[t]?.enable!==!1}updateMcpEndpoint(e){if(Array.isArray(e)){if(e.length===0)throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let n of e)if(!n||typeof n!="string")throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig();t.mcpEndpoint=e,this.saveConfig(t)}addMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),n=this.getMcpEndpoints();if(n.includes(e))throw new Error(`MCP \u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728`);let i=[...n,e];t.mcpEndpoint=i,this.saveConfig(t)}removeMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),n=this.getMcpEndpoints();if(n.indexOf(e)===-1)throw new Error(`MCP \u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);if(n.length===1)throw new Error("\u4E0D\u80FD\u5220\u9664\u6700\u540E\u4E00\u4E2A MCP \u7AEF\u70B9");let r=n.filter(c=>c!==e);t.mcpEndpoint=r,this.saveConfig(t)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let n=y(e,t);if(!n.valid)throw new Error(n.error||"\u670D\u52A1\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let i=this.getMutableConfig();i.mcpServers[e]=t,this.saveConfig(i)}removeMcpServer(e){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getConfig();if(!t.mcpServers[e])throw new Error(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728`);let n={...t.mcpServers};delete n[e];let i={...t,mcpServers:n};this.saveConfig(i)}updateServerToolsConfig(e,t){let n=this.getMutableConfig();n.mcpServerConfig||(n.mcpServerConfig={}),Object.keys(t).length===0?delete n.mcpServerConfig[e]:n.mcpServerConfig[e]={tools:t},this.saveConfig(n)}removeServerToolsConfig(e){let n={...this.getConfig()};n.mcpServerConfig&&(delete n.mcpServerConfig[e],this.saveConfig(n))}setToolEnabled(e,t,n,i){let r=this.getMutableConfig();r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[e]||(r.mcpServerConfig[e]={tools:{}}),r.mcpServerConfig[e].tools[t]={...r.mcpServerConfig[e].tools[t],enable:n,...i&&{description:i}},this.saveConfig(r)}saveConfig(e){try{this.validateConfig(e);let t;this.currentConfigPath?t=this.currentConfigPath:(t=this.getConfigFilePath(),this.currentConfigPath=t);let n=this.getConfigFileFormat(t),i;switch(n){case"json5":try{this.json5Writer?(this.json5Writer.write(e),i=this.json5Writer.toSource()):(console.warn("\u6CA1\u6709 json5Writer \u5B9E\u4F8B\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON5 \u683C\u5F0F"),i=I.stringify(e,null,2))}catch(r){console.warn("\u4F7F\u7528 json5-writer \u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON5 \u683C\u5F0F:",r),i=I.stringify(e,null,2)}break;case"jsonc":try{i=v.stringify(e,null,2)}catch(r){console.warn("\u4F7F\u7528 comment-json \u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON \u683C\u5F0F:",r),i=JSON.stringify(e,null,2)}break;default:i=JSON.stringify(e,null,2);break}V(t,i,"utf8"),this.config=e,this.notifyConfigUpdate(e)}catch(t){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null,this.currentConfigPath=null,this.json5Writer=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let t=this.getConfig().connection||{};return{heartbeatInterval:t.heartbeatInterval??O.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??O.heartbeatTimeout,reconnectInterval:t.reconnectInterval??O.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let t=this.getMutableConfig();t.connection||(t.connection={}),Object.assign(t.connection,e),this.saveConfig(t)}async updateToolUsageStats(e,t,n){try{let i=this.getMutableConfig();i.mcpServerConfig||(i.mcpServerConfig={}),i.mcpServerConfig[e]||(i.mcpServerConfig[e]={tools:{}}),i.mcpServerConfig[e].tools[t]||(i.mcpServerConfig[e].tools[t]={enable:!0});let r=i.mcpServerConfig[e].tools[t],c=r.usageCount||0,g=r.lastUsedTime;r.usageCount=c+1,(!g||new Date(n)>new Date(g))&&(r.lastUsedTime=ee(n).format("YYYY-MM-DD HH:mm:ss")),this.saveConfig(i),E.debug(`\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5DF2\u66F4\u65B0: ${e}/${t}, \u4F7F\u7528\u6B21\u6570: ${r.usageCount}`)}catch(i){E.error(`\u66F4\u65B0\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5931\u8D25 (${e}/${t}): ${i instanceof Error?i.message:String(i)}`)}}setHeartbeatInterval(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatInterval:e})}setHeartbeatTimeout(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatTimeout:e})}setReconnectInterval(e){if(e<=0)throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({reconnectInterval:e})}getModelScopeConfig(){return this.getConfig().modelscope||{}}getModelScopeApiKey(){return this.getModelScopeConfig().apiKey||process.env.MODELSCOPE_API_TOKEN}updateModelScopeConfig(e){let t=this.getMutableConfig();t.modelscope||(t.modelscope={}),Object.assign(t.modelscope,e),this.saveConfig(t)}setModelScopeApiKey(e){if(!e||typeof e!="string")throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");this.updateModelScopeConfig({apiKey:e})}getWebUIConfig(){return this.getConfig().webUI||{}}getWebUIPort(){return this.getWebUIConfig().port??9999}notifyConfigUpdate(e){try{let t=global.__webServer;t&&typeof t.broadcastConfigUpdate=="function"&&(t.broadcastConfigUpdate(e),console.log("\u5DF2\u901A\u8FC7 WebSocket \u5E7F\u64AD\u914D\u7F6E\u66F4\u65B0"))}catch(t){console.warn("\u901A\u77E5 Web \u754C\u9762\u914D\u7F6E\u66F4\u65B0\u5931\u8D25:",t instanceof Error?t.message:String(t))}}updateWebUIConfig(e){let t=this.getMutableConfig();t.webUI||(t.webUI={}),Object.assign(t.webUI,e),this.saveConfig(t)}setWebUIPort(e){if(!Number.isInteger(e)||e<=0||e>65535)throw new Error("\u7AEF\u53E3\u53F7\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6574\u6570");this.updateWebUIConfig({port:e})}},u=x.getInstance();import{randomUUID as ne}from"crypto";import $ from"express";var p=class{static{s(this,"TransportAdapter")}logger;messageHandler;connectionId;config;state="disconnected";constructor(e,t){this.messageHandler=e,this.config=t,this.connectionId=this.generateConnectionId(),this.logger=new a().withTag(`TransportAdapter:${t.name}`)}async handleIncomingMessage(e){try{this.logger.debug(`\u5904\u7406\u63A5\u6536\u5230\u7684\u6D88\u606F: ${e.method}`,e);let t=await this.messageHandler.handleMessage(e);this.logger.debug("\u53D1\u9001\u54CD\u5E94\u6D88\u606F:",t),await this.sendMessage(t)}catch(t){this.logger.error(`\u5904\u7406\u6D88\u606F\u65F6\u51FA\u9519: ${e.method}`,t);let n=this.createErrorResponse(t,e.id);await this.sendMessage(n)}}createErrorResponse(e,t){let n=-32603;return e.message.includes("\u672A\u627E\u5230\u5DE5\u5177")||e.message.includes("\u672A\u77E5\u7684\u65B9\u6CD5")?n=-32601:(e.message.includes("\u53C2\u6570")||e.message.includes("\u4E0D\u80FD\u4E3A\u7A7A"))&&(n=-32602),{jsonrpc:"2.0",error:{code:n,message:e.message,data:{stack:e.stack}},id:t||null}}generateConnectionId(){let e=Date.now(),t=Math.random().toString(36).substr(2,9);return`${this.config.name}_${e}_${t}`}getConnectionId(){return this.connectionId}getState(){return this.state}setState(e){let t=this.state;this.state=e,t!==e&&(this.logger.info(`\u8FDE\u63A5\u72B6\u6001\u53D8\u66F4: ${t} -> ${e}`),this.onStateChange(t,e))}onStateChange(e,t){}getConfig(){return{...this.config}}getMessageHandler(){return this.messageHandler}parseMessage(e){try{let t=JSON.parse(e.trim());return!t.jsonrpc||t.jsonrpc!=="2.0"?(this.logger.warn("\u6536\u5230\u975E JSON-RPC 2.0 \u683C\u5F0F\u7684\u6D88\u606F",t),null):t.method?t:(this.logger.warn("\u6536\u5230\u6CA1\u6709 method \u5B57\u6BB5\u7684\u6D88\u606F",t),null)}catch(t){return this.logger.error("\u89E3\u6790 JSON \u6D88\u606F\u5931\u8D25",{data:e,error:t}),null}}serializeMessage(e){try{return JSON.stringify(e)}catch(t){this.logger.error("\u5E8F\u5217\u5316\u6D88\u606F\u5931\u8D25",{message:e,error:t});let n=t instanceof Error?t.message:String(t);throw new Error(`\u6D88\u606F\u5E8F\u5217\u5316\u5931\u8D25: ${n}`)}}validateMessage(e){return!(!e||typeof e!="object"||e.jsonrpc!=="2.0"||e.method&&typeof e.method!="string"||!e.method&&!e.result&&!e.error)}createTimeoutPromise(e,t){return Promise.race([e,new Promise((n,i)=>{setTimeout(()=>{i(new Error(`\u64CD\u4F5C\u8D85\u65F6: ${t}ms`))},t)})])}};var b=class extends p{static{s(this,"HTTPAdapter")}app;server=null;clients=new Map;port;host;enableSSE;enableRPC;corsOrigin;maxClients;constructor(e,t={name:"http"}){super(e,t),this.port=t.port||3e3,this.host=t.host||"0.0.0.0",this.enableSSE=t.enableSSE!==!1,this.enableRPC=t.enableRPC!==!1,this.corsOrigin=t.corsOrigin||"*",this.maxClients=t.maxClients!==void 0?t.maxClients:100,this.app=$(),this.setupMiddleware()}async initialize(){this.logger.info("\u521D\u59CB\u5316 HTTP \u9002\u914D\u5668");try{this.setupRoutes(),this.setState("connecting"),this.logger.info("HTTP \u9002\u914D\u5668\u521D\u59CB\u5316\u5B8C\u6210")}catch(e){throw this.logger.error("HTTP \u9002\u914D\u5668\u521D\u59CB\u5316\u5931\u8D25",e),this.setState("error"),e}}async start(){if(this.server){this.logger.warn("HTTP \u670D\u52A1\u5668\u5DF2\u5728\u8FD0\u884C");return}return this.logger.info(`\u542F\u52A8 HTTP \u670D\u52A1\u5668\u5728 ${this.host}:${this.port}`),new Promise((e,t)=>{this.server=this.app.listen(this.port,this.host,()=>{this.setState("connected"),this.logger.info("HTTP \u9002\u914D\u5668\u542F\u52A8\u6210\u529F"),this.logger.info(`- RPC \u7AEF\u70B9: http://${this.host}:${this.port}/rpc`),this.enableSSE&&(this.logger.info(`- SSE \u7AEF\u70B9: http://${this.host}:${this.port}/sse`),this.logger.info(`- \u6D88\u606F\u7AEF\u70B9: http://${this.host}:${this.port}/messages`)),e()}),this.server?.on("error",n=>{this.logger.error("HTTP \u670D\u52A1\u5668\u9519\u8BEF",n),this.setState("error"),t(n)})})}async stop(){if(this.server)return this.logger.info("\u505C\u6B62 HTTP \u670D\u52A1\u5668"),new Promise(e=>{for(let t of this.clients.values())t.response.end();this.clients.clear(),this.server.close(()=>{this.server=null,this.setState("disconnected"),this.logger.info("HTTP \u670D\u52A1\u5668\u5DF2\u505C\u6B62"),e()})})}async sendMessage(e){this.clients.size>0&&this.broadcastToClients(e)}setupMiddleware(){this.app.use($.json({limit:"10mb"})),this.app.use($.urlencoded({extended:!0})),this.app.use((e,t,n)=>{t.header("Access-Control-Allow-Origin",this.corsOrigin),t.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.header("Access-Control-Allow-Headers","Content-Type, Accept"),t.header("Cache-Control","no-cache"),n()}),this.app.use((e,t,n)=>{this.logger.debug(`${e.method} ${e.path}`,{query:e.query,headers:e.headers}),n()})}setupRoutes(){this.enableSSE&&(this.app.get("/sse",this.handleSSE.bind(this)),this.app.post("/messages",this.handleMessages.bind(this))),this.enableRPC&&this.app.post("/rpc",this.handleRPC.bind(this)),this.app.get("/status",this.handleStatus.bind(this)),this.app.get("/health",this.handleHealth.bind(this))}handleSSE(e,t){if(this.clients.size>=this.maxClients){t.status(503).json({error:"\u670D\u52A1\u5668\u7E41\u5FD9\uFF0C\u5BA2\u6237\u7AEF\u8FDE\u63A5\u6570\u5DF2\u8FBE\u4E0A\u9650",maxClients:this.maxClients});return}let n=Date.now().toString(),i=ne();t.setHeader("Content-Type","text/event-stream"),t.setHeader("Cache-Control","no-cache, no-transform"),t.setHeader("Connection","keep-alive"),t.setHeader("X-Accel-Buffering","no");let r={id:n,sessionId:i,response:t,connectedAt:new Date};this.clients.set(i,r),this.logger.info(`SSE \u5BA2\u6237\u7AEF\u5DF2\u8FDE\u63A5: ${n} (\u4F1A\u8BDD: ${i})`),t.write(`event: endpoint
|
|
3
|
+
data: /messages?sessionId=${i}
|
|
4
|
+
|
|
5
|
+
`),e.on("close",()=>{this.clients.delete(i),this.logger.info(`SSE \u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00\u8FDE\u63A5: ${n} (\u4F1A\u8BDD: ${i})`)}),e.on("error",c=>{this.logger.error(`SSE \u5BA2\u6237\u7AEF\u8FDE\u63A5\u9519\u8BEF: ${n}`,c),this.clients.delete(i)})}async handleMessages(e,t){try{let n=e.query.sessionId,i=e.body;if(this.logger.debug(`\u6536\u5230 SSE \u6D88\u606F (\u4F1A\u8BDD: ${n}):`,i),!n||!this.clients.has(n)){t.status(400).json({jsonrpc:"2.0",error:{code:-32600,message:"\u65E0\u6548\u6216\u7F3A\u5C11 sessionId"},id:i.id});return}let r=await this.messageHandler.handleMessage(i);this.logger.debug("SSE \u6D88\u606F\u5904\u7406\u54CD\u5E94:",r);let c=this.clients.get(n);c&&this.sendToClient(c,r),t.status(202).send()}catch(n){this.logger.error("\u5904\u7406 SSE \u6D88\u606F\u65F6\u51FA\u9519",n),t.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:n.message}})}}async handleRPC(e,t){try{let n=e.body;this.logger.debug("\u6536\u5230 RPC \u6D88\u606F:",n);let i=await this.messageHandler.handleMessage(n);t.json(i)}catch(n){this.logger.error("\u5904\u7406 RPC \u6D88\u606F\u65F6\u51FA\u9519",n),t.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:n.message},id:e.body?.id||null})}}handleStatus(e,t){t.json({status:"ok",mode:"mcp-server",serviceManager:"running",clients:this.clients.size,tools:0,maxClients:this.maxClients,enableSSE:this.enableSSE,enableRPC:this.enableRPC,uptime:process.uptime()})}handleHealth(e,t){t.json({status:"ok",mode:"mcp-server",timestamp:new Date().toISOString()})}sendToClient(e,t){try{let n=this.serializeMessage(t);e.response.write(`data: ${n}
|
|
6
|
+
|
|
7
|
+
`),this.logger.debug(`\u6D88\u606F\u5DF2\u53D1\u9001\u5230\u5BA2\u6237\u7AEF ${e.id}`,{sessionId:e.sessionId,messageId:t.id})}catch(n){this.logger.error(`\u5411\u5BA2\u6237\u7AEF ${e.id} \u53D1\u9001\u6D88\u606F\u5931\u8D25`,n),this.clients.delete(e.sessionId)}}broadcastToClients(e){for(let t of this.clients.values())this.sendToClient(t,e)}getStatus(){return{isRunning:this.server!==null,port:this.port,host:this.host,clientCount:this.clients.size,maxClients:this.maxClients,enableSSE:this.enableSSE,enableRPC:this.enableRPC,connectionId:this.connectionId,state:this.state}}getClients(){return Array.from(this.clients.values()).map(e=>({id:e.id,sessionId:e.sessionId,connectedAt:e.connectedAt}))}};import et,{WebSocketServer as tt}from"ws";import{EventEmitter as z}from"events";import{Client as Ce}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as j}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as ie}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as oe}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{EventSource as re}from"eventsource";typeof global<"u"&&!global.EventSource&&(global.EventSource=re);function se(){return new a().withTag("TransportFactory")}s(se,"getLogger");function ae(o){switch(se().info(`\u521B\u5EFA ${o.type} transport for ${o.name}`),o.type){case"stdio":return ce(o);case"sse":return le(o);case"modelscope-sse":return ge(o);case"streamable-http":return he(o);default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${o.type}`)}}s(ae,"createTransport");function ce(o){if(!o.command)throw new Error("stdio transport \u9700\u8981 command \u914D\u7F6E");return new ie({command:o.command,args:o.args||[]})}s(ce,"createStdioTransport");function le(o){if(!o.url)throw new Error("SSE transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(o.url),t=pe(o);return new j(e,t)}s(le,"createSSETransport");function ge(o){if(!o.url)throw new Error("ModelScope SSE transport \u9700\u8981 URL \u914D\u7F6E");if(!o.apiKey)throw new Error("ModelScope SSE transport \u9700\u8981 apiKey \u914D\u7F6E");let e=new URL(o.url),t=de(o);return new j(e,t)}s(ge,"createModelScopeSSETransport");function he(o){if(!o.url)throw new Error("StreamableHTTP transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(o.url),t=fe(o);return new oe(e,t)}s(he,"createStreamableHTTPTransport");function pe(o){let e={};return o.apiKey?e.headers={Authorization:`Bearer ${o.apiKey}`,...o.headers}:o.headers&&(e.headers=o.headers),e}s(pe,"createSSEOptions");function de(o){let e=o.apiKey;return o.customSSEOptions?o.customSSEOptions:{eventSourceInit:{fetch:s(async(t,n)=>{let i={...n?.headers,Authorization:`Bearer ${e}`};return fetch(t,{...n,headers:i})},"fetch")},requestInit:{headers:{Authorization:`Bearer ${e}`,...o.headers}}}}s(de,"createModelScopeSSEOptions");function fe(o){let e={};return o.apiKey?e.headers={Authorization:`Bearer ${o.apiKey}`,...o.headers}:o.headers&&(e.headers=o.headers),e}s(fe,"createStreamableHTTPOptions");function ue(o){if(!o.name||typeof o.name!="string")throw new Error("\u914D\u7F6E\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 name \u5B57\u6BB5");if(!o.type)throw new Error("\u914D\u7F6E\u5FC5\u987B\u5305\u542B type \u5B57\u6BB5");switch(o.type){case"stdio":if(!o.command)throw new Error("stdio \u7C7B\u578B\u9700\u8981 command \u5B57\u6BB5");break;case"sse":case"streamable-http":if(!o.url)throw new Error(`${o.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);break;case"modelscope-sse":if(!o.url)throw new Error("modelscope-sse \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5");if(!o.apiKey)throw new Error("modelscope-sse \u7C7B\u578B\u9700\u8981 apiKey \u5B57\u6BB5\u3002\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E modelscope.apiKey \u6216\u786E\u4FDD\u670D\u52A1\u914D\u7F6E\u5305\u542B apiKey");break;default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${o.type}`)}}s(ue,"validateConfig");function me(){return["stdio","sse","modelscope-sse","streamable-http"]}s(me,"getSupportedTypes");var N={create:ae,validateConfig:ue,getSupportedTypes:me};var M=class{static{s(this,"MCPService")}config;client=null;transport=null;tools=new Map;connectionState="disconnected";reconnectOptions;reconnectState;logger;connectionTimeout=null;initialized=!1;pingOptions;pingTimer=null;pingFailureCount=0;lastPingTime=null;isPinging=!1;constructor(e,t){this.config=e,this.logger=new a().withTag(`MCP-${e.name}`),this.validateConfig(),this.reconnectOptions={enabled:!0,maxAttempts:10,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:1e4,jitter:!0,...t?.reconnect,...e.reconnect},this.pingOptions={enabled:!0,interval:3e4,timeout:5e3,maxFailures:3,startDelay:5e3,...e.ping},this.reconnectState={attempts:0,nextInterval:this.reconnectOptions.initialInterval,timer:null,lastError:null,isManualDisconnect:!1}}validateConfig(){N.validateConfig(this.config)}async connect(){if(this.connectionState==="connecting")throw new Error("\u8FDE\u63A5\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u8FDE\u63A5\u5B8C\u6210");return this.cleanupConnection(),this.reconnectState.isManualDisconnect=!1,this.attemptConnection()}async attemptConnection(){return this.connectionState="connecting",this.logger.info(`\u6B63\u5728\u8FDE\u63A5 MCP \u670D\u52A1: ${this.config.name} (\u5C1D\u8BD5 ${this.reconnectState.attempts+1}/${this.reconnectOptions.maxAttempts})`),new Promise((e,t)=>{this.connectionTimeout=setTimeout(()=>{let n=new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.reconnectOptions.timeout}ms)`);this.handleConnectionError(n),t(n)},this.reconnectOptions.timeout);try{this.client=new Ce({name:`xiaozhi-${this.config.name}-client`,version:"1.0.0"},{capabilities:{tools:{}}}),this.transport=N.create(this.config),this.client.connect(this.transport).then(async()=>{this.handleConnectionSuccess(),await this.refreshTools(),e()}).catch(n=>{this.handleConnectionError(n),t(n)})}catch(n){this.handleConnectionError(n),t(n)}})}handleConnectionSuccess(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.connectionState="connected",this.initialized=!0,this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.resetPingState(),this.logger.info(`MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5\u5DF2\u5EFA\u7ACB`),this.startPingMonitoring()}handleConnectionError(e){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.reconnectState.lastError=e,this.logger.error(`MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5\u9519\u8BEF:`,e.message),this.cleanupConnection(),this.shouldReconnect()?this.scheduleReconnect():(this.connectionState="failed",this.logger.warn(`${this.config.name} \u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570 (${this.reconnectOptions.maxAttempts})\uFF0C\u505C\u6B62\u91CD\u8FDE`))}shouldReconnect(){return this.reconnectOptions.enabled&&this.reconnectState.attempts<this.reconnectOptions.maxAttempts&&!this.reconnectState.isManualDisconnect}scheduleReconnect(){this.connectionState="reconnecting",this.reconnectState.attempts++,this.calculateNextInterval(),this.logger.info(`${this.config.name} \u5C06\u5728 ${this.reconnectState.nextInterval}ms \u540E\u8FDB\u884C\u7B2C ${this.reconnectState.attempts} \u6B21\u91CD\u8FDE`),this.reconnectState.timer&&clearTimeout(this.reconnectState.timer),this.reconnectState.timer=setTimeout(async()=>{try{await this.attemptConnection()}catch{}},this.reconnectState.nextInterval)}calculateNextInterval(){let e;switch(this.reconnectOptions.backoffStrategy){case"fixed":e=this.reconnectOptions.initialInterval;break;case"linear":e=this.reconnectOptions.initialInterval+this.reconnectState.attempts*this.reconnectOptions.backoffMultiplier*1e3;break;case"exponential":e=this.reconnectOptions.initialInterval*this.reconnectOptions.backoffMultiplier**(this.reconnectState.attempts-1);break;default:e=this.reconnectOptions.initialInterval}if(e=Math.min(e,this.reconnectOptions.maxInterval),this.reconnectOptions.jitter){let t=e*.1,n=(Math.random()-.5)*2*t;e+=n}this.reconnectState.nextInterval=Math.max(e,1e3)}cleanupConnection(){if(this.stopPingMonitoring(),this.client){try{this.client.close().catch(()=>{})}catch{}this.client=null}this.transport=null,this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.initialized=!1}stopReconnect(){this.reconnectState.timer&&(clearTimeout(this.reconnectState.timer),this.reconnectState.timer=null)}async refreshTools(){if(!this.client)throw new Error("\u5BA2\u6237\u7AEF\u672A\u521D\u59CB\u5316");try{let t=(await this.client.listTools()).tools||[];this.tools.clear();for(let n of t)this.tools.set(n.name,n);this.logger.info(`${this.config.name} \u670D\u52A1\u52A0\u8F7D\u4E86 ${t.length} \u4E2A\u5DE5\u5177: ${t.map(n=>n.name).join(", ")}`)}catch(e){throw this.logger.error(`${this.config.name} \u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25:`,e instanceof Error?e.message:String(e)),e}}async disconnect(){this.logger.info(`\u4E3B\u52A8\u65AD\u5F00 MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5`),this.reconnectState.isManualDisconnect=!0,this.stopPingMonitoring(),this.stopReconnect(),this.cleanupConnection(),this.connectionState="disconnected"}async reconnect(){this.logger.info(`\u624B\u52A8\u91CD\u8FDE MCP \u670D\u52A1 ${this.config.name}`),this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.isManualDisconnect=!1,this.cleanupConnection(),await this.connect()}getTools(){return Array.from(this.tools.values())}async callTool(e,t){if(!this.client)throw new Error(`\u670D\u52A1 ${this.config.name} \u672A\u8FDE\u63A5`);if(!this.tools.has(e))throw new Error(`\u5DE5\u5177 ${e} \u5728\u670D\u52A1 ${this.config.name} \u4E2D\u4E0D\u5B58\u5728`);this.logger.info(`\u8C03\u7528 ${this.config.name} \u670D\u52A1\u7684\u5DE5\u5177 ${e}\uFF0C\u53C2\u6570:`,JSON.stringify(t));try{let n=await this.client.callTool({name:e,arguments:t||{}});return this.logger.info(`\u5DE5\u5177 ${e} \u8C03\u7528\u6210\u529F\uFF0C\u7ED3\u679C:`,`${JSON.stringify(n).substring(0,500)}...`),n}catch(n){throw this.logger.error(`\u5DE5\u5177 ${e} \u8C03\u7528\u5931\u8D25:`,n instanceof Error?n.message:String(n)),n}}getConfig(){return this.config}getStatus(){return{name:this.config.name,connected:this.connectionState==="connected",initialized:this.initialized,transportType:this.config.type,toolCount:this.tools.size,lastError:this.reconnectState.lastError?.message,reconnectAttempts:this.reconnectState.attempts,connectionState:this.connectionState,pingEnabled:this.pingOptions.enabled,lastPingTime:this.lastPingTime||void 0,pingFailureCount:this.pingFailureCount,isPinging:this.isPinging}}isConnected(){return this.connectionState==="connected"&&this.initialized}enableReconnect(){this.reconnectOptions.enabled=!0,this.logger.info(`${this.config.name} \u81EA\u52A8\u91CD\u8FDE\u5DF2\u542F\u7528`)}disableReconnect(){this.reconnectOptions.enabled=!1,this.stopReconnect(),this.logger.info(`${this.config.name} \u81EA\u52A8\u91CD\u8FDE\u5DF2\u7981\u7528`)}updateReconnectOptions(e){this.reconnectOptions={...this.reconnectOptions,...e},this.logger.info(`${this.config.name} \u91CD\u8FDE\u914D\u7F6E\u5DF2\u66F4\u65B0`,e)}getReconnectOptions(){return{...this.reconnectOptions}}resetReconnectState(){this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.logger.info(`${this.config.name} \u91CD\u8FDE\u72B6\u6001\u5DF2\u91CD\u7F6E`)}startPingMonitoring(){!this.pingOptions.enabled||this.pingTimer||!this.isConnected()||(this.logger.info(`${this.config.name} \u542F\u52A8ping\u76D1\u63A7\uFF0C\u95F4\u9694: ${this.pingOptions.interval}ms`),setTimeout(()=>{this.isConnected()&&!this.pingTimer&&(this.pingTimer=setInterval(()=>{this.performPing()},this.pingOptions.interval))},this.pingOptions.startDelay))}stopPingMonitoring(){this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null,this.logger.debug(`${this.config.name} \u505C\u6B62ping\u76D1\u63A7`))}async performPing(){if(!this.client||this.isPinging||!this.isConnected())return;this.isPinging=!0;let e=performance.now();try{this.logger.debug(`${this.config.name} \u53D1\u9001ping\u8BF7\u6C42\uFF08\u901A\u8FC7listTools\u68C0\u6D4B\u8FDE\u63A5\uFF09`);let t=this.client.listTools(),n=new Promise((r,c)=>{setTimeout(()=>{c(new Error(`Ping\u8D85\u65F6 (${this.pingOptions.timeout}ms)`))},this.pingOptions.timeout)});await Promise.race([t,n]);let i=performance.now()-e;this.handlePingSuccess(i)}catch(t){let n=performance.now()-e;this.handlePingFailure(t,n)}finally{this.isPinging=!1}}handlePingSuccess(e){this.pingFailureCount=0,this.lastPingTime=new Date,this.logger.debug(`${this.config.name} ping\u6210\u529F\uFF0C\u5EF6\u8FDF: ${e.toFixed(2)}ms`)}handlePingFailure(e,t){if(this.pingFailureCount++,this.logger.warn(`${this.config.name} ping\u5931\u8D25 (${this.pingFailureCount}/${this.pingOptions.maxFailures})\uFF0C\u5EF6\u8FDF: ${t.toFixed(2)}ms\uFF0C\u9519\u8BEF: ${e.message}`),this.pingFailureCount>=this.pingOptions.maxFailures){this.logger.error(`${this.config.name} \u8FDE\u7EEDping\u5931\u8D25\u8FBE\u5230\u9608\u503C\uFF0C\u89E6\u53D1\u91CD\u8FDE\u673A\u5236`),this.stopPingMonitoring();let n=new Error(`Ping\u68C0\u6D4B\u5931\u8D25\uFF0C\u8FDE\u7EED\u5931\u8D25${this.pingFailureCount}\u6B21\uFF0C\u8FDE\u63A5\u53EF\u80FD\u5DF2\u65AD\u5F00`);this.handleConnectionError(n)}}resetPingState(){this.pingFailureCount=0,this.lastPingTime=null,this.isPinging=!1}enablePing(){this.pingOptions.enabled=!0,this.logger.info(`${this.config.name} ping\u76D1\u63A7\u5DF2\u542F\u7528`),this.isConnected()&&this.startPingMonitoring()}disablePing(){this.pingOptions.enabled=!1,this.stopPingMonitoring(),this.logger.info(`${this.config.name} ping\u76D1\u63A7\u5DF2\u7981\u7528`)}updatePingOptions(e){let t=this.pingOptions.enabled;this.pingOptions={...this.pingOptions,...e},this.logger.info(`${this.config.name} ping\u914D\u7F6E\u5DF2\u66F4\u65B0`,e),t!==this.pingOptions.enabled&&(this.pingOptions.enabled&&this.isConnected()?this.startPingMonitoring():this.pingOptions.enabled||this.stopPingMonitoring())}getPingOptions(){return{...this.pingOptions}}};var P=class{static{s(this,"MCPServiceManager")}services=new Map;configs={};logger;tools=new Map;constructor(e){this.logger=new a().withTag("MCPManager"),this.configs=e||{}}async startAllServices(){this.logger.info("\u6B63\u5728\u542F\u52A8\u6240\u6709 MCP \u670D\u52A1...");let e=Object.entries(this.configs);if(e.length===0){this.logger.warn("\u6CA1\u6709\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1\uFF0C\u8BF7\u4F7F\u7528 addServiceConfig() \u6DFB\u52A0\u670D\u52A1\u914D\u7F6E");return}for(let[t]of e)await this.startService(t);this.logger.info("\u6240\u6709 MCP \u670D\u52A1\u542F\u52A8\u5B8C\u6210")}async startService(e){this.logger.info(`\u542F\u52A8 MCP \u670D\u52A1: ${e}`);let t=this.configs[e];if(!t)throw new Error(`\u672A\u627E\u5230\u670D\u52A1\u914D\u7F6E: ${e}`);try{this.services.has(e)&&await this.stopService(e);let n=new M(t);await n.connect(),this.services.set(e,n),await this.refreshToolsCache();let i=n.getTools();this.logger.info(`${e} \u670D\u52A1\u542F\u52A8\u6210\u529F\uFF0C\u52A0\u8F7D\u4E86 ${i.length} \u4E2A\u5DE5\u5177:`,i.map(r=>r.name).join(", "))}catch(n){throw this.logger.error(`\u542F\u52A8 ${e} \u670D\u52A1\u5931\u8D25:`,n.message),n}}async stopService(e){this.logger.info(`\u505C\u6B62 MCP \u670D\u52A1: ${e}`);let t=this.services.get(e);if(!t){this.logger.warn(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728\u6216\u672A\u542F\u52A8`);return}try{await t.disconnect(),this.services.delete(e),await this.refreshToolsCache(),this.logger.info(`${e} \u670D\u52A1\u5DF2\u505C\u6B62`)}catch(n){throw this.logger.error(`\u505C\u6B62 ${e} \u670D\u52A1\u5931\u8D25:`,n.message),n}}async refreshToolsCache(){this.tools.clear();for(let[e,t]of this.services)if(t.isConnected()){let n=t.getTools();for(let i of n){let r=`${e}__${i.name}`;this.tools.set(r,{serviceName:e,originalName:i.name,tool:i})}}}getAllTools(){let e=[];for(let[t,n]of this.tools)e.push({name:t,description:n.tool.description||"",inputSchema:n.tool.inputSchema,serviceName:n.serviceName,originalName:n.originalName});return e}async callTool(e,t){this.logger.info(`\u8C03\u7528\u5DE5\u5177: ${e}\uFF0C\u53C2\u6570:`,t);let n=this.tools.get(e);if(!n)throw new Error(`\u672A\u627E\u5230\u5DE5\u5177: ${e}`);let i=this.services.get(n.serviceName);if(!i)throw new Error(`\u670D\u52A1 ${n.serviceName} \u4E0D\u53EF\u7528`);if(!i.isConnected())throw new Error(`\u670D\u52A1 ${n.serviceName} \u672A\u8FDE\u63A5`);try{let r=await i.callTool(n.originalName,t||{});return this.logger.info(`\u5DE5\u5177 ${e} \u8C03\u7528\u6210\u529F\uFF0C\u7ED3\u679C:`,r),r}catch(r){throw this.logger.error(`\u5DE5\u5177 ${e} \u8C03\u7528\u5931\u8D25:`,r.message),r}}async stopAllServices(){this.logger.info("\u6B63\u5728\u505C\u6B62\u6240\u6709 MCP \u670D\u52A1...");for(let[e,t]of this.services)try{await t.disconnect(),this.logger.info(`${e} \u670D\u52A1\u5DF2\u505C\u6B62`)}catch(n){this.logger.error(`\u505C\u6B62 ${e} \u670D\u52A1\u5931\u8D25:`,n.message)}this.services.clear(),this.tools.clear(),this.logger.info("\u6240\u6709 MCP \u670D\u52A1\u5DF2\u505C\u6B62")}getStatus(){let e={services:{},totalTools:this.tools.size,availableTools:Array.from(this.tools.keys())};for(let[t,n]of this.services){let i=n.getStatus();e.services[t]={connected:i.connected,clientName:`xiaozhi-${t}-client`}}return e}getService(e){return this.services.get(e)}getAllServices(){return new Map(this.services)}enhanceServiceConfig(e){let t={...e};try{if(e.type==="modelscope-sse"){let n=u.getModelScopeApiKey();if(n)t.apiKey=n,this.logger.info(`\u4E3A ${e.name} \u670D\u52A1\u6DFB\u52A0 ModelScope API Key`);else throw this.logger.warn(`${e.name} \u670D\u52A1\u9700\u8981 ModelScope API Key\uFF0C\u4F46\u672A\u5728\u914D\u7F6E\u4E2D\u627E\u5230`),new Error(`ModelScope SSE \u670D\u52A1 ${e.name} \u9700\u8981 API Key\uFF0C\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E modelscope.apiKey`)}return t}catch(n){throw this.logger.error(`\u914D\u7F6E\u589E\u5F3A\u5931\u8D25: ${e.name}`,n),n}}addServiceConfig(e,t){let n,i;if(typeof e=="string"&&t)i=e,n=t;else if(typeof e=="object")i=e.name,n=e;else throw new Error("Invalid arguments for addServiceConfig");let r=this.enhanceServiceConfig(n);this.configs[i]=r,this.logger.info(`\u5DF2\u6DFB\u52A0\u670D\u52A1\u914D\u7F6E: ${i}`)}updateServiceConfig(e,t){let n=this.enhanceServiceConfig(t);this.configs[e]=n,this.logger.info(`\u5DF2\u66F4\u65B0\u5E76\u589E\u5F3A\u670D\u52A1\u914D\u7F6E: ${e}`)}removeServiceConfig(e){delete this.configs[e],this.logger.info(`\u5DF2\u79FB\u9664\u670D\u52A1\u914D\u7F6E: ${e}`)}};var w=class{static{s(this,"MCPMessageHandler")}logger;serviceManager;constructor(e){this.serviceManager=e,this.logger=new a().withTag("MCPMessageHandler")}async handleMessage(e){this.logger.debug(`\u5904\u7406 MCP \u6D88\u606F: ${e.method}`,e);try{switch(e.method){case"initialize":return await this.handleInitialize(e.params,e.id);case"tools/list":return await this.handleToolsList(e.id);case"tools/call":return await this.handleToolCall(e.params,e.id);case"ping":return await this.handlePing(e.id);default:throw new Error(`\u672A\u77E5\u7684\u65B9\u6CD5: ${e.method}`)}}catch(t){return this.logger.error(`\u5904\u7406\u6D88\u606F\u65F6\u51FA\u9519: ${e.method}`,t),this.createErrorResponse(t,e.id)}}async handleInitialize(e,t){return this.logger.info("\u5904\u7406 initialize \u8BF7\u6C42",e),{jsonrpc:"2.0",result:{serverInfo:{name:"xiaozhi-mcp-server",version:"1.0.0"},capabilities:{tools:{},logging:{}},protocolVersion:"2024-11-05"},id:t||null}}async handleToolsList(e){this.logger.info("\u5904\u7406 tools/list \u8BF7\u6C42");try{let n=this.serviceManager.getAllTools().map(i=>({name:i.name,description:i.description,inputSchema:i.inputSchema}));return this.logger.info(`\u8FD4\u56DE ${n.length} \u4E2A\u5DE5\u5177`),{jsonrpc:"2.0",result:{tools:n},id:e||null}}catch(t){throw this.logger.error("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25",t),t}}async handleToolCall(e,t){this.logger.info(`\u5904\u7406 tools/call \u8BF7\u6C42: ${e.name}`,e);try{if(!e.name)throw new Error("\u5DE5\u5177\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");let n=await this.serviceManager.callTool(e.name,e.arguments||{});return this.logger.info(`\u5DE5\u5177 ${e.name} \u8C03\u7528\u6210\u529F`),{jsonrpc:"2.0",result:{content:n.content,isError:n.isError||!1},id:t||null}}catch(n){throw this.logger.error(`\u5DE5\u5177\u8C03\u7528\u5931\u8D25: ${e.name}`,n),n}}async handlePing(e){return this.logger.debug("\u5904\u7406 ping \u8BF7\u6C42"),{jsonrpc:"2.0",result:{status:"ok",timestamp:new Date().toISOString()},id:e||null}}createErrorResponse(e,t){let n=-32603;return e.message.includes("\u672A\u627E\u5230\u5DE5\u5177")||e.message.includes("\u672A\u77E5\u7684\u65B9\u6CD5")?n=-32601:(e.message.includes("\u53C2\u6570")||e.message.includes("\u4E0D\u80FD\u4E3A\u7A7A"))&&(n=-32602),{jsonrpc:"2.0",error:{code:n,message:e.message,data:{stack:e.stack}},id:t||null}}getServiceManager(){return this.serviceManager}};var A=class{static{s(this,"ToolRegistry")}serviceManager;logger;constructor(e){this.serviceManager=e,this.logger=new a().withTag("ToolRegistry")}async initialize(){this.logger.info("\u521D\u59CB\u5316\u5DE5\u5177\u6CE8\u518C\u8868")}getAllTools(){return this.serviceManager.getAllTools().map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,serviceName:e.serviceName,originalName:e.originalName}))}findTool(e){return this.getAllTools().find(n=>n.name===e)||null}hasTool(e){return this.findTool(e)!==null}},k=class extends z{static{s(this,"ConnectionManager")}connections=new Map;logger;constructor(){super(),this.logger=new a().withTag("ConnectionManager")}async initialize(){this.logger.info("\u521D\u59CB\u5316\u8FDE\u63A5\u7BA1\u7406\u5668")}registerConnection(e,t,n){let i={id:e,transportName:t,state:n,connectedAt:new Date,lastActivity:new Date};this.connections.set(e,i),this.emit("connectionRegistered",i),this.logger.debug(`\u8FDE\u63A5\u5DF2\u6CE8\u518C: ${e} (${t})`)}updateConnectionState(e,t){let n=this.connections.get(e);n&&(n.state=t,n.lastActivity=new Date,this.emit("connectionStateChanged",n),this.logger.debug(`\u8FDE\u63A5\u72B6\u6001\u66F4\u65B0: ${e} -> ${t}`))}removeConnection(e){let t=this.connections.get(e);t&&(this.connections.delete(e),this.emit("connectionRemoved",t),this.logger.debug(`\u8FDE\u63A5\u5DF2\u79FB\u9664: ${e}`))}getAllConnections(){return Array.from(this.connections.values())}getActiveConnectionCount(){return Array.from(this.connections.values()).filter(e=>e.state==="connected").length}async closeAllConnections(){this.logger.info("\u5173\u95ED\u6240\u6709\u8FDE\u63A5"),this.connections.clear(),this.emit("allConnectionsClosed")}},T=class extends z{static{s(this,"UnifiedMCPServer")}serviceManager;messageHandler;transportAdapters=new Map;toolRegistry;connectionManager;isRunning=!1;logger;config;constructor(e={}){super(),this.config={name:"UnifiedMCPServer",enableLogging:!0,logLevel:"info",maxConnections:100,connectionTimeout:3e4,...e},this.logger=new a().withTag(this.config.name),this.serviceManager=new P,this.messageHandler=new w(this.serviceManager),this.toolRegistry=new A(this.serviceManager),this.connectionManager=new k,this.setupEventListeners()}setupEventListeners(){this.connectionManager.on("connectionRegistered",e=>{this.emit("connectionRegistered",e)}),this.connectionManager.on("connectionStateChanged",e=>{this.emit("connectionStateChanged",e)}),this.connectionManager.on("connectionRemoved",e=>{this.emit("connectionRemoved",e)})}async initialize(){this.logger.info("\u521D\u59CB\u5316\u7EDF\u4E00 MCP \u670D\u52A1\u5668");try{await this.serviceManager.startAllServices(),await this.toolRegistry.initialize(),await this.connectionManager.initialize(),this.logger.info("\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u521D\u59CB\u5316\u5B8C\u6210"),this.emit("initialized")}catch(e){throw this.logger.error("\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u521D\u59CB\u5316\u5931\u8D25",e),e}}async registerTransport(e,t){if(this.transportAdapters.has(e))throw new Error(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u5DF2\u5B58\u5728`);this.logger.info(`\u6CE8\u518C\u4F20\u8F93\u9002\u914D\u5668: ${e}`);try{await t.initialize(),this.transportAdapters.set(e,t),this.connectionManager.registerConnection(t.getConnectionId(),e,t.getState()),this.logger.info(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u6CE8\u518C\u6210\u529F`),this.emit("transportRegistered",{name:e,adapter:t})}catch(n){throw this.logger.error(`\u6CE8\u518C\u4F20\u8F93\u9002\u914D\u5668 ${e} \u5931\u8D25`,n),n}}async start(){if(this.isRunning)throw new Error("\u670D\u52A1\u5668\u5DF2\u5728\u8FD0\u884C");this.logger.info("\u542F\u52A8\u7EDF\u4E00 MCP \u670D\u52A1\u5668");try{for(let[e,t]of this.transportAdapters)try{await t.start(),this.connectionManager.updateConnectionState(t.getConnectionId(),t.getState()),this.logger.info(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u542F\u52A8\u6210\u529F`)}catch(n){throw this.logger.error(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u542F\u52A8\u5931\u8D25`,n),n}this.isRunning=!0,this.logger.info("\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u542F\u52A8\u6210\u529F"),this.emit("started")}catch(e){throw this.logger.error("\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25",e),e}}async stop(){if(this.isRunning){this.logger.info("\u505C\u6B62\u7EDF\u4E00 MCP \u670D\u52A1\u5668");try{for(let[e,t]of this.transportAdapters)try{await t.stop(),this.connectionManager.updateConnectionState(t.getConnectionId(),t.getState()),this.logger.info(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u505C\u6B62\u6210\u529F`)}catch(n){this.logger.error(`\u4F20\u8F93\u9002\u914D\u5668 ${e} \u505C\u6B62\u5931\u8D25`,n)}await this.connectionManager.closeAllConnections(),await this.serviceManager.stopAllServices(),this.isRunning=!1,this.logger.info("\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u505C\u6B62\u6210\u529F"),this.emit("stopped")}catch(e){throw this.logger.error("\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u505C\u6B62\u5931\u8D25",e),e}}}getServiceManager(){return this.serviceManager}getToolRegistry(){return this.toolRegistry}getConnectionManager(){return this.connectionManager}getMessageHandler(){return this.messageHandler}getStatus(){return{isRunning:this.isRunning,transportCount:this.transportAdapters.size,activeConnections:this.connectionManager.getActiveConnectionCount(),toolCount:this.toolRegistry.getAllTools().length,config:this.config}}getTransportAdapters(){return new Map(this.transportAdapters)}isServerRunning(){return this.isRunning}};var U=new a;async function W(o={name:"http"}){U.info("\u521B\u5EFA HTTP \u6A21\u5F0F\u670D\u52A1\u5668");let e=new T;await e.initialize();let t=e.getMessageHandler(),n=new b(t,o);return await e.registerTransport("http",n),U.info("HTTP \u6A21\u5F0F\u670D\u52A1\u5668\u521B\u5EFA\u6210\u529F"),e}s(W,"createHTTPServer");var l=new a,F=class extends ve{static{s(this,"MCPServer")}unifiedServer=null;proxyMCPServer=null;port;isStarted=!1;constructor(e=3e3){super(),this.port=e}async initializeUnifiedServer(){if(!this.unifiedServer){l.info("\u521D\u59CB\u5316\u7EDF\u4E00 MCP \u670D\u52A1\u5668");try{let e={name:"http",port:this.port,host:"0.0.0.0",enableSSE:!0,enableRPC:!0};this.unifiedServer=await W(e),this.unifiedServer.on("started",()=>this.emit("started")),this.unifiedServer.on("stopped",()=>this.emit("stopped")),this.unifiedServer.on("connectionRegistered",t=>{this.emit("connectionRegistered",t)}),l.info("\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u521D\u59CB\u5316\u5B8C\u6210")}catch(e){throw l.error("\u521D\u59CB\u5316\u7EDF\u4E00 MCP \u670D\u52A1\u5668\u5931\u8D25",e),e}}}async initializeMCPClient(){try{let e=null;try{u.configExists()&&(e=u.getMcpEndpoints().find(n=>n&&!n.includes("<\u8BF7\u586B\u5199"))||null)}catch(t){l.warn("\u4ECE\u914D\u7F6E\u4E2D\u8BFB\u53D6\u5C0F\u667A\u63A5\u5165\u70B9\u5931\u8D25:",t)}e?(this.proxyMCPServer=new C(e),this.unifiedServer&&this.proxyMCPServer.setServiceManager(this.unifiedServer.getServiceManager()),await this.proxyMCPServer.connect(),l.info("\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u6210\u529F")):l.info("\u672A\u914D\u7F6E\u6709\u6548\u7684\u5C0F\u667A\u63A5\u5165\u70B9\uFF0C\u8DF3\u8FC7\u8FDE\u63A5")}catch(e){l.error("\u521D\u59CB\u5316\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u5931\u8D25:",e)}}async start(){if(this.isStarted){l.warn("\u670D\u52A1\u5668\u5DF2\u542F\u52A8");return}try{l.info("\u542F\u52A8 MCP \u670D\u52A1\u5668"),await this.initializeUnifiedServer(),this.unifiedServer&&await this.unifiedServer.start(),this.initializeMCPClient().catch(e=>{l.error("\u521D\u59CB\u5316\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u5931\u8D25:",e)}),this.isStarted=!0,this.emit("started"),l.info("MCP \u670D\u52A1\u5668\u542F\u52A8\u6210\u529F")}catch(e){throw l.error("\u542F\u52A8 MCP \u670D\u52A1\u5668\u5931\u8D25:",e),e}}async stop(){if(!this.isStarted){l.warn("\u670D\u52A1\u5668\u672A\u542F\u52A8");return}try{l.info("\u505C\u6B62 MCP \u670D\u52A1\u5668"),this.unifiedServer&&await this.unifiedServer.stop(),this.proxyMCPServer&&(this.proxyMCPServer.disconnect(),this.proxyMCPServer=null),this.isStarted=!1,this.emit("stopped"),l.info("MCP \u670D\u52A1\u5668\u5DF2\u505C\u6B62")}catch(e){throw l.error("\u505C\u6B62 MCP \u670D\u52A1\u5668\u5931\u8D25:",e),e}}getServiceManager(){return this.unifiedServer?.getServiceManager()||null}getMessageHandler(){return this.unifiedServer?.getMessageHandler()||null}getStatus(){return this.unifiedServer?{...this.unifiedServer.getStatus(),port:this.port,mode:"mcp-server",proxyConnected:this.proxyMCPServer!==null}:{isRunning:!1,port:this.port,mode:"mcp-server"}}isRunning(){return this.isStarted&&(this.unifiedServer?.isServerRunning()||!1)}};export{F as MCPServer};
|
|
8
|
+
//# sourceMappingURL=MCPServer.js.map
|