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
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
|
|
4
|
+
declare enum ConnectionState {
|
|
5
|
+
DISCONNECTED = "disconnected",
|
|
6
|
+
CONNECTING = "connecting",
|
|
7
|
+
CONNECTED = "connected",
|
|
8
|
+
RECONNECTING = "reconnecting",
|
|
9
|
+
FAILED = "failed"
|
|
10
|
+
}
|
|
11
|
+
interface ReconnectOptions {
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
maxAttempts: number;
|
|
14
|
+
initialInterval: number;
|
|
15
|
+
maxInterval: number;
|
|
16
|
+
backoffStrategy: "linear" | "exponential" | "fixed";
|
|
17
|
+
backoffMultiplier: number;
|
|
18
|
+
timeout: number;
|
|
19
|
+
jitter: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface ProxyMCPServerOptions {
|
|
22
|
+
reconnect?: Partial<ReconnectOptions>;
|
|
23
|
+
}
|
|
24
|
+
interface ProxyMCPServerStatus {
|
|
25
|
+
connected: boolean;
|
|
26
|
+
initialized: boolean;
|
|
27
|
+
url: string;
|
|
28
|
+
availableTools: number;
|
|
29
|
+
connectionState: ConnectionState;
|
|
30
|
+
reconnectAttempts: number;
|
|
31
|
+
lastError: string | null;
|
|
32
|
+
}
|
|
33
|
+
declare class ProxyMCPServer {
|
|
34
|
+
private endpointUrl;
|
|
35
|
+
private ws;
|
|
36
|
+
private logger;
|
|
37
|
+
private isConnected;
|
|
38
|
+
private serverInitialized;
|
|
39
|
+
private tools;
|
|
40
|
+
private connectionState;
|
|
41
|
+
private reconnectOptions;
|
|
42
|
+
private reconnectState;
|
|
43
|
+
private connectionTimeout;
|
|
44
|
+
constructor(endpointUrl: string, options?: ProxyMCPServerOptions);
|
|
45
|
+
/**
|
|
46
|
+
* 设置 MCPServiceManager 实例
|
|
47
|
+
* @param serviceManager MCPServiceManager 实例
|
|
48
|
+
*/
|
|
49
|
+
setServiceManager(serviceManager: any): void;
|
|
50
|
+
/**
|
|
51
|
+
* 从 MCPServiceManager 同步工具
|
|
52
|
+
* 优化版本:支持增量同步和错误恢复
|
|
53
|
+
*/
|
|
54
|
+
syncToolsFromServiceManager(): void;
|
|
55
|
+
/**
|
|
56
|
+
* 添加单个工具
|
|
57
|
+
* @param name 工具名称
|
|
58
|
+
* @param tool 工具定义
|
|
59
|
+
* @param options 工具选项(可选)
|
|
60
|
+
* @returns 返回 this 支持链式调用
|
|
61
|
+
*/
|
|
62
|
+
addTool(name: string, tool: Tool): this;
|
|
63
|
+
/**
|
|
64
|
+
* 批量添加工具
|
|
65
|
+
* @param tools 工具对象,键为工具名称,值为工具定义
|
|
66
|
+
* @returns 返回 this 支持链式调用
|
|
67
|
+
*/
|
|
68
|
+
addTools(tools: Record<string, Tool>): this;
|
|
69
|
+
/**
|
|
70
|
+
* 移除单个工具
|
|
71
|
+
* @param name 工具名称
|
|
72
|
+
* @returns 返回 this 支持链式调用
|
|
73
|
+
*/
|
|
74
|
+
removeTool(name: string): this;
|
|
75
|
+
/**
|
|
76
|
+
* 获取当前所有工具列表
|
|
77
|
+
* @returns 工具数组
|
|
78
|
+
*/
|
|
79
|
+
getTools(): Tool[];
|
|
80
|
+
/**
|
|
81
|
+
* 检查工具是否存在
|
|
82
|
+
* @param name 工具名称
|
|
83
|
+
* @returns 是否存在
|
|
84
|
+
*/
|
|
85
|
+
hasTool(name: string): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* 验证工具的有效性
|
|
88
|
+
* @param name 工具名称
|
|
89
|
+
* @param tool 工具定义
|
|
90
|
+
*/
|
|
91
|
+
private validateTool;
|
|
92
|
+
/**
|
|
93
|
+
* 连接 MCP 接入点
|
|
94
|
+
* @returns 连接成功后的 Promise
|
|
95
|
+
*/
|
|
96
|
+
connect(): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* 尝试建立连接
|
|
99
|
+
* @returns 连接成功后的 Promise
|
|
100
|
+
*/
|
|
101
|
+
private attemptConnection;
|
|
102
|
+
/**
|
|
103
|
+
* 处理连接成功
|
|
104
|
+
*/
|
|
105
|
+
private handleConnectionSuccess;
|
|
106
|
+
/**
|
|
107
|
+
* 处理连接错误
|
|
108
|
+
*/
|
|
109
|
+
private handleConnectionError;
|
|
110
|
+
/**
|
|
111
|
+
* 处理连接关闭
|
|
112
|
+
*/
|
|
113
|
+
private handleConnectionClose;
|
|
114
|
+
/**
|
|
115
|
+
* 检查是否应该重连
|
|
116
|
+
*/
|
|
117
|
+
private shouldReconnect;
|
|
118
|
+
/**
|
|
119
|
+
* 安排重连
|
|
120
|
+
*/
|
|
121
|
+
private scheduleReconnect;
|
|
122
|
+
/**
|
|
123
|
+
* 计算下次重连间隔
|
|
124
|
+
*/
|
|
125
|
+
private calculateNextInterval;
|
|
126
|
+
/**
|
|
127
|
+
* 清理连接资源
|
|
128
|
+
*/
|
|
129
|
+
private cleanupConnection;
|
|
130
|
+
/**
|
|
131
|
+
* 停止重连
|
|
132
|
+
*/
|
|
133
|
+
private stopReconnect;
|
|
134
|
+
private handleMessage;
|
|
135
|
+
private handleServerRequest;
|
|
136
|
+
private sendResponse;
|
|
137
|
+
/**
|
|
138
|
+
* 获取 MCP 服务器状态
|
|
139
|
+
* @returns 服务器状态
|
|
140
|
+
*/
|
|
141
|
+
getStatus(): ProxyMCPServerStatus;
|
|
142
|
+
/**
|
|
143
|
+
* 主动断开 MCP 连接
|
|
144
|
+
*/
|
|
145
|
+
disconnect(): void;
|
|
146
|
+
/**
|
|
147
|
+
* 手动重连 MCP 接入点
|
|
148
|
+
*/
|
|
149
|
+
reconnect(): Promise<void>;
|
|
150
|
+
/**
|
|
151
|
+
* 启用自动重连
|
|
152
|
+
*/
|
|
153
|
+
enableReconnect(): void;
|
|
154
|
+
/**
|
|
155
|
+
* 禁用自动重连
|
|
156
|
+
*/
|
|
157
|
+
disableReconnect(): void;
|
|
158
|
+
/**
|
|
159
|
+
* 更新重连配置
|
|
160
|
+
*/
|
|
161
|
+
updateReconnectOptions(options: Partial<ReconnectOptions>): void;
|
|
162
|
+
/**
|
|
163
|
+
* 获取重连配置
|
|
164
|
+
*/
|
|
165
|
+
getReconnectOptions(): ReconnectOptions;
|
|
166
|
+
/**
|
|
167
|
+
* 重置重连状态
|
|
168
|
+
*/
|
|
169
|
+
resetReconnectState(): void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { ProxyMCPServer };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var f=Object.defineProperty;var r=(o,t)=>f(o,"name",{value:t,configurable:!0});import u from"ws";import g from"fs";import v from"path";import h from"chalk";import{createConsola as C}from"consola";function b(o){let t=o.getFullYear(),e=String(o.getMonth()+1).padStart(2,"0"),n=String(o.getDate()).padStart(2,"0"),i=String(o.getHours()).padStart(2,"0"),c=String(o.getMinutes()).padStart(2,"0"),a=String(o.getSeconds()).padStart(2,"0");return`${t}-${e}-${n} ${i}:${c}:${a}`}r(b,"formatDateTime");var p=class{static{r(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=C({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let t=this.isDaemonMode;this.consolaInstance.setReporters([{log:r(e=>{let n={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},i={info:h.blue,success:h.green,warn:h.yellow,error:h.red,debug:h.gray,log:r(s=>s,"log")},c=n[e.type]||e.type.toUpperCase(),a=i[e.type]||(s=>s),l=b(new Date),d=a(`[${c}]`),S=`[${l}] ${d} ${e.args.join(" ")}`;if(!t)try{console.error(S)}catch(s){if(s instanceof Error&&s.message?.includes("EPIPE"))return;throw s}},"log")}])}initLogFile(t){this.logFilePath=v.join(t,"xiaozhi.log"),g.existsSync(this.logFilePath)||g.writeFileSync(this.logFilePath,""),this.writeStream=g.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(t,e,...n){if(this.writeStream){let c=`[${new Date().toISOString()}] [${t.toUpperCase()}] ${e}`,a=n.length>0?`${c} ${n.map(l=>typeof l=="object"?JSON.stringify(l):String(l)).join(" ")}`:c;this.writeStream.write(`${a}
|
|
2
|
+
`)}}enableFileLogging(t){t&&!this.writeStream&&this.logFilePath?this.writeStream=g.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"}):!t&&this.writeStream&&(this.writeStream.end(),this.writeStream=null)}info(t,...e){this.consolaInstance.info(t,...e),this.logToFile("info",t,...e)}success(t,...e){this.consolaInstance.success(t,...e),this.logToFile("success",t,...e)}warn(t,...e){this.consolaInstance.warn(t,...e),this.logToFile("warn",t,...e)}error(t,...e){this.consolaInstance.error(t,...e),this.logToFile("error",t,...e)}debug(t,...e){this.consolaInstance.debug(t,...e),this.logToFile("debug",t,...e)}log(t,...e){this.consolaInstance.log(t,...e),this.logToFile("log",t,...e)}withTag(t){return this}close(){this.writeStream&&(this.writeStream.end(),this.writeStream=null)}},I=new p;var m=class{static{r(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(t,e){this.endpointUrl=t,this.logger=new p,this.reconnectOptions={enabled:!0,maxAttempts:10,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:1e4,jitter:!0,...e?.reconnect},this.reconnectState.nextInterval=this.reconnectOptions.initialInterval}setServiceManager(t){this.serviceManager=t,this.logger.info("\u5DF2\u8BBE\u7F6E MCPServiceManager"),this.syncToolsFromServiceManager()}syncToolsFromServiceManager(){let t=this.serviceManager;if(!t){this.logger.debug("MCPServiceManager \u672A\u8BBE\u7F6E\uFF0C\u8DF3\u8FC7\u5DE5\u5177\u540C\u6B65");return}try{let e=t.getAllTools(),n=new Map;for(let i of e)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(e){this.logger.error(`\u540C\u6B65\u5DE5\u5177\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}addTool(t,e){return this.validateTool(t,e),this.tools.set(t,e),this.logger.debug(`\u5DE5\u5177 '${t}' \u5DF2\u6DFB\u52A0`),this}addTools(t){for(let[e,n]of Object.entries(t))this.addTool(e,n);return this}removeTool(t){return this.tools.delete(t)?this.logger.debug(`\u5DE5\u5177 '${t}' \u5DF2\u79FB\u9664`):this.logger.warn(`\u5C1D\u8BD5\u79FB\u9664\u4E0D\u5B58\u5728\u7684\u5DE5\u5177: '${t}'`),this}getTools(){try{this.syncToolsFromServiceManager()}catch{}return Array.from(this.tools.values())}hasTool(t){return this.tools.has(t)}validateTool(t,e){if(!t||typeof t!="string"||t.trim()==="")throw new Error("\u5DE5\u5177\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(this.tools.has(t))throw new Error(`\u5DE5\u5177 '${t}' \u5DF2\u5B58\u5728`);if(!e||typeof e!="object")throw new Error("\u5DE5\u5177\u5FC5\u987B\u662F\u6709\u6548\u7684\u5BF9\u8C61");if(!e.name||typeof e.name!="string")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'name' \u5B57\u6BB5");if(!e.description||typeof e.description!="string")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'description' \u5B57\u6BB5");if(!e.inputSchema||typeof e.inputSchema!="object")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'inputSchema' \u5B57\u6BB5");if(!e.inputSchema.type||!e.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((t,e)=>{this.connectionTimeout=setTimeout(()=>{let n=new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.reconnectOptions.timeout}ms)`);this.handleConnectionError(n),e(n)},this.reconnectOptions.timeout),this.ws=new u(this.endpointUrl),this.ws.on("open",()=>{this.handleConnectionSuccess(),t()}),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),e(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(t){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.reconnectState.lastError=t,this.logger.error("MCP WebSocket \u9519\u8BEF:",t.message),this.cleanupConnection()}handleConnectionClose(t,e){if(this.isConnected=!1,this.serverInitialized=!1,this.logger.info(`MCP \u8FDE\u63A5\u5DF2\u5173\u95ED (\u4EE3\u7801: ${t}, \u539F\u56E0: ${e})`),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 t;switch(this.reconnectOptions.backoffStrategy){case"fixed":t=this.reconnectOptions.initialInterval;break;case"linear":t=this.reconnectOptions.initialInterval+this.reconnectState.attempts*this.reconnectOptions.backoffMultiplier*1e3;break;case"exponential":t=this.reconnectOptions.initialInterval*this.reconnectOptions.backoffMultiplier**(this.reconnectState.attempts-1);break;default:t=this.reconnectOptions.initialInterval}if(t=Math.min(t,this.reconnectOptions.maxInterval),this.reconnectOptions.jitter){let e=t*.1,n=(Math.random()-.5)*2*e;t+=n}this.reconnectState.nextInterval=Math.max(t,1e3)}cleanupConnection(){if(this.ws){this.ws.removeAllListeners();try{this.ws.readyState===u.OPEN?this.ws.close(1e3,"Cleaning up connection"):this.ws.readyState===u.CONNECTING&&this.ws.terminate()}catch(t){this.logger.debug("WebSocket \u5173\u95ED\u65F6\u51FA\u73B0\u9519\u8BEF\uFF08\u5DF2\u5FFD\u7565\uFF09:",t)}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(t){this.logger.debug("\u6536\u5230 MCP \u6D88\u606F:",JSON.stringify(t,null,2)),t.method&&this.handleServerRequest(t)}handleServerRequest(t){switch(t.method){case"initialize":this.sendResponse(t.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 e=this.getTools();this.sendResponse(t.id,{tools:e}),this.logger.info(`MCP \u5DE5\u5177\u5217\u8868\u5DF2\u53D1\u9001 (${e.length}\u4E2A\u5DE5\u5177)`);break}case"ping":this.sendResponse(t.id,{}),this.logger.debug("\u56DE\u5E94 MCP ping \u6D88\u606F");break;default:this.logger.warn(`\u672A\u77E5\u7684 MCP \u8BF7\u6C42: ${t.method}`)}}sendResponse(t,e){if(this.isConnected&&this.ws?.readyState===u.OPEN){let n={jsonrpc:"2.0",id:t,result:e};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(t){this.reconnectOptions={...this.reconnectOptions,...t},this.logger.info("\u91CD\u8FDE\u914D\u7F6E\u5DF2\u66F4\u65B0",t)}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")}};export{m as ProxyMCPServer};
|
|
3
|
+
//# sourceMappingURL=ProxyMCPServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ProxyMCPServer.ts","../src/logger.ts"],"sourcesContent":["import type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport WebSocket from \"ws\";\nimport { Logger } from \"./logger.js\";\n\nexport type { Tool };\n\n// MCP 消息接口\ninterface MCPMessage {\n jsonrpc: string;\n id?: number | string;\n method?: string;\n params?: any;\n result?: any;\n}\n\n// 连接状态枚举\nenum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 重连配置接口\ninterface ReconnectOptions {\n enabled: boolean; // 是否启用自动重连\n maxAttempts: number; // 最大重连次数\n initialInterval: number; // 初始重连间隔(ms)\n maxInterval: number; // 最大重连间隔(ms)\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\"; // 退避策略\n backoffMultiplier: number; // 退避倍数\n timeout: number; // 单次连接超时时间(ms)\n jitter: boolean; // 是否添加随机抖动\n}\n\n// 重连状态接口\ninterface ReconnectState {\n attempts: number; // 当前重连次数\n nextInterval: number; // 下次重连间隔\n timer: NodeJS.Timeout | null; // 重连定时器\n lastError: Error | null; // 最后一次错误\n isManualDisconnect: boolean; // 是否为主动断开\n}\n\n// 服务器选项接口\ninterface ProxyMCPServerOptions {\n reconnect?: Partial<ReconnectOptions>;\n}\n\n// 服务器状态接口\ninterface ProxyMCPServerStatus {\n connected: boolean;\n initialized: boolean;\n url: string;\n availableTools: number;\n connectionState: ConnectionState;\n reconnectAttempts: number;\n lastError: string | null;\n}\n\nexport class ProxyMCPServer {\n private endpointUrl: string;\n private ws: WebSocket | null = null;\n private logger: Logger;\n private isConnected = false;\n private serverInitialized = false;\n\n // 工具管理\n private tools: Map<string, Tool> = new Map();\n\n // 连接状态管理\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n\n // 重连配置\n private reconnectOptions: ReconnectOptions;\n\n // 重连状态\n private reconnectState: ReconnectState = {\n attempts: 0,\n nextInterval: 0,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n\n // 连接超时定时器\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n constructor(endpointUrl: string, options?: ProxyMCPServerOptions) {\n this.endpointUrl = endpointUrl;\n this.logger = new Logger();\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...options?.reconnect,\n };\n\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n }\n\n /**\n * 设置 MCPServiceManager 实例\n * @param serviceManager MCPServiceManager 实例\n */\n setServiceManager(serviceManager: any): void {\n // 临时存储在一个变量中,避免类型检查问题\n (this as any).serviceManager = serviceManager;\n this.logger.info(\"已设置 MCPServiceManager\");\n\n // 立即同步工具\n this.syncToolsFromServiceManager();\n }\n\n /**\n * 从 MCPServiceManager 同步工具\n * 优化版本:支持增量同步和错误恢复\n */\n syncToolsFromServiceManager(): void {\n const serviceManager = (this as any).serviceManager;\n if (!serviceManager) {\n this.logger.debug(\"MCPServiceManager 未设置,跳过工具同步\");\n return;\n }\n\n try {\n // 从 MCPServiceManager 获取所有工具\n const allTools = serviceManager.getAllTools();\n\n // 原子性更新:先构建新的工具映射,再替换\n const newTools = new Map<string, Tool>();\n\n for (const toolInfo of allTools) {\n newTools.set(toolInfo.name, {\n name: toolInfo.name,\n description: toolInfo.description,\n inputSchema: toolInfo.inputSchema,\n });\n }\n\n // 原子性替换\n this.tools = newTools;\n\n this.logger.info(`已从 MCPServiceManager 同步 ${this.tools.size} 个工具`);\n } catch (error) {\n this.logger.error(\n `同步工具失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 同步失败时保持现有工具不变,确保服务可用性\n }\n }\n\n /**\n * 添加单个工具\n * @param name 工具名称\n * @param tool 工具定义\n * @param options 工具选项(可选)\n * @returns 返回 this 支持链式调用\n */\n addTool(name: string, tool: Tool): this {\n this.validateTool(name, tool);\n this.tools.set(name, tool);\n this.logger.debug(`工具 '${name}' 已添加`);\n // TODO: 未来可以使用 options 参数来设置工具的启用状态、元数据等\n return this;\n }\n\n /**\n * 批量添加工具\n * @param tools 工具对象,键为工具名称,值为工具定义\n * @returns 返回 this 支持链式调用\n */\n addTools(tools: Record<string, Tool>): this {\n for (const [name, tool] of Object.entries(tools)) {\n this.addTool(name, tool);\n }\n return this;\n }\n\n /**\n * 移除单个工具\n * @param name 工具名称\n * @returns 返回 this 支持链式调用\n */\n removeTool(name: string): this {\n if (this.tools.delete(name)) {\n this.logger.debug(`工具 '${name}' 已移除`);\n } else {\n this.logger.warn(`尝试移除不存在的工具: '${name}'`);\n }\n return this;\n }\n\n /**\n * 获取当前所有工具列表\n * @returns 工具数组\n */\n getTools(): Tool[] {\n // 每次获取工具时都尝试从 MCPServiceManager 同步\n try {\n this.syncToolsFromServiceManager();\n } catch (error) {\n // 静默处理同步错误,不影响现有工具的返回\n }\n\n return Array.from(this.tools.values());\n }\n\n /**\n * 检查工具是否存在\n * @param name 工具名称\n * @returns 是否存在\n */\n hasTool(name: string): boolean {\n return this.tools.has(name);\n }\n\n /**\n * 验证工具的有效性\n * @param name 工具名称\n * @param tool 工具定义\n */\n private validateTool(name: string, tool: Tool): void {\n if (!name || typeof name !== \"string\" || name.trim() === \"\") {\n throw new Error(\"工具名称必须是非空字符串\");\n }\n\n if (this.tools.has(name)) {\n throw new Error(`工具 '${name}' 已存在`);\n }\n\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具必须是有效的对象\");\n }\n\n // 验证工具的必需字段\n if (!tool.name || typeof tool.name !== \"string\") {\n throw new Error(\"工具必须包含有效的 'name' 字段\");\n }\n\n if (!tool.description || typeof tool.description !== \"string\") {\n throw new Error(\"工具必须包含有效的 'description' 字段\");\n }\n\n if (!tool.inputSchema || typeof tool.inputSchema !== \"object\") {\n throw new Error(\"工具必须包含有效的 'inputSchema' 字段\");\n }\n\n // 验证 inputSchema 的基本结构\n if (!tool.inputSchema.type || !tool.inputSchema.properties) {\n throw new Error(\n \"工具的 inputSchema 必须包含 'type' 和 'properties' 字段\"\n );\n }\n }\n\n /**\n * 连接 MCP 接入点\n * @returns 连接成功后的 Promise\n */\n public async connect(): Promise<void> {\n // 连接前验证\n if (this.tools.size === 0) {\n throw new Error(\"未配置任何工具。请在连接前至少添加一个工具。\");\n }\n\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n // 重置手动断开标志\n this.reconnectState.isManualDisconnect = false;\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n * @returns 连接成功后的 Promise\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n this.logger.info(\n `正在连接 MCP 接入点: ${this.endpointUrl} (尝试 ${\n this.reconnectState.attempts + 1\n }/${this.reconnectOptions.maxAttempts})`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n try {\n const message: MCPMessage = JSON.parse(data.toString());\n this.handleMessage(message);\n } catch (error) {\n this.logger.error(\"MCP 消息解析错误:\", error);\n }\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.isConnected = true;\n this.connectionState = ConnectionState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n this.logger.info(\"MCP WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(\"MCP WebSocket 错误:\", error.message);\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.isConnected = false;\n this.serverInitialized = false;\n this.logger.info(`MCP 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n this.connectionState = ConnectionState.DISCONNECTED;\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.connectionState = ConnectionState.FAILED;\n this.logger.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.connectionState = ConnectionState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算下次重连间隔\n this.calculateNextInterval();\n\n this.logger.info(\n `将在 ${this.reconnectState.nextInterval}ms 后进行第 ${this.reconnectState.attempts} 次重连`\n );\n\n // 清理之前的重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n }\n\n // 设置重连定时器\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.attemptConnection();\n } catch (error) {\n // 连接失败会触发 handleConnectionError,无需额外处理\n }\n }, this.reconnectState.nextInterval);\n }\n\n /**\n * 计算下次重连间隔\n */\n private calculateNextInterval(): void {\n let interval: number;\n\n switch (this.reconnectOptions.backoffStrategy) {\n case \"fixed\":\n interval = this.reconnectOptions.initialInterval;\n break;\n\n case \"linear\":\n interval =\n this.reconnectOptions.initialInterval +\n this.reconnectState.attempts *\n this.reconnectOptions.backoffMultiplier *\n 1000;\n break;\n\n case \"exponential\":\n interval =\n this.reconnectOptions.initialInterval *\n this.reconnectOptions.backoffMultiplier **\n (this.reconnectState.attempts - 1);\n break;\n\n default:\n interval = this.reconnectOptions.initialInterval;\n }\n\n // 限制最大间隔\n interval = Math.min(interval, this.reconnectOptions.maxInterval);\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n const jitterRange = interval * 0.1; // 10% 抖动\n const jitter = (Math.random() - 0.5) * 2 * jitterRange;\n interval += jitter;\n }\n\n this.reconnectState.nextInterval = Math.max(interval, 1000); // 最小1秒\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 清理 WebSocket\n if (this.ws) {\n // 移除所有事件监听器,防止在关闭时触发错误事件\n this.ws.removeAllListeners();\n\n // 安全关闭 WebSocket\n try {\n if (this.ws.readyState === WebSocket.OPEN) {\n this.ws.close(1000, \"Cleaning up connection\");\n } else if (this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.terminate(); // 强制终止正在连接的 WebSocket\n }\n } catch (error) {\n // 忽略关闭时的错误\n this.logger.debug(\"WebSocket 关闭时出现错误(已忽略):\", error);\n }\n\n this.ws = null;\n }\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置连接状态\n this.isConnected = false;\n this.serverInitialized = false;\n }\n\n /**\n * 停止重连\n */\n private stopReconnect(): void {\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n }\n\n private handleMessage(message: MCPMessage): void {\n this.logger.debug(\"收到 MCP 消息:\", JSON.stringify(message, null, 2));\n\n if (message.method) {\n this.handleServerRequest(message);\n }\n }\n\n private handleServerRequest(request: MCPMessage): void {\n switch (request.method) {\n case \"initialize\":\n this.sendResponse(request.id, {\n protocolVersion: \"2024-11-05\",\n capabilities: {\n tools: { listChanged: true },\n logging: {},\n },\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n });\n this.serverInitialized = true;\n this.logger.info(\"MCP 服务器初始化完成\");\n break;\n\n case \"tools/list\": {\n const toolsList = this.getTools();\n this.sendResponse(request.id, { tools: toolsList });\n this.logger.info(`MCP 工具列表已发送 (${toolsList.length}个工具)`);\n break;\n }\n\n case \"ping\":\n this.sendResponse(request.id, {});\n this.logger.debug(\"回应 MCP ping 消息\");\n break;\n\n default:\n this.logger.warn(`未知的 MCP 请求: ${request.method}`);\n }\n }\n\n private sendResponse(id: number | string | undefined, result: any): void {\n if (this.isConnected && this.ws?.readyState === WebSocket.OPEN) {\n const response: MCPMessage = {\n jsonrpc: \"2.0\",\n id,\n result,\n };\n this.ws.send(JSON.stringify(response));\n }\n }\n\n /**\n * 获取 MCP 服务器状态\n * @returns 服务器状态\n */\n public getStatus(): ProxyMCPServerStatus {\n return {\n connected: this.isConnected,\n initialized: this.serverInitialized,\n url: this.endpointUrl,\n availableTools: this.tools.size,\n connectionState: this.connectionState,\n reconnectAttempts: this.reconnectState.attempts,\n lastError: this.reconnectState.lastError?.message || null,\n };\n }\n\n /**\n * 主动断开 MCP 连接\n */\n public disconnect(): void {\n this.logger.info(\"主动断开 MCP 连接\");\n\n // 标记为手动断开,阻止自动重连\n this.reconnectState.isManualDisconnect = true;\n\n // 停止重连定时器\n this.stopReconnect();\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n }\n\n /**\n * 手动重连 MCP 接入点\n */\n public async reconnect(): Promise<void> {\n this.logger.info(\"手动重连 MCP 接入点\");\n\n // 停止自动重连\n this.stopReconnect();\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.isManualDisconnect = false;\n\n // 清理现有连接\n this.cleanupConnection();\n\n // 尝试连接\n await this.connect();\n }\n\n /**\n * 启用自动重连\n */\n public enableReconnect(): void {\n this.reconnectOptions.enabled = true;\n this.logger.info(\"自动重连已启用\");\n }\n\n /**\n * 禁用自动重连\n */\n public disableReconnect(): void {\n this.reconnectOptions.enabled = false;\n this.stopReconnect();\n this.logger.info(\"自动重连已禁用\");\n }\n\n /**\n * 更新重连配置\n */\n public updateReconnectOptions(options: Partial<ReconnectOptions>): void {\n this.reconnectOptions = { ...this.reconnectOptions, ...options };\n this.logger.info(\"重连配置已更新\", options);\n }\n\n /**\n * 获取重连配置\n */\n public getReconnectOptions(): ReconnectOptions {\n return { ...this.reconnectOptions };\n }\n\n /**\n * 重置重连状态\n */\n public resetReconnectState(): void {\n this.stopReconnect();\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n this.logger.info(\"重连状态已重置\");\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { type consola, createConsola } from \"consola\";\n\nfunction formatDateTime(date: Date) {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\nexport class Logger {\n private logFilePath: string | null = null;\n private writeStream: fs.WriteStream | null = null;\n private consolaInstance: typeof consola;\n private isDaemonMode: boolean;\n\n constructor() {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n // 创建自定义的 consola 实例,禁用图标并自定义格式\n this.consolaInstance = createConsola({\n formatOptions: {\n date: false,\n colors: true,\n compact: true,\n },\n fancy: false,\n });\n\n // 保存对当前实例的引用,以便在闭包中访问\n const isDaemonMode = this.isDaemonMode;\n\n // 自定义格式化器\n this.consolaInstance.setReporters([\n {\n log: (logObj) => {\n const levelMap: Record<string, string> = {\n info: \"INFO\",\n success: \"SUCCESS\",\n warn: \"WARN\",\n error: \"ERROR\",\n debug: \"DEBUG\",\n log: \"LOG\",\n };\n\n const colorMap: Record<string, (text: string) => string> = {\n info: chalk.blue,\n success: chalk.green,\n warn: chalk.yellow,\n error: chalk.red,\n debug: chalk.gray,\n log: (text: string) => text,\n };\n\n const level = levelMap[logObj.type] || logObj.type.toUpperCase();\n const colorFn = colorMap[logObj.type] || ((text: string) => text);\n const timestamp = formatDateTime(new Date());\n\n // 为级别添加颜色\n const coloredLevel = colorFn(`[${level}]`);\n const message = `[${timestamp}] ${coloredLevel} ${logObj.args.join(\n \" \"\n )}`;\n\n // 守护进程模式下不输出到控制台,只写入文件\n if (!isDaemonMode) {\n // 输出到 stderr(与原来保持一致)\n try {\n console.error(message);\n } catch (error) {\n // 忽略 EPIPE 错误\n if (error instanceof Error && error.message?.includes(\"EPIPE\")) {\n return;\n }\n throw error;\n }\n }\n },\n },\n ]);\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 确保日志文件存在\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n\n // 创建写入流,追加模式\n this.writeStream = fs.createWriteStream(this.logFilePath, {\n flags: \"a\",\n encoding: \"utf8\",\n });\n }\n\n /**\n * 记录日志到文件\n * @param level 日志级别\n * @param message 日志消息\n * @param args 额外参数\n */\n private logToFile(level: string, message: string, ...args: any[]): void {\n if (this.writeStream) {\n const timestamp = new Date().toISOString();\n const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;\n const fullMessage =\n args.length > 0\n ? `${formattedMessage} ${args\n .map((arg) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \")}`\n : formattedMessage;\n\n this.writeStream.write(`${fullMessage}\\n`);\n }\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n if (enable && !this.writeStream && this.logFilePath) {\n this.writeStream = fs.createWriteStream(this.logFilePath, {\n flags: \"a\",\n encoding: \"utf8\",\n });\n } else if (!enable && this.writeStream) {\n this.writeStream.end();\n this.writeStream = null;\n }\n }\n\n /**\n * 日志方法\n */\n info(message: string, ...args: any[]): void {\n this.consolaInstance.info(message, ...args);\n this.logToFile(\"info\", message, ...args);\n }\n\n success(message: string, ...args: any[]): void {\n this.consolaInstance.success(message, ...args);\n this.logToFile(\"success\", message, ...args);\n }\n\n warn(message: string, ...args: any[]): void {\n this.consolaInstance.warn(message, ...args);\n this.logToFile(\"warn\", message, ...args);\n }\n\n error(message: string, ...args: any[]): void {\n this.consolaInstance.error(message, ...args);\n this.logToFile(\"error\", message, ...args);\n }\n\n debug(message: string, ...args: any[]): void {\n this.consolaInstance.debug(message, ...args);\n this.logToFile(\"debug\", message, ...args);\n }\n\n log(message: string, ...args: any[]): void {\n this.consolaInstance.log(message, ...args);\n this.logToFile(\"log\", message, ...args);\n }\n\n /**\n * 创建一个带标签的日志实例(已废弃,直接返回原实例)\n * @param tag 标签(不再使用)\n * @deprecated 标签功能已移除\n */\n withTag(tag: string): Logger {\n // 不再添加标签,直接返回共享实例\n return this;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n if (this.writeStream) {\n this.writeStream.end();\n this.writeStream = null;\n }\n }\n}\n\n// 导出单例实例\nexport const logger = new Logger();\n"],"mappings":"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","names":["WebSocket","fs","path","chalk","createConsola","formatDateTime","date","year","month","day","hours","minutes","seconds","__name","Logger","createConsola","isDaemonMode","logObj","levelMap","colorMap","chalk","text","level","colorFn","timestamp","coloredLevel","message","error","projectDir","path","fs","args","formattedMessage","fullMessage","arg","enable","tag","logger","ProxyMCPServer","__name","endpointUrl","options","Logger","serviceManager","allTools","newTools","toolInfo","error","name","tool","tools","resolve","reject","WebSocket","data","message","code","reason","interval","jitterRange","jitter","request","toolsList","id","result","response"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { AppConfig } from './configManager.js';
|
|
2
|
+
|
|
3
|
+
interface ClientInfo {
|
|
4
|
+
status: "connected" | "disconnected";
|
|
5
|
+
mcpEndpoint: string;
|
|
6
|
+
activeMCPServers: string[];
|
|
7
|
+
lastHeartbeat?: number;
|
|
8
|
+
}
|
|
9
|
+
declare class WebServer {
|
|
10
|
+
private app;
|
|
11
|
+
private httpServer;
|
|
12
|
+
private wss;
|
|
13
|
+
private logger;
|
|
14
|
+
private port;
|
|
15
|
+
private clientInfo;
|
|
16
|
+
private heartbeatTimeout?;
|
|
17
|
+
private readonly HEARTBEAT_TIMEOUT;
|
|
18
|
+
private proxyMCPServer;
|
|
19
|
+
private xiaozhiConnectionManager;
|
|
20
|
+
private mcpServiceManager;
|
|
21
|
+
constructor(port?: number);
|
|
22
|
+
/**
|
|
23
|
+
* 初始化所有连接(配置驱动)
|
|
24
|
+
*/
|
|
25
|
+
private initializeConnections;
|
|
26
|
+
/**
|
|
27
|
+
* 加载配置文件
|
|
28
|
+
*/
|
|
29
|
+
private loadConfiguration;
|
|
30
|
+
/**
|
|
31
|
+
* 从配置加载 MCP 服务
|
|
32
|
+
*/
|
|
33
|
+
private loadMCPServicesFromConfig;
|
|
34
|
+
/**
|
|
35
|
+
* 初始化小智接入点连接
|
|
36
|
+
*/
|
|
37
|
+
private initializeXiaozhiConnection;
|
|
38
|
+
/**
|
|
39
|
+
* 获取最佳的小智连接(用于向后兼容)
|
|
40
|
+
*/
|
|
41
|
+
private getBestXiaozhiConnection;
|
|
42
|
+
/**
|
|
43
|
+
* 获取小智连接状态信息
|
|
44
|
+
*/
|
|
45
|
+
getXiaozhiConnectionStatus(): any;
|
|
46
|
+
/**
|
|
47
|
+
* 带重试的连接方法
|
|
48
|
+
*/
|
|
49
|
+
private connectWithRetry;
|
|
50
|
+
/**
|
|
51
|
+
* 延迟工具方法
|
|
52
|
+
*/
|
|
53
|
+
private sleep;
|
|
54
|
+
private setupMiddleware;
|
|
55
|
+
private setupRoutes;
|
|
56
|
+
private serveStaticFile;
|
|
57
|
+
private setupWebSocket;
|
|
58
|
+
private handleWebSocketMessage;
|
|
59
|
+
private sendInitialData;
|
|
60
|
+
broadcastConfigUpdate(config: AppConfig): void;
|
|
61
|
+
private broadcastRestartStatus;
|
|
62
|
+
private broadcastStatusUpdate;
|
|
63
|
+
private updateClientInfo;
|
|
64
|
+
private resetHeartbeatTimeout;
|
|
65
|
+
private updateConfig;
|
|
66
|
+
private restartService;
|
|
67
|
+
updateStatus(info: Partial<ClientInfo>): void;
|
|
68
|
+
start(): Promise<void>;
|
|
69
|
+
stop(): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { WebServer };
|