xiaozhi-client 0.0.1 → 1.0.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.
@@ -1,493 +1,8 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
- // If the importer is in node compatibility mode or this is not an ESM
20
- // file that has been converted to a CommonJS file using a Babel-
21
- // compatible transform (i.e. "__esModule" has not been set), then set
22
- // "default" to the CommonJS "module.exports" for node compatibility.
23
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
- mod
25
- ));
26
- var import_child_process = require("child_process");
27
- var import_fs = require("fs");
28
- var import_path = require("path");
29
- var import_process = __toESM(require("process"));
30
- var import_configManager = require("./configManager.cjs");
31
- const logger = {
32
- info: /* @__PURE__ */ __name((message) => {
33
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
34
- console.error(`${timestamp} - MCPProxy - INFO - ${message}`);
35
- }, "info"),
36
- error: /* @__PURE__ */ __name((message) => {
37
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
38
- console.error(`${timestamp} - MCPProxy - ERROR - ${message}`);
39
- }, "error"),
40
- debug: /* @__PURE__ */ __name((message) => {
41
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
42
- console.error(`${timestamp} - MCPProxy - DEBUG - ${message}`);
43
- }, "debug")
44
- };
45
- class MCPClient {
46
- static {
47
- __name(this, "MCPClient");
48
- }
49
- name;
50
- config;
51
- process;
52
- initialized;
53
- tools;
54
- requestId;
55
- pendingRequests;
56
- messageBuffer;
57
- constructor(name, config) {
58
- this.name = name;
59
- this.config = config;
60
- this.process = null;
61
- this.initialized = false;
62
- this.tools = [];
63
- this.requestId = 1;
64
- this.pendingRequests = /* @__PURE__ */ new Map();
65
- this.messageBuffer = "";
66
- }
67
- async start() {
68
- logger.info(`Starting MCP client for ${this.name}`);
69
- const { command, args, env } = this.config;
70
- const spawnOptions = {
71
- stdio: ["pipe", "pipe", "pipe"]
72
- };
73
- if (env) {
74
- spawnOptions.env = { ...import_process.default.env, ...env };
75
- }
76
- this.process = (0, import_child_process.spawn)(command, args, spawnOptions);
77
- this.process.stdout?.on("data", (data) => {
78
- this.handleStdoutData(data.toString());
79
- });
80
- this.process.stderr?.on("data", (data) => {
81
- logger.debug(`${this.name} stderr: ${data.toString().trim()}`);
82
- });
83
- this.process.on("exit", (code, signal) => {
84
- logger.error(`${this.name} process exited with code ${code}, signal ${signal}`);
85
- this.initialized = false;
86
- });
87
- this.process.on("error", (error) => {
88
- logger.error(`${this.name} process error: ${error.message}`);
89
- this.initialized = false;
90
- });
91
- await this.initialize();
92
- }
93
- handleStdoutData(data) {
94
- this.messageBuffer += data;
95
- const lines = this.messageBuffer.split("\n");
96
- this.messageBuffer = lines.pop() || "";
97
- for (const line of lines) {
98
- if (line.trim()) {
99
- try {
100
- const message = JSON.parse(line.trim());
101
- this.handleMessage(message);
102
- } catch (error) {
103
- logger.error(`${this.name} failed to parse message: ${line.trim()}`);
104
- }
105
- }
106
- }
107
- }
108
- handleMessage(message) {
109
- logger.debug(`${this.name} received: ${JSON.stringify(message).substring(0, 200)}...`);
110
- if (message.id && this.pendingRequests.has(message.id)) {
111
- const pendingRequest = this.pendingRequests.get(message.id);
112
- if (pendingRequest) {
113
- const { resolve: resolve2, reject } = pendingRequest;
114
- this.pendingRequests.delete(message.id);
115
- if (message.error) {
116
- reject(new Error(`${message.error.message} (code: ${message.error.code})`));
117
- } else {
118
- resolve2(message.result);
119
- }
120
- }
121
- }
122
- }
123
- async sendRequest(method, params = {}) {
124
- if (!this.process || !this.process.stdin) {
125
- throw new Error(`${this.name} process not available`);
126
- }
127
- const id = this.requestId++;
128
- const request = {
129
- jsonrpc: "2.0",
130
- id,
131
- method,
132
- params
133
- };
134
- return new Promise((resolve2, reject) => {
135
- this.pendingRequests.set(id, { resolve: resolve2, reject });
136
- setTimeout(() => {
137
- if (this.pendingRequests.has(id)) {
138
- this.pendingRequests.delete(id);
139
- reject(new Error(`Request timeout for ${method}`));
140
- }
141
- }, 3e4);
142
- const message = JSON.stringify(request) + "\n";
143
- logger.debug(`${this.name} sending: ${message.trim()}`);
144
- this.process.stdin.write(message);
145
- });
146
- }
147
- async initialize() {
148
- try {
149
- const initResult = await this.sendRequest("initialize", {
150
- protocolVersion: "2024-11-05",
151
- capabilities: {},
152
- clientInfo: {
153
- name: "MCPProxy",
154
- version: "0.3.0"
155
- }
156
- });
157
- logger.info(`${this.name} initialized with capabilities: ${JSON.stringify(initResult.capabilities)}`);
158
- const notification = {
159
- jsonrpc: "2.0",
160
- method: "notifications/initialized"
161
- };
162
- this.process.stdin.write(JSON.stringify(notification) + "\n");
163
- await this.refreshTools();
164
- this.initialized = true;
165
- logger.info(`${this.name} client ready with ${this.tools.length} tools`);
166
- } catch (error) {
167
- logger.error(`Failed to initialize ${this.name}: ${error instanceof Error ? error.message : String(error)}`);
168
- throw error;
169
- }
170
- }
171
- async refreshTools() {
172
- try {
173
- const result = await this.sendRequest("tools/list");
174
- this.tools = result.tools || [];
175
- logger.info(`${this.name} loaded ${this.tools.length} tools: ${this.tools.map((t) => t.name).join(", ")}`);
176
- } catch (error) {
177
- logger.error(`Failed to get tools from ${this.name}: ${error instanceof Error ? error.message : String(error)}`);
178
- this.tools = [];
179
- }
180
- }
181
- async callTool(name, arguments_) {
182
- try {
183
- const result = await this.sendRequest("tools/call", {
184
- name,
185
- arguments: arguments_
186
- });
187
- return result;
188
- } catch (error) {
189
- logger.error(`Failed to call tool ${name} on ${this.name}: ${error instanceof Error ? error.message : String(error)}`);
190
- throw error;
191
- }
192
- }
193
- stop() {
194
- if (this.process) {
195
- logger.info(`Stopping ${this.name} client`);
196
- this.process.kill("SIGTERM");
197
- this.process = null;
198
- }
199
- this.initialized = false;
200
- }
201
- }
202
- function loadMCPConfig() {
203
- try {
204
- if (import_configManager.configManager.configExists()) {
205
- const mcpServers = import_configManager.configManager.getMcpServers();
206
- logger.info(`\u4ECE\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u4E86 ${Object.keys(mcpServers).length} \u4E2A MCP \u670D\u52A1`);
207
- return mcpServers;
208
- }
209
- const legacyConfigPath = (0, import_path.resolve)(__dirname, "mcp_server.json");
210
- if (import_fs.readFileSync) {
211
- try {
212
- const configData = (0, import_fs.readFileSync)(legacyConfigPath, "utf8");
213
- const config = JSON.parse(configData);
214
- if (!config.mcpServers || typeof config.mcpServers !== "object") {
215
- throw new Error("Invalid configuration: mcpServers section not found or invalid");
216
- }
217
- logger.info(`\u4ECE\u65E7\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u4E86 ${Object.keys(config.mcpServers).length} \u4E2A MCP \u670D\u52A1\uFF08\u5EFA\u8BAE\u8FC1\u79FB\u5230\u65B0\u914D\u7F6E\u683C\u5F0F\uFF09`);
218
- return config.mcpServers;
219
- } catch (legacyError) {
220
- logger.error('\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E');
221
- throw new Error('\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E');
222
- }
223
- }
224
- throw new Error('\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E');
225
- } catch (error) {
226
- logger.error(`Failed to load MCP configuration: ${error instanceof Error ? error.message : String(error)}`);
227
- throw error;
228
- }
229
- }
230
- __name(loadMCPConfig, "loadMCPConfig");
231
- class MCPServerProxy {
232
- static {
233
- __name(this, "MCPServerProxy");
234
- }
235
- clients;
236
- toolMap;
237
- // Maps tool name to client name
238
- initialized;
239
- config;
240
- constructor() {
241
- this.clients = /* @__PURE__ */ new Map();
242
- this.toolMap = /* @__PURE__ */ new Map();
243
- this.initialized = false;
244
- this.config = null;
245
- }
246
- async start() {
247
- logger.info("Starting MCP Server Proxy");
248
- this.config = loadMCPConfig();
249
- const clientPromises = [];
250
- for (const [serverName, serverConfig] of Object.entries(this.config)) {
251
- logger.info(`Initializing MCP client: ${serverName}`);
252
- const client = new MCPClient(serverName, serverConfig);
253
- this.clients.set(serverName, client);
254
- clientPromises.push(client.start());
255
- }
256
- try {
257
- const results = await Promise.allSettled(clientPromises);
258
- let successCount = 0;
259
- for (let i = 0; i < results.length; i++) {
260
- const result = results[i];
261
- const serverName = Object.keys(this.config)[i];
262
- if (result.status === "fulfilled") {
263
- successCount++;
264
- logger.info(`Successfully started MCP client: ${serverName}`);
265
- } else {
266
- logger.error(`Failed to start MCP client ${serverName}: ${result.reason.message}`);
267
- this.clients.delete(serverName);
268
- }
269
- }
270
- if (successCount === 0) {
271
- throw new Error("No MCP clients started successfully");
272
- }
273
- this.buildToolMap();
274
- this.initialized = true;
275
- logger.info(`MCP Server Proxy initialized successfully with ${successCount}/${Object.keys(this.config).length} clients`);
276
- } catch (error) {
277
- logger.error(`Failed to start MCP clients: ${error instanceof Error ? error.message : String(error)}`);
278
- throw error;
279
- }
280
- }
281
- buildToolMap() {
282
- this.toolMap.clear();
283
- for (const [clientName, client] of this.clients) {
284
- for (const tool of client.tools) {
285
- if (this.toolMap.has(tool.name)) {
286
- logger.error(`Duplicate tool name: ${tool.name} (from ${clientName} and ${this.toolMap.get(tool.name)})`);
287
- } else {
288
- this.toolMap.set(tool.name, clientName);
289
- }
290
- }
291
- }
292
- logger.info(`Built tool map with ${this.toolMap.size} tools`);
293
- }
294
- getAllTools() {
295
- const allTools = [];
296
- for (const client of this.clients.values()) {
297
- allTools.push(...client.tools);
298
- }
299
- return allTools;
300
- }
301
- async callTool(toolName, arguments_) {
302
- const clientName = this.toolMap.get(toolName);
303
- if (!clientName) {
304
- throw new Error(`Unknown tool: ${toolName}`);
305
- }
306
- const client = this.clients.get(clientName);
307
- if (!client || !client.initialized) {
308
- throw new Error(`Client ${clientName} not available`);
309
- }
310
- return await client.callTool(toolName, arguments_);
311
- }
312
- stop() {
313
- logger.info("Stopping MCP Server Proxy");
314
- for (const client of this.clients.values()) {
315
- client.stop();
316
- }
317
- this.initialized = false;
318
- }
319
- }
320
- class JSONRPCServer {
321
- static {
322
- __name(this, "JSONRPCServer");
323
- }
324
- proxy;
325
- requestId;
326
- constructor(proxy) {
327
- this.proxy = proxy;
328
- this.requestId = 1;
329
- }
330
- async handleMessage(message) {
331
- try {
332
- const parsedMessage = JSON.parse(message);
333
- logger.debug(`Received request: ${JSON.stringify(parsedMessage).substring(0, 200)}...`);
334
- if (parsedMessage.method) {
335
- if (parsedMessage.id !== void 0) {
336
- const response = await this.handleRequest(parsedMessage);
337
- return JSON.stringify(response);
338
- } else {
339
- await this.handleNotification(parsedMessage);
340
- return null;
341
- }
342
- } else {
343
- throw new Error("Invalid JSON-RPC message");
344
- }
345
- } catch (error) {
346
- logger.error(`Error handling message: ${error instanceof Error ? error.message : String(error)}`);
347
- return JSON.stringify({
348
- jsonrpc: "2.0",
349
- id: null,
350
- error: {
351
- code: -32700,
352
- message: "Parse error"
353
- }
354
- });
355
- }
356
- }
357
- async handleRequest(request) {
358
- const { id, method, params = {} } = request;
359
- try {
360
- let result;
361
- switch (method) {
362
- case "initialize":
363
- result = await this.handleInitialize(params);
364
- break;
365
- case "tools/list":
366
- result = await this.handleToolsList(params);
367
- break;
368
- case "tools/call":
369
- result = await this.handleToolsCall(params);
370
- break;
371
- case "ping":
372
- result = await this.handlePing(params);
373
- break;
374
- default:
375
- throw new Error(`Unknown method: ${method}`);
376
- }
377
- return {
378
- jsonrpc: "2.0",
379
- id,
380
- result
381
- };
382
- } catch (error) {
383
- logger.error(`Error handling request ${method}: ${error instanceof Error ? error.message : String(error)}`);
384
- return {
385
- jsonrpc: "2.0",
386
- id,
387
- error: {
388
- code: -32603,
389
- message: error instanceof Error ? error.message : String(error)
390
- }
391
- };
392
- }
393
- }
394
- async handleNotification(notification) {
395
- const { method } = notification;
396
- switch (method) {
397
- case "notifications/initialized":
398
- logger.info("Client sent initialized notification");
399
- break;
400
- default:
401
- logger.debug(`Received notification: ${method}`);
402
- break;
403
- }
404
- }
405
- async handleInitialize(params) {
406
- logger.info(`Initialize request from client: ${JSON.stringify(params.clientInfo)}`);
407
- return {
408
- protocolVersion: "2024-11-05",
409
- capabilities: {
410
- tools: {
411
- listChanged: false
412
- }
413
- },
414
- serverInfo: {
415
- name: "MCPServerProxy",
416
- version: "0.3.0"
417
- }
418
- };
419
- }
420
- async handleToolsList(_params) {
421
- if (!this.proxy.initialized) {
422
- throw new Error("Proxy not initialized");
423
- }
424
- const tools = this.proxy.getAllTools();
425
- logger.info(`Returning ${tools.length} tools`);
426
- return {
427
- tools
428
- };
429
- }
430
- async handleToolsCall(params) {
431
- const { name, arguments: args } = params;
432
- if (!name) {
433
- throw new Error("Tool name is required");
434
- }
435
- logger.info(`Calling tool: ${name} with args: ${JSON.stringify(args)}`);
436
- const result = await this.proxy.callTool(name, args || {});
437
- return result;
438
- }
439
- async handlePing(_params) {
440
- logger.debug("Received ping request");
441
- return {};
442
- }
443
- }
444
- async function main() {
445
- logger.info("Starting MCP Server Proxy");
446
- const proxy = new MCPServerProxy();
447
- const jsonrpcServer = new JSONRPCServer(proxy);
448
- const cleanup = /* @__PURE__ */ __name(() => {
449
- logger.info("Shutting down MCP Server Proxy");
450
- proxy.stop();
451
- import_process.default.exit(0);
452
- }, "cleanup");
453
- import_process.default.on("SIGINT", cleanup);
454
- import_process.default.on("SIGTERM", cleanup);
455
- try {
456
- await proxy.start();
457
- import_process.default.stdin.setEncoding("utf8");
458
- let messageBuffer = "";
459
- import_process.default.stdin.on("data", async (data) => {
460
- messageBuffer += data;
461
- const lines = messageBuffer.split("\n");
462
- messageBuffer = lines.pop() || "";
463
- for (const line of lines) {
464
- if (line.trim()) {
465
- try {
466
- const response = await jsonrpcServer.handleMessage(line.trim());
467
- if (response) {
468
- import_process.default.stdout.write(response + "\n");
469
- }
470
- } catch (error) {
471
- logger.error(`Error processing message: ${error instanceof Error ? error.message : String(error)}`);
472
- }
473
- }
474
- }
475
- });
476
- import_process.default.stdin.on("end", () => {
477
- logger.info("stdin closed, shutting down");
478
- cleanup();
479
- });
480
- logger.info("MCP Server Proxy is running on stdio");
481
- } catch (error) {
482
- logger.error(`Failed to start MCP Server Proxy: ${error instanceof Error ? error.message : String(error)}`);
483
- import_process.default.exit(1);
484
- }
485
- }
486
- __name(main, "main");
487
- if (require.main === module) {
488
- main().catch((error) => {
489
- logger.error(`Unhandled error: ${error instanceof Error ? error.message : String(error)}`);
490
- import_process.default.exit(1);
491
- });
492
- }
2
+ "use strict";var p=Object.create;var f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,$=Object.prototype.hasOwnProperty;var g=(n,e)=>f(n,"name",{value:e,configurable:!0});var w=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of v(e))!$.call(n,o)&&o!==t&&f(n,o,{get:()=>e[o],enumerable:!(i=y(e,o))||i.enumerable});return n};var P=(n,e,t)=>(t=n!=null?p(S(n)):{},w(e||!n||!n.__esModule?f(t,"default",{value:n,enumerable:!0}):t,n));var m=require("node:child_process"),u=require("node:fs"),d=require("node:path"),l=P(require("node:process")),h=require("./configManager.cjs");const C=(0,d.dirname)(__filename),r={info:g(n=>{const e=new Date().toISOString();console.error(`${e} - MCPProxy - INFO - ${n}`)},"info"),error:g(n=>{const e=new Date().toISOString();console.error(`${e} - MCPProxy - ERROR - ${n}`)},"error"),debug:g(n=>{const e=new Date().toISOString();console.error(`${e} - MCPProxy - DEBUG - ${n}`)},"debug")};class b{static{g(this,"MCPClient")}name;config;process;initialized;tools;originalTools;requestId;pendingRequests;messageBuffer;constructor(e,t){this.name=e,this.config=t,this.process=null,this.initialized=!1,this.tools=[],this.originalTools=[],this.requestId=1,this.pendingRequests=new Map,this.messageBuffer=""}generatePrefixedToolName(e){return`${this.name.replace(/-/g,"_")}_xzcli_${e}`}getOriginalToolName(e){const i=`${this.name.replace(/-/g,"_")}_xzcli_`;return e.startsWith(i)?e.substring(i.length):null}async start(){r.info(`Starting MCP client for ${this.name}`);const{command:e,args:t,env:i}=this.config,o={stdio:["pipe","pipe","pipe"]},s=l.default.env.XIAOZHI_CONFIG_DIR||l.default.cwd();o.cwd=s,i?o.env={...l.default.env,...i}:o.env={...l.default.env},this.process=(0,m.spawn)(e,t,o),this.process.stdout?.on("data",a=>{this.handleStdoutData(a.toString())}),this.process.stderr?.on("data",a=>{r.debug(`${this.name} stderr: ${a.toString().trim()}`)}),this.process.on("exit",(a,c)=>{r.error(`${this.name} process exited with code ${a}, signal ${c}`),this.initialized=!1}),this.process.on("error",a=>{r.error(`${this.name} process error: ${a.message}`),this.initialized=!1}),await this.initialize()}handleStdoutData(e){this.messageBuffer=`${this.messageBuffer}${e}`;const t=this.messageBuffer.split(`
3
+ `);this.messageBuffer=t.pop()||"";for(const i of t)if(i.trim())try{const o=JSON.parse(i.trim());this.handleMessage(o)}catch{r.error(`${this.name} failed to parse message: ${i.trim()}`)}}handleMessage(e){if(r.debug(`${this.name} received: ${JSON.stringify(e).substring(0,200)}...`),e.id&&this.pendingRequests.has(e.id)){const t=this.pendingRequests.get(e.id);if(t){const{resolve:i,reject:o}=t;this.pendingRequests.delete(e.id),e.error?o(new Error(`${e.error.message} (code: ${e.error.code})`)):i(e.result)}}}async sendRequest(e,t={}){if(!this.process||!this.process.stdin)throw new Error(`${this.name} process not available`);const i=this.requestId++,o={jsonrpc:"2.0",id:i,method:e,params:t};return new Promise((s,a)=>{this.pendingRequests.set(i,{resolve:s,reject:a}),setTimeout(()=>{this.pendingRequests.has(i)&&(this.pendingRequests.delete(i),a(new Error(`Request timeout for ${e}`)))},3e4);const c=`${JSON.stringify(o)}
4
+ `;r.debug(`${this.name} sending: ${c.trim()}`),this.process?.stdin?.write(c)})}async initialize(){try{const e=await this.sendRequest("initialize",{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"MCPProxy",version:"0.3.0"}});r.info(`${this.name} initialized with capabilities: ${JSON.stringify(e.capabilities)}`);const t={jsonrpc:"2.0",method:"notifications/initialized"};this.process?.stdin?.write(`${JSON.stringify(t)}
5
+ `),await this.refreshTools(),this.initialized=!0,r.info(`${this.name} client ready with ${this.tools.length} tools`)}catch(e){throw r.error(`Failed to initialize ${this.name}: ${e instanceof Error?e.message:String(e)}`),e}}async refreshTools(){try{const e=await this.sendRequest("tools/list");this.originalTools=e.tools||[];const t=this.originalTools.map(i=>({...i,name:this.generatePrefixedToolName(i.name)}));this.tools=this.filterEnabledTools(t),await this.updateToolsConfig(),r.info(`${this.name} loaded ${this.originalTools.length} tools: ${this.originalTools.map(i=>i.name).join(", ")}`),r.info(`${this.name} enabled ${this.tools.length} tools: ${this.tools.map(i=>i.name).join(", ")}`)}catch(e){r.error(`Failed to get tools from ${this.name}: ${e instanceof Error?e.message:String(e)}`),this.tools=[],this.originalTools=[]}}filterEnabledTools(e){return e.filter(t=>{const i=this.getOriginalToolName(t.name);return i?h.configManager.isToolEnabled(this.name,i):!0})}async updateToolsConfig(){try{const e=h.configManager.getServerToolsConfig(this.name),t={};for(const o of this.originalTools){const s=e[o.name];t[o.name]={description:o.description||"",enable:s?.enable!==!1}}(Object.keys(t).some(o=>{const s=e[o],a=t[o];return!s||s.enable!==a.enable||s.description!==a.description})||Object.keys(e).length===0)&&(h.configManager.updateServerToolsConfig(this.name,t),r.info(`${this.name} updated tools configuration`))}catch(e){r.error(`Failed to update tools config for ${this.name}: ${e instanceof Error?e.message:String(e)}`)}}async callTool(e,t){try{const i=this.getOriginalToolName(e);if(!i)throw new Error(`Invalid tool name format: ${e}`);return await this.sendRequest("tools/call",{name:i,arguments:t})}catch(i){throw r.error(`Failed to call tool ${e} (original: ${this.getOriginalToolName(e)}) on ${this.name}: ${i instanceof Error?i.message:String(i)}`),i}}stop(){this.process&&(r.info(`Stopping ${this.name} client`),this.process.kill("SIGTERM"),this.process=null),this.initialized=!1}}function T(){try{if(h.configManager.configExists()){const e=h.configManager.getMcpServers();return r.info(`\u4ECE\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u4E86 ${Object.keys(e).length} \u4E2A MCP \u670D\u52A1`),e}const n=(0,d.resolve)(C,"mcp_server.json");if(u.readFileSync)try{const e=(0,u.readFileSync)(n,"utf8"),t=JSON.parse(e);if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("Invalid configuration: mcpServers section not found or invalid");return r.info(`\u4ECE\u65E7\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u4E86 ${Object.keys(t.mcpServers).length} \u4E2A MCP \u670D\u52A1\uFF08\u5EFA\u8BAE\u8FC1\u79FB\u5230\u65B0\u914D\u7F6E\u683C\u5F0F\uFF09`),t.mcpServers}catch{throw r.error('\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'),new Error('\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')}throw new Error('\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')}catch(n){throw r.error(`Failed to load MCP configuration: ${n instanceof Error?n.message:String(n)}`),n}}g(T,"loadMCPConfig");class M{static{g(this,"MCPServerProxy")}clients;toolMap;initialized;config;constructor(){this.clients=new Map,this.toolMap=new Map,this.initialized=!1,this.config=null}async start(){r.info("Starting MCP Server Proxy"),this.config=T();const e=[];for(const[t,i]of Object.entries(this.config)){r.info(`Initializing MCP client: ${t}`);const o=new b(t,i);this.clients.set(t,o),e.push(o.start())}try{const t=await Promise.allSettled(e);let i=0;for(let o=0;o<t.length;o++){const s=t[o],a=Object.keys(this.config)[o];s.status==="fulfilled"?(i++,r.info(`Successfully started MCP client: ${a}`)):(r.error(`Failed to start MCP client ${a}: ${s.reason.message}`),this.clients.delete(a))}if(i===0)throw new Error("No MCP clients started successfully");this.buildToolMap(),this.initialized=!0,r.info(`MCP Server Proxy initialized successfully with ${i}/${Object.keys(this.config).length} clients`)}catch(t){throw r.error(`Failed to start MCP clients: ${t instanceof Error?t.message:String(t)}`),t}}buildToolMap(){this.toolMap.clear();for(const[e,t]of this.clients)for(const i of t.tools)this.toolMap.has(i.name)?r.error(`Duplicate tool name: ${i.name} (from ${e} and ${this.toolMap.get(i.name)})`):this.toolMap.set(i.name,e);r.info(`Built tool map with ${this.toolMap.size} tools`),r.debug(`Tool map: ${Array.from(this.toolMap.keys()).join(", ")}`)}getAllTools(){const e=[];for(const t of this.clients.values())e.push(...t.tools);return e}getAllServers(){const e=[];for(const[t,i]of this.clients)e.push({name:t,toolCount:i.originalTools.length,enabledToolCount:i.tools.length});return e}getServerTools(e){const t=this.clients.get(e);if(!t)throw new Error(`Server ${e} not found`);return t.originalTools.map(i=>({name:i.name,description:i.description||"",enabled:h.configManager.isToolEnabled(e,i.name)}))}async refreshServerTools(e){const t=this.clients.get(e);if(!t)throw new Error(`Server ${e} not found`);await t.refreshTools(),this.buildToolMap()}async refreshAllTools(){const e=Array.from(this.clients.values()).map(t=>t.refreshTools());await Promise.allSettled(e),this.buildToolMap()}async callTool(e,t){const i=this.toolMap.get(e);if(!i)throw new Error(`Unknown tool: ${e}`);const o=this.clients.get(i);if(!o||!o.initialized)throw new Error(`Client ${i} not available`);return await o.callTool(e,t)}stop(){r.info("Stopping MCP Server Proxy");for(const e of this.clients.values())e.stop();this.initialized=!1}}class E{static{g(this,"JSONRPCServer")}proxy;requestId;constructor(e){this.proxy=e,this.requestId=1}async handleMessage(e){try{const t=JSON.parse(e);if(r.debug(`Received request: ${JSON.stringify(t).substring(0,200)}...`),t.method){if(t.id!==void 0){const i=await this.handleRequest(t);return JSON.stringify(i)}return await this.handleNotification(t),null}throw new Error("Invalid JSON-RPC message")}catch(t){return r.error(`Error handling message: ${t instanceof Error?t.message:String(t)}`),JSON.stringify({jsonrpc:"2.0",id:null,error:{code:-32700,message:"Parse error"}})}}async handleRequest(e){const{id:t,method:i,params:o={}}=e;try{let s;switch(i){case"initialize":s=await this.handleInitialize(o);break;case"tools/list":s=await this.handleToolsList(o);break;case"tools/call":s=await this.handleToolsCall(o);break;case"ping":s=await this.handlePing(o);break;default:throw new Error(`Unknown method: ${i}`)}return{jsonrpc:"2.0",id:t,result:s}}catch(s){return r.error(`Error handling request ${i}: ${s instanceof Error?s.message:String(s)}`),{jsonrpc:"2.0",id:t,error:{code:-32603,message:s instanceof Error?s.message:String(s)}}}}async handleNotification(e){const{method:t}=e;switch(t){case"notifications/initialized":r.info("Client sent initialized notification");break;default:r.debug(`Received notification: ${t}`);break}}async handleInitialize(e){return r.info(`Initialize request from client: ${JSON.stringify(e.clientInfo)}`),{protocolVersion:"2024-11-05",capabilities:{tools:{listChanged:!1}},serverInfo:{name:"MCPServerProxy",version:"0.3.0"}}}async handleToolsList(e){if(!this.proxy.initialized)throw new Error("Proxy not initialized");const t=this.proxy.getAllTools();return r.info(`Returning ${t.length} tools`),{tools:t}}async handleToolsCall(e){const{name:t,arguments:i}=e;if(!t)throw new Error("Tool name is required");return r.info(`Calling tool: ${t} with args: ${JSON.stringify(i)}`),await this.proxy.callTool(t,i||{})}async handlePing(e){return r.debug("Received ping request"),{}}}async function z(){r.info("Starting MCP Server Proxy");const n=new M,e=new E(n),t=g(()=>{r.info("Shutting down MCP Server Proxy"),n.stop(),l.default.exit(0)},"cleanup");l.default.on("SIGINT",t),l.default.on("SIGTERM",t);try{await n.start(),l.default.stdin.setEncoding("utf8");let i="";l.default.stdin.on("data",async o=>{i=`${i}${o}`;const s=i.split(`
6
+ `);i=s.pop()||"";for(const a of s)if(a.trim())try{const c=await e.handleMessage(a.trim());c&&l.default.stdout.write(`${c}
7
+ `)}catch(c){r.error(`Error processing message: ${c instanceof Error?c.message:String(c)}`)}}),l.default.stdin.on("end",()=>{r.info("stdin closed, shutting down"),t()}),r.info("MCP Server Proxy is running on stdio")}catch(i){r.error(`Failed to start MCP Server Proxy: ${i instanceof Error?i.message:String(i)}`),l.default.exit(1)}}g(z,"main"),require.main===module&&z().catch(n=>{r.error(`Unhandled error: ${n instanceof Error?n.message:String(n)}`),l.default.exit(1)});
493
8
  //# sourceMappingURL=mcpServerProxy.cjs.map