@xiaozhi-client/mcp-core 1.9.7-beta.5 → 1.9.7-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -53,144 +53,806 @@ var ToolCallError = class extends Error {
53
53
  }
54
54
  };
55
55
 
56
- // src/manager.ts
57
- import { EventEmitter } from "events";
58
- var MCPServiceManager = class extends EventEmitter {
56
+ // src/connection.ts
57
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
58
+
59
+ // src/transport-factory.ts
60
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
61
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
62
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
63
+ import { EventSource } from "eventsource";
64
+ var globalThisAny = typeof globalThis !== "undefined" ? globalThis : global;
65
+ if (typeof globalThisAny !== "undefined" && !globalThisAny.EventSource) {
66
+ globalThisAny.EventSource = EventSource;
67
+ }
68
+ function createTransport(config) {
69
+ console.debug(
70
+ `[TransportFactory] \u521B\u5EFA ${config.type} transport for ${config.name}`
71
+ );
72
+ switch (config.type) {
73
+ case "stdio" /* STDIO */:
74
+ return createStdioTransport(config);
75
+ case "sse" /* SSE */:
76
+ return createSSETransport(config);
77
+ case "streamable-http" /* STREAMABLE_HTTP */:
78
+ return createStreamableHTTPTransport(config);
79
+ default:
80
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${config.type}`);
81
+ }
82
+ }
83
+ __name(createTransport, "createTransport");
84
+ function createStdioTransport(config) {
85
+ if (!config.command) {
86
+ throw new Error("stdio transport \u9700\u8981 command \u914D\u7F6E");
87
+ }
88
+ return new StdioClientTransport({
89
+ command: config.command,
90
+ args: config.args || [],
91
+ env: config.env
92
+ // 传递环境变量
93
+ });
94
+ }
95
+ __name(createStdioTransport, "createStdioTransport");
96
+ function createSSETransport(config) {
97
+ if (!config.url) {
98
+ throw new Error("SSE transport \u9700\u8981 URL \u914D\u7F6E");
99
+ }
100
+ const url = new URL(config.url);
101
+ const options = createSSEOptions(config);
102
+ return new SSEClientTransport(url, options);
103
+ }
104
+ __name(createSSETransport, "createSSETransport");
105
+ function createStreamableHTTPTransport(config) {
106
+ if (!config.url) {
107
+ throw new Error("StreamableHTTP transport \u9700\u8981 URL \u914D\u7F6E");
108
+ }
109
+ const url = new URL(config.url);
110
+ const options = createStreamableHTTPOptions(config);
111
+ return new StreamableHTTPClientTransport(url, options);
112
+ }
113
+ __name(createStreamableHTTPTransport, "createStreamableHTTPTransport");
114
+ function createSSEOptions(config) {
115
+ const options = {};
116
+ if (config.apiKey) {
117
+ options.requestInit = {
118
+ headers: {
119
+ Authorization: `Bearer ${config.apiKey}`,
120
+ ...config.headers
121
+ }
122
+ };
123
+ } else if (config.headers) {
124
+ options.requestInit = {
125
+ headers: config.headers
126
+ };
127
+ }
128
+ return options;
129
+ }
130
+ __name(createSSEOptions, "createSSEOptions");
131
+ function createStreamableHTTPOptions(config) {
132
+ const options = {};
133
+ if (config.apiKey) {
134
+ options.requestInit = {
135
+ headers: {
136
+ Authorization: `Bearer ${config.apiKey}`,
137
+ ...config.headers
138
+ }
139
+ };
140
+ } else if (config.headers) {
141
+ options.requestInit = {
142
+ headers: config.headers
143
+ };
144
+ }
145
+ return options;
146
+ }
147
+ __name(createStreamableHTTPOptions, "createStreamableHTTPOptions");
148
+ function validateConfig(config) {
149
+ if (!config.name || typeof config.name !== "string") {
150
+ throw new Error("\u914D\u7F6E\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 name \u5B57\u6BB5");
151
+ }
152
+ if (config.type && !Object.values(MCPTransportType).includes(config.type)) {
153
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${config.type}`);
154
+ }
155
+ if (!config.type) {
156
+ throw new Error("\u4F20\u8F93\u7C7B\u578B\u672A\u8BBE\u7F6E\uFF0C\u8FD9\u5E94\u8BE5\u5728 inferTransportType \u4E2D\u5904\u7406");
157
+ }
158
+ switch (config.type) {
159
+ case "stdio" /* STDIO */:
160
+ if (!config.command) {
161
+ throw new Error("stdio \u7C7B\u578B\u9700\u8981 command \u5B57\u6BB5");
162
+ }
163
+ break;
164
+ case "sse" /* SSE */:
165
+ if (config.url === void 0 || config.url === null) {
166
+ throw new Error(`${config.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);
167
+ }
168
+ break;
169
+ case "streamable-http" /* STREAMABLE_HTTP */:
170
+ if (config.url === void 0 || config.url === null) {
171
+ throw new Error(`${config.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);
172
+ }
173
+ break;
174
+ default:
175
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${config.type}`);
176
+ }
177
+ }
178
+ __name(validateConfig, "validateConfig");
179
+ function getSupportedTypes() {
180
+ return [
181
+ "stdio" /* STDIO */,
182
+ "sse" /* SSE */,
183
+ "streamable-http" /* STREAMABLE_HTTP */
184
+ ];
185
+ }
186
+ __name(getSupportedTypes, "getSupportedTypes");
187
+ var TransportFactory = {
188
+ create: createTransport,
189
+ validateConfig,
190
+ getSupportedTypes
191
+ };
192
+
193
+ // src/utils/type-normalizer.ts
194
+ var TypeFieldNormalizer;
195
+ ((TypeFieldNormalizer2) => {
196
+ function normalizeTypeField2(config) {
197
+ if (!config || typeof config !== "object") {
198
+ return config;
199
+ }
200
+ const normalizedConfig = JSON.parse(JSON.stringify(config));
201
+ if (!("type" in normalizedConfig)) {
202
+ return normalizedConfig;
203
+ }
204
+ const originalType = normalizedConfig.type;
205
+ if (originalType === "sse" || originalType === "streamable-http") {
206
+ return normalizedConfig;
207
+ }
208
+ let normalizedType;
209
+ if (originalType === "streamableHttp" || originalType === "streamable_http") {
210
+ normalizedType = "streamable-http";
211
+ } else if (originalType === "s_se" || originalType === "s-se") {
212
+ normalizedType = "sse";
213
+ } else {
214
+ normalizedType = convertToKebabCase(originalType);
215
+ }
216
+ if (normalizedType === "sse" || normalizedType === "streamable-http") {
217
+ normalizedConfig.type = normalizedType;
218
+ if (originalType !== normalizedType) {
219
+ }
220
+ }
221
+ return normalizedConfig;
222
+ }
223
+ TypeFieldNormalizer2.normalizeTypeField = normalizeTypeField2;
224
+ __name(normalizeTypeField2, "normalizeTypeField");
225
+ function convertToKebabCase(str) {
226
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
227
+ }
228
+ __name(convertToKebabCase, "convertToKebabCase");
229
+ })(TypeFieldNormalizer || (TypeFieldNormalizer = {}));
230
+ function normalizeTypeField(config) {
231
+ return TypeFieldNormalizer.normalizeTypeField(config);
232
+ }
233
+ __name(normalizeTypeField, "normalizeTypeField");
234
+
235
+ // src/utils/validators.ts
236
+ function inferTransportTypeFromUrl(url, options) {
237
+ try {
238
+ const parsedUrl = new URL(url);
239
+ const pathname = parsedUrl.pathname;
240
+ if (pathname.endsWith("/sse")) {
241
+ return "sse" /* SSE */;
242
+ }
243
+ if (pathname.endsWith("/mcp")) {
244
+ return "streamable-http" /* STREAMABLE_HTTP */;
245
+ }
246
+ if (options?.serviceName) {
247
+ console.info(
248
+ `[MCP-${options.serviceName}] URL \u8DEF\u5F84 ${pathname} \u4E0D\u5339\u914D\u7279\u5B9A\u89C4\u5219\uFF0C\u9ED8\u8BA4\u63A8\u65AD\u4E3A streamable-http \u7C7B\u578B`
249
+ );
250
+ }
251
+ return "streamable-http" /* STREAMABLE_HTTP */;
252
+ } catch (error) {
253
+ if (options?.serviceName) {
254
+ console.warn(
255
+ `[MCP-${options.serviceName}] URL \u89E3\u6790\u5931\u8D25\uFF0C\u9ED8\u8BA4\u63A8\u65AD\u4E3A streamable-http \u7C7B\u578B`,
256
+ error
257
+ );
258
+ }
259
+ return "streamable-http" /* STREAMABLE_HTTP */;
260
+ }
261
+ }
262
+ __name(inferTransportTypeFromUrl, "inferTransportTypeFromUrl");
263
+ function inferTransportTypeFromConfig(config) {
264
+ if (config.type) {
265
+ const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(config);
266
+ return normalizedConfig;
267
+ }
268
+ if (config.command) {
269
+ return {
270
+ ...config,
271
+ type: "stdio" /* STDIO */
272
+ };
273
+ }
274
+ if (config.url !== void 0 && config.url !== null) {
275
+ const inferredType = inferTransportTypeFromUrl(config.url, {
276
+ serviceName: config.name
277
+ });
278
+ return {
279
+ ...config,
280
+ type: inferredType
281
+ };
282
+ }
283
+ throw new Error(
284
+ `\u65E0\u6CD5\u4E3A\u670D\u52A1 ${config.name} \u63A8\u65AD\u4F20\u8F93\u7C7B\u578B\u3002\u8BF7\u663E\u5F0F\u6307\u5B9A type \u5B57\u6BB5\uFF0C\u6216\u63D0\u4F9B command/url \u914D\u7F6E`
285
+ );
286
+ }
287
+ __name(inferTransportTypeFromConfig, "inferTransportTypeFromConfig");
288
+ function validateToolCallParams(params, options) {
289
+ const opts = {
290
+ validateName: true,
291
+ validateArguments: true,
292
+ allowEmptyArguments: true,
293
+ ...options
294
+ };
295
+ if (!params || typeof params !== "object") {
296
+ throw new ToolCallError(
297
+ -32602 /* INVALID_PARAMS */,
298
+ "\u8BF7\u6C42\u53C2\u6570\u5FC5\u987B\u662F\u5BF9\u8C61"
299
+ );
300
+ }
301
+ const paramsObj = params;
302
+ if (opts.validateName) {
303
+ if (!paramsObj.name || typeof paramsObj.name !== "string") {
304
+ throw new ToolCallError(
305
+ -32602 /* INVALID_PARAMS */,
306
+ "\u5DE5\u5177\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32"
307
+ );
308
+ }
309
+ }
310
+ if (opts.validateArguments && paramsObj.arguments !== void 0 && paramsObj.arguments !== null) {
311
+ if (typeof paramsObj.arguments !== "object" || Array.isArray(paramsObj.arguments)) {
312
+ throw new ToolCallError(
313
+ -32602 /* INVALID_PARAMS */,
314
+ "\u5DE5\u5177\u53C2\u6570\u5FC5\u987B\u662F\u5BF9\u8C61"
315
+ );
316
+ }
317
+ }
318
+ if (!opts.allowEmptyArguments && paramsObj.arguments !== void 0 && paramsObj.arguments !== null) {
319
+ const argsObj = paramsObj.arguments;
320
+ if (Object.keys(argsObj).length === 0) {
321
+ throw new ToolCallError(
322
+ -32602 /* INVALID_PARAMS */,
323
+ "\u5DE5\u5177\u53C2\u6570\u4E0D\u80FD\u4E3A\u7A7A"
324
+ );
325
+ }
326
+ }
327
+ if (opts.customValidator) {
328
+ const error = opts.customValidator(paramsObj);
329
+ if (error) {
330
+ throw new ToolCallError(-32602 /* INVALID_PARAMS */, error);
331
+ }
332
+ }
333
+ return {
334
+ name: paramsObj.name,
335
+ arguments: paramsObj.arguments
336
+ };
337
+ }
338
+ __name(validateToolCallParams, "validateToolCallParams");
339
+
340
+ // src/connection.ts
341
+ var MCPConnection = class {
59
342
  static {
60
- __name(this, "MCPServiceManager");
343
+ __name(this, "MCPConnection");
61
344
  }
62
- configs = {};
345
+ config;
346
+ client = null;
347
+ transport = null;
63
348
  tools = /* @__PURE__ */ new Map();
64
- isInitialized = false;
65
- constructor(configs) {
66
- super();
67
- if (configs) {
68
- this.configs = configs;
69
- }
349
+ connectionState = "disconnected" /* DISCONNECTED */;
350
+ connectionTimeout = null;
351
+ initialized = false;
352
+ callbacks;
353
+ constructor(config, callbacks) {
354
+ this.config = inferTransportTypeFromConfig(config);
355
+ this.callbacks = callbacks;
356
+ this.validateConfig();
70
357
  }
71
358
  /**
72
- * 添加服务配置
359
+ * 验证配置
73
360
  */
74
- addServiceConfig(name, config) {
75
- this.configs[name] = { ...config, name };
361
+ validateConfig() {
362
+ TransportFactory.validateConfig(this.config);
76
363
  }
77
364
  /**
78
- * 更新服务配置
365
+ * 连接到 MCP 服务
79
366
  */
80
- updateServiceConfig(name, config) {
81
- if (!this.configs[name]) {
82
- throw new Error(`\u670D\u52A1\u4E0D\u5B58\u5728: ${name}`);
367
+ async connect() {
368
+ if (this.connectionState === "connecting" /* CONNECTING */) {
369
+ throw new Error("\u8FDE\u63A5\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u8FDE\u63A5\u5B8C\u6210");
83
370
  }
84
- this.configs[name] = { ...config, name };
371
+ this.cleanupConnection();
372
+ return this.attemptConnection();
85
373
  }
86
374
  /**
87
- * 移除服务配置
375
+ * 尝试建立连接
88
376
  */
89
- removeServiceConfig(name) {
90
- delete this.configs[name];
377
+ async attemptConnection() {
378
+ this.connectionState = "connecting" /* CONNECTING */;
379
+ console.debug(
380
+ `[MCP-${this.config.name}] \u6B63\u5728\u8FDE\u63A5 MCP \u670D\u52A1: ${this.config.name}`
381
+ );
382
+ return new Promise((resolve, reject) => {
383
+ this.connectionTimeout = setTimeout(() => {
384
+ const error = new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.config.timeout || 1e4}ms)`);
385
+ this.handleConnectionError(error);
386
+ reject(error);
387
+ }, this.config.timeout || 1e4);
388
+ try {
389
+ this.client = new Client(
390
+ {
391
+ name: `xiaozhi-${this.config.name}-client`,
392
+ version: "1.0.0"
393
+ },
394
+ {
395
+ capabilities: {}
396
+ }
397
+ );
398
+ this.transport = TransportFactory.create(this.config);
399
+ this.client.connect(this.transport).then(async () => {
400
+ this.handleConnectionSuccess();
401
+ await this.refreshTools();
402
+ this.callbacks?.onConnected?.({
403
+ serviceName: this.config.name,
404
+ tools: this.getTools(),
405
+ connectionTime: /* @__PURE__ */ new Date()
406
+ });
407
+ resolve();
408
+ }).catch((error) => {
409
+ this.handleConnectionError(error);
410
+ reject(error);
411
+ });
412
+ } catch (error) {
413
+ this.handleConnectionError(error);
414
+ reject(error);
415
+ }
416
+ });
91
417
  }
92
418
  /**
93
- * 获取所有服务配置
419
+ * 处理连接成功
94
420
  */
95
- getServiceConfigs() {
96
- return { ...this.configs };
421
+ handleConnectionSuccess() {
422
+ if (this.connectionTimeout) {
423
+ clearTimeout(this.connectionTimeout);
424
+ this.connectionTimeout = null;
425
+ }
426
+ this.connectionState = "connected" /* CONNECTED */;
427
+ this.initialized = true;
428
+ console.info(
429
+ `[MCP-${this.config.name}] MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5\u5DF2\u5EFA\u7ACB`
430
+ );
97
431
  }
98
432
  /**
99
- * 启动所有服务
433
+ * 处理连接错误
100
434
  */
101
- async startAllServices() {
102
- if (this.isInitialized) {
103
- return;
435
+ handleConnectionError(error) {
436
+ this.connectionState = "disconnected" /* DISCONNECTED */;
437
+ this.initialized = false;
438
+ console.debug(`MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5\u9519\u8BEF:`, error.message);
439
+ if (this.connectionTimeout) {
440
+ clearTimeout(this.connectionTimeout);
441
+ this.connectionTimeout = null;
104
442
  }
105
- this.isInitialized = true;
106
- this.emit("initialized");
443
+ this.cleanupConnection();
444
+ this.callbacks?.onConnectionFailed?.({
445
+ serviceName: this.config.name,
446
+ error,
447
+ attempt: 0
448
+ });
107
449
  }
108
450
  /**
109
- * 启动单个服务
451
+ * 清理连接资源
110
452
  */
111
- async startService(serviceName) {
112
- if (!this.configs[serviceName]) {
113
- throw new Error(`\u670D\u52A1\u914D\u7F6E\u4E0D\u5B58\u5728: ${serviceName}`);
453
+ cleanupConnection() {
454
+ if (this.client) {
455
+ try {
456
+ this.client.close().catch(() => {
457
+ });
458
+ } catch (error) {
459
+ }
460
+ this.client = null;
461
+ }
462
+ this.transport = null;
463
+ if (this.connectionTimeout) {
464
+ clearTimeout(this.connectionTimeout);
465
+ this.connectionTimeout = null;
114
466
  }
115
- this.emit("serviceStarted", serviceName);
467
+ this.initialized = false;
116
468
  }
117
469
  /**
118
- * 获取所有工具列表
470
+ * 刷新工具列表
119
471
  */
120
- getAllTools(status = "all") {
121
- const allTools = Array.from(this.tools.values());
122
- if (status === "all") {
123
- return allTools;
472
+ async refreshTools() {
473
+ if (!this.client) {
474
+ throw new Error("\u5BA2\u6237\u7AEF\u672A\u521D\u59CB\u5316");
475
+ }
476
+ try {
477
+ const toolsResult = await this.client.listTools();
478
+ const tools = toolsResult.tools || [];
479
+ this.tools.clear();
480
+ for (const tool of tools) {
481
+ this.tools.set(tool.name, tool);
482
+ }
483
+ console.debug(
484
+ `${this.config.name} \u670D\u52A1\u52A0\u8F7D\u4E86 ${tools.length} \u4E2A\u5DE5\u5177: ${tools.map((t) => t.name).join(", ")}`
485
+ );
486
+ } catch (error) {
487
+ console.error(
488
+ `${this.config.name} \u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25:`,
489
+ error instanceof Error ? error.message : String(error)
490
+ );
491
+ throw error;
124
492
  }
125
- return allTools.filter(
126
- (tool) => status === "enabled" ? tool.enabled : !tool.enabled
127
- );
493
+ }
494
+ /**
495
+ * 断开连接
496
+ */
497
+ async disconnect() {
498
+ console.info(`\u4E3B\u52A8\u65AD\u5F00 MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5`);
499
+ this.cleanupConnection();
500
+ this.connectionState = "disconnected" /* DISCONNECTED */;
501
+ this.callbacks?.onDisconnected?.({
502
+ serviceName: this.config.name,
503
+ reason: "\u624B\u52A8\u65AD\u5F00",
504
+ disconnectionTime: /* @__PURE__ */ new Date()
505
+ });
506
+ }
507
+ /**
508
+ * 获取工具列表
509
+ */
510
+ getTools() {
511
+ return Array.from(this.tools.values());
128
512
  }
129
513
  /**
130
514
  * 调用工具
131
515
  */
132
- async callTool(toolName, _arguments_, _options) {
133
- const tool = this.tools.get(toolName);
134
- if (!tool) {
135
- throw new ToolCallError(
136
- -32601 /* TOOL_NOT_FOUND */,
137
- `\u5DE5\u5177\u4E0D\u5B58\u5728: ${toolName}`
138
- );
516
+ async callTool(name, arguments_) {
517
+ if (!this.client) {
518
+ throw new Error(`\u670D\u52A1 ${this.config.name} \u672A\u8FDE\u63A5`);
139
519
  }
140
- if (!tool.enabled) {
141
- throw new ToolCallError(
142
- -32001 /* SERVICE_UNAVAILABLE */,
143
- `\u5DE5\u5177\u5DF2\u7981\u7528: ${toolName}`
520
+ if (!this.tools.has(name)) {
521
+ throw new Error(`\u5DE5\u5177 ${name} \u5728\u670D\u52A1 ${this.config.name} \u4E2D\u4E0D\u5B58\u5728`);
522
+ }
523
+ console.debug(
524
+ `\u8C03\u7528 ${this.config.name} \u670D\u52A1\u7684\u5DE5\u5177 ${name}\uFF0C\u53C2\u6570:`,
525
+ JSON.stringify(arguments_)
526
+ );
527
+ try {
528
+ const result = await this.client.callTool({
529
+ name,
530
+ arguments: arguments_ || {}
531
+ });
532
+ console.debug(
533
+ `\u5DE5\u5177 ${name} \u8C03\u7528\u6210\u529F\uFF0C\u7ED3\u679C:`,
534
+ `${JSON.stringify(result).substring(0, 500)}...`
535
+ );
536
+ return result;
537
+ } catch (error) {
538
+ console.error(
539
+ `\u5DE5\u5177 ${name} \u8C03\u7528\u5931\u8D25:`,
540
+ error instanceof Error ? error.message : String(error)
144
541
  );
542
+ throw error;
145
543
  }
544
+ }
545
+ /**
546
+ * 获取服务配置
547
+ */
548
+ getConfig() {
549
+ return this.config;
550
+ }
551
+ /**
552
+ * 获取服务状态
553
+ */
554
+ getStatus() {
146
555
  return {
147
- content: [
148
- {
149
- type: "text",
150
- text: `\u5DE5\u5177 ${toolName} \u9700\u8981\u901A\u8FC7\u5B9E\u9645\u7684 MCP \u8FDE\u63A5\u8C03\u7528`
151
- }
152
- ],
153
- isError: false
556
+ name: this.config.name,
557
+ connected: this.connectionState === "connected" /* CONNECTED */,
558
+ initialized: this.initialized,
559
+ transportType: this.config.type || "streamable-http" /* STREAMABLE_HTTP */,
560
+ toolCount: this.tools.size,
561
+ connectionState: this.connectionState
154
562
  };
155
563
  }
156
564
  /**
157
- * 添加工具(用于测试或自定义工具)
565
+ * 检查是否已连接
158
566
  */
159
- addTool(tool) {
160
- this.tools.set(tool.name, tool);
567
+ isConnected() {
568
+ return this.connectionState === "connected" /* CONNECTED */ && this.initialized;
569
+ }
570
+ };
571
+
572
+ // src/manager.ts
573
+ import { EventEmitter } from "events";
574
+ var MCPManager = class extends EventEmitter {
575
+ static {
576
+ __name(this, "MCPManager");
577
+ }
578
+ connections = /* @__PURE__ */ new Map();
579
+ configs = /* @__PURE__ */ new Map();
580
+ constructor() {
581
+ super();
161
582
  }
162
583
  /**
163
- * 移除工具
584
+ * 添加 MCP 服务器配置
585
+ * @param name 服务器名称
586
+ * @param config 服务器配置
587
+ *
588
+ * @example
589
+ * ```typescript
590
+ * // 添加 stdio 服务
591
+ * manager.addServer('calculator', {
592
+ * type: 'stdio',
593
+ * command: 'node',
594
+ * args: ['calculator.js']
595
+ * });
596
+ *
597
+ * // 添加 HTTP 服务
598
+ * manager.addServer('web-search', {
599
+ * type: 'http',
600
+ * url: 'https://api.example.com/mcp',
601
+ * headers: {
602
+ * Authorization: 'Bearer your-api-key'
603
+ * }
604
+ * });
605
+ * ```
164
606
  */
165
- removeTool(toolName) {
166
- this.tools.delete(toolName);
607
+ addServer(name, config) {
608
+ if (this.configs.has(name)) {
609
+ throw new Error(`\u670D\u52A1 ${name} \u5DF2\u5B58\u5728`);
610
+ }
611
+ const fullConfig = {
612
+ ...config,
613
+ name
614
+ };
615
+ if (config.type) {
616
+ const typeStr = String(config.type);
617
+ if (typeStr === "http") {
618
+ fullConfig.type = "streamable-http" /* STREAMABLE_HTTP */;
619
+ } else if (typeStr === "sse") {
620
+ fullConfig.type = "sse" /* SSE */;
621
+ } else {
622
+ fullConfig.type = config.type;
623
+ }
624
+ }
625
+ this.configs.set(name, fullConfig);
167
626
  }
168
627
  /**
169
- * 获取管理器状态
628
+ * 移除服务器配置
629
+ * @param name 服务器名称
170
630
  */
171
- getStatus() {
172
- const availableTools = this.getAllTools("enabled").map((t) => t.name);
631
+ removeServer(name) {
632
+ return this.configs.delete(name);
633
+ }
634
+ /**
635
+ * 连接所有已添加的 MCP 服务
636
+ * 所有服务并行连接,单个服务失败不会影响其他服务
637
+ *
638
+ * @example
639
+ * ```typescript
640
+ * await manager.connect();
641
+ * ```
642
+ */
643
+ async connect() {
644
+ this.emit("connect");
645
+ const promises = Array.from(this.configs.entries()).map(
646
+ async ([name, config]) => {
647
+ try {
648
+ const connection = new MCPConnection(config, {
649
+ onConnected: /* @__PURE__ */ __name((data) => {
650
+ this.emit("connected", {
651
+ serverName: data.serviceName,
652
+ tools: data.tools
653
+ });
654
+ }, "onConnected"),
655
+ onDisconnected: /* @__PURE__ */ __name((data) => {
656
+ this.emit("disconnected", {
657
+ serverName: data.serviceName,
658
+ reason: data.reason
659
+ });
660
+ }, "onDisconnected"),
661
+ onConnectionFailed: /* @__PURE__ */ __name((data) => {
662
+ this.emit("error", {
663
+ serverName: data.serviceName,
664
+ error: data.error
665
+ });
666
+ }, "onConnectionFailed")
667
+ });
668
+ await connection.connect();
669
+ this.connections.set(name, connection);
670
+ } catch (error) {
671
+ this.emit("error", { serverName: name, error });
672
+ throw error;
673
+ }
674
+ }
675
+ );
676
+ await Promise.allSettled(promises);
677
+ }
678
+ /**
679
+ * 断开所有 MCP 服务连接
680
+ *
681
+ * @example
682
+ * ```typescript
683
+ * await manager.disconnect();
684
+ * ```
685
+ */
686
+ async disconnect() {
687
+ const promises = Array.from(this.connections.values()).map(
688
+ (conn) => conn.disconnect()
689
+ );
690
+ await Promise.allSettled(promises);
691
+ this.connections.clear();
692
+ this.emit("disconnect");
693
+ }
694
+ /**
695
+ * 调用指定服务的工具
696
+ * @param serverName 服务名称
697
+ * @param toolName 工具名称
698
+ * @param args 工具参数
699
+ *
700
+ * @example
701
+ * ```typescript
702
+ * const result = await manager.callTool('datetime', 'get_current_time', {
703
+ * format: 'YYYY-MM-DD HH:mm:ss'
704
+ * });
705
+ * ```
706
+ */
707
+ async callTool(serverName, toolName, args) {
708
+ const connection = this.connections.get(serverName);
709
+ if (!connection) {
710
+ throw new Error(`\u670D\u52A1 ${serverName} \u4E0D\u5B58\u5728`);
711
+ }
712
+ if (!connection.isConnected()) {
713
+ throw new Error(`\u670D\u52A1 ${serverName} \u672A\u8FDE\u63A5`);
714
+ }
715
+ return connection.callTool(toolName, args);
716
+ }
717
+ /**
718
+ * 列出所有可用的工具
719
+ * @returns 工具列表,格式为 [{ name, serverName, description, inputSchema }]
720
+ *
721
+ * @example
722
+ * ```typescript
723
+ * const tools = manager.listTools();
724
+ * console.log('可用工具:', tools.map(t => `${t.serverName}/${t.name}`));
725
+ * ```
726
+ */
727
+ listTools() {
728
+ const allTools = [];
729
+ for (const [serverName, connection] of this.connections) {
730
+ if (connection.isConnected()) {
731
+ const tools = connection.getTools();
732
+ for (const tool of tools) {
733
+ allTools.push({
734
+ name: tool.name,
735
+ serverName,
736
+ description: tool.description || "",
737
+ inputSchema: tool.inputSchema
738
+ });
739
+ }
740
+ }
741
+ }
742
+ return allTools;
743
+ }
744
+ /**
745
+ * 获取服务状态
746
+ * @param serverName 服务名称
747
+ * @returns 服务状态,如果服务不存在则返回 null
748
+ *
749
+ * @example
750
+ * ```typescript
751
+ * const status = manager.getServerStatus('datetime');
752
+ * if (status) {
753
+ * console.log(`已连接: ${status.connected}, 工具数: ${status.toolCount}`);
754
+ * }
755
+ * ```
756
+ */
757
+ getServerStatus(serverName) {
758
+ const connection = this.connections.get(serverName);
759
+ if (!connection) {
760
+ return null;
761
+ }
762
+ const status = connection.getStatus();
173
763
  return {
174
- services: {},
175
- totalTools: this.tools.size,
176
- availableTools
764
+ connected: status.connected,
765
+ toolCount: status.toolCount
177
766
  };
178
767
  }
179
768
  /**
180
- * 清理资源
769
+ * 获取所有服务的状态
770
+ * @returns 所有服务的状态映射
771
+ *
772
+ * @example
773
+ * ```typescript
774
+ * const statuses = manager.getAllServerStatus();
775
+ * console.log(statuses);
776
+ * // {
777
+ * // datetime: { connected: true, toolCount: 3 },
778
+ * // calculator: { connected: true, toolCount: 1 }
779
+ * // }
780
+ * ```
781
+ */
782
+ getAllServerStatus() {
783
+ const statuses = {};
784
+ for (const [serverName, connection] of this.connections) {
785
+ const status = connection.getStatus();
786
+ statuses[serverName] = {
787
+ connected: status.connected,
788
+ toolCount: status.toolCount
789
+ };
790
+ }
791
+ return statuses;
792
+ }
793
+ /**
794
+ * 检查服务是否已连接
795
+ * @param serverName 服务名称
796
+ *
797
+ * @example
798
+ * ```typescript
799
+ * if (manager.isConnected('datetime')) {
800
+ * console.log('datetime 服务已连接');
801
+ * }
802
+ * ```
803
+ */
804
+ isConnected(serverName) {
805
+ const connection = this.connections.get(serverName);
806
+ return connection ? connection.isConnected() : false;
807
+ }
808
+ /**
809
+ * 获取已配置的服务列表
810
+ * @returns 服务名称数组
811
+ *
812
+ * @example
813
+ * ```typescript
814
+ * const servers = manager.getServerNames();
815
+ * console.log('已配置的服务:', servers);
816
+ * ```
181
817
  */
182
- async cleanup() {
183
- this.tools.clear();
184
- this.isInitialized = false;
818
+ getServerNames() {
819
+ return Array.from(this.configs.keys());
820
+ }
821
+ /**
822
+ * 获取已连接的服务列表
823
+ * @returns 已连接的服务名称数组
824
+ *
825
+ * @example
826
+ * ```typescript
827
+ * const connectedServers = manager.getConnectedServerNames();
828
+ * console.log('已连接的服务:', connectedServers);
829
+ * ```
830
+ */
831
+ getConnectedServerNames() {
832
+ const connected = [];
833
+ for (const [serverName, connection] of this.connections) {
834
+ if (connection.isConnected()) {
835
+ connected.push(serverName);
836
+ }
837
+ }
838
+ return connected;
185
839
  }
186
840
  };
187
841
  export {
188
842
  ConnectionState,
189
- MCPServiceManager,
843
+ MCPConnection,
844
+ MCPManager,
845
+ MCPManager as MCPServiceManager,
190
846
  MCPTransportType,
191
847
  ToolCallError,
192
848
  ToolCallErrorCode,
849
+ TransportFactory,
850
+ TypeFieldNormalizer,
193
851
  ensureToolJSONSchema,
194
- isValidToolJSONSchema
852
+ inferTransportTypeFromConfig,
853
+ inferTransportTypeFromUrl,
854
+ isValidToolJSONSchema,
855
+ normalizeTypeField,
856
+ validateToolCallParams
195
857
  };
196
858
  //# sourceMappingURL=index.js.map