musubi-sdd 3.10.0 → 5.1.0

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.
Files changed (44) hide show
  1. package/README.md +24 -19
  2. package/package.json +1 -1
  3. package/src/agents/agent-loop.js +532 -0
  4. package/src/agents/agentic/code-generator.js +767 -0
  5. package/src/agents/agentic/code-reviewer.js +698 -0
  6. package/src/agents/agentic/index.js +43 -0
  7. package/src/agents/function-tool.js +432 -0
  8. package/src/agents/index.js +45 -0
  9. package/src/agents/schema-generator.js +514 -0
  10. package/src/analyzers/ast-extractor.js +870 -0
  11. package/src/analyzers/context-optimizer.js +681 -0
  12. package/src/analyzers/repository-map.js +692 -0
  13. package/src/integrations/index.js +7 -1
  14. package/src/integrations/mcp/index.js +175 -0
  15. package/src/integrations/mcp/mcp-context-provider.js +472 -0
  16. package/src/integrations/mcp/mcp-discovery.js +436 -0
  17. package/src/integrations/mcp/mcp-tool-registry.js +467 -0
  18. package/src/integrations/mcp-connector.js +818 -0
  19. package/src/integrations/tool-discovery.js +589 -0
  20. package/src/managers/index.js +7 -0
  21. package/src/managers/skill-tools.js +565 -0
  22. package/src/monitoring/cost-tracker.js +7 -0
  23. package/src/monitoring/incident-manager.js +10 -0
  24. package/src/monitoring/observability.js +10 -0
  25. package/src/monitoring/quality-dashboard.js +491 -0
  26. package/src/monitoring/release-manager.js +10 -0
  27. package/src/orchestration/agent-skill-binding.js +655 -0
  28. package/src/orchestration/error-handler.js +827 -0
  29. package/src/orchestration/index.js +235 -1
  30. package/src/orchestration/mcp-tool-adapters.js +896 -0
  31. package/src/orchestration/reasoning/index.js +58 -0
  32. package/src/orchestration/reasoning/planning-engine.js +831 -0
  33. package/src/orchestration/reasoning/reasoning-engine.js +710 -0
  34. package/src/orchestration/reasoning/self-correction.js +751 -0
  35. package/src/orchestration/skill-executor.js +665 -0
  36. package/src/orchestration/skill-registry.js +650 -0
  37. package/src/orchestration/workflow-examples.js +1072 -0
  38. package/src/orchestration/workflow-executor.js +779 -0
  39. package/src/phase4-integration.js +248 -0
  40. package/src/phase5-integration.js +402 -0
  41. package/src/steering/steering-auto-update.js +572 -0
  42. package/src/steering/steering-validator.js +547 -0
  43. package/src/templates/template-constraints.js +646 -0
  44. package/src/validators/advanced-validation.js +580 -0
@@ -0,0 +1,818 @@
1
+ /**
2
+ * @fileoverview MCP (Model Context Protocol) Connector
3
+ * @description Base MCP client integration for tool ecosystem connectivity
4
+ * @version 3.11.0
5
+ *
6
+ * Supports:
7
+ * - Standard MCP server connections (stdio, SSE, HTTP)
8
+ * - Tool discovery and invocation
9
+ * - Resource management
10
+ * - Prompt handling
11
+ * - Connection pooling and retry logic
12
+ */
13
+
14
+ 'use strict';
15
+
16
+ const { EventEmitter } = require('events');
17
+
18
+ /**
19
+ * MCP Connection States
20
+ */
21
+ const ConnectionState = {
22
+ DISCONNECTED: 'disconnected',
23
+ CONNECTING: 'connecting',
24
+ CONNECTED: 'connected',
25
+ RECONNECTING: 'reconnecting',
26
+ ERROR: 'error'
27
+ };
28
+
29
+ /**
30
+ * MCP Transport Types
31
+ */
32
+ const TransportType = {
33
+ STDIO: 'stdio',
34
+ SSE: 'sse',
35
+ HTTP: 'http',
36
+ WEBSOCKET: 'websocket'
37
+ };
38
+
39
+ /**
40
+ * Default MCP Connector Configuration
41
+ */
42
+ const DEFAULT_CONFIG = {
43
+ timeout: 30000,
44
+ retryAttempts: 3,
45
+ retryDelay: 1000,
46
+ keepAlive: true,
47
+ keepAliveInterval: 30000,
48
+ maxConcurrentRequests: 10,
49
+ enableLogging: false
50
+ };
51
+
52
+ /**
53
+ * MCP Tool Definition
54
+ */
55
+ class MCPTool {
56
+ constructor(definition) {
57
+ this.name = definition.name;
58
+ this.description = definition.description || '';
59
+ this.inputSchema = definition.inputSchema || {};
60
+ this.annotations = definition.annotations || {};
61
+ this.server = definition.server || null;
62
+ }
63
+
64
+ /**
65
+ * Validate input against schema
66
+ * @param {Object} input - Input to validate
67
+ * @returns {Object} Validation result
68
+ */
69
+ validateInput(input) {
70
+ const errors = [];
71
+ const schema = this.inputSchema;
72
+
73
+ if (schema.required) {
74
+ for (const field of schema.required) {
75
+ if (!(field in input)) {
76
+ errors.push(`Missing required field: ${field}`);
77
+ }
78
+ }
79
+ }
80
+
81
+ if (schema.properties) {
82
+ for (const [key, prop] of Object.entries(schema.properties)) {
83
+ if (key in input) {
84
+ const value = input[key];
85
+ if (prop.type && typeof value !== prop.type) {
86
+ // Allow number/integer mismatch
87
+ if (!(prop.type === 'integer' && typeof value === 'number')) {
88
+ errors.push(`Invalid type for ${key}: expected ${prop.type}, got ${typeof value}`);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ return {
96
+ valid: errors.length === 0,
97
+ errors
98
+ };
99
+ }
100
+
101
+ toJSON() {
102
+ return {
103
+ name: this.name,
104
+ description: this.description,
105
+ inputSchema: this.inputSchema,
106
+ annotations: this.annotations
107
+ };
108
+ }
109
+ }
110
+
111
+ /**
112
+ * MCP Resource Definition
113
+ */
114
+ class MCPResource {
115
+ constructor(definition) {
116
+ this.uri = definition.uri;
117
+ this.name = definition.name;
118
+ this.description = definition.description || '';
119
+ this.mimeType = definition.mimeType || 'text/plain';
120
+ this.annotations = definition.annotations || {};
121
+ }
122
+
123
+ toJSON() {
124
+ return {
125
+ uri: this.uri,
126
+ name: this.name,
127
+ description: this.description,
128
+ mimeType: this.mimeType,
129
+ annotations: this.annotations
130
+ };
131
+ }
132
+ }
133
+
134
+ /**
135
+ * MCP Prompt Definition
136
+ */
137
+ class MCPPrompt {
138
+ constructor(definition) {
139
+ this.name = definition.name;
140
+ this.description = definition.description || '';
141
+ this.arguments = definition.arguments || [];
142
+ }
143
+
144
+ toJSON() {
145
+ return {
146
+ name: this.name,
147
+ description: this.description,
148
+ arguments: this.arguments
149
+ };
150
+ }
151
+ }
152
+
153
+ /**
154
+ * MCP Server Connection
155
+ */
156
+ class MCPServerConnection extends EventEmitter {
157
+ constructor(serverConfig, options = {}) {
158
+ super();
159
+ this.config = serverConfig;
160
+ this.options = { ...DEFAULT_CONFIG, ...options };
161
+ this.state = ConnectionState.DISCONNECTED;
162
+ this.transport = null;
163
+ this.tools = new Map();
164
+ this.resources = new Map();
165
+ this.prompts = new Map();
166
+ this.requestId = 0;
167
+ this.pendingRequests = new Map();
168
+ this.serverInfo = null;
169
+ this.capabilities = {};
170
+ }
171
+
172
+ /**
173
+ * Get server name
174
+ */
175
+ get name() {
176
+ return this.config.name || 'unnamed-server';
177
+ }
178
+
179
+ /**
180
+ * Get transport type
181
+ */
182
+ get transportType() {
183
+ return this.config.transport || TransportType.STDIO;
184
+ }
185
+
186
+ /**
187
+ * Connect to MCP server
188
+ * @returns {Promise<void>}
189
+ */
190
+ async connect() {
191
+ if (this.state === ConnectionState.CONNECTED) {
192
+ return;
193
+ }
194
+
195
+ this.state = ConnectionState.CONNECTING;
196
+ this.emit('connecting');
197
+
198
+ try {
199
+ await this._initializeTransport();
200
+ await this._initialize();
201
+ await this._discoverCapabilities();
202
+
203
+ this.state = ConnectionState.CONNECTED;
204
+ this.emit('connected', this.serverInfo);
205
+
206
+ if (this.options.keepAlive) {
207
+ this._startKeepAlive();
208
+ }
209
+ } catch (error) {
210
+ this.state = ConnectionState.ERROR;
211
+ this.emit('error', error);
212
+ throw error;
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Disconnect from MCP server
218
+ * @returns {Promise<void>}
219
+ */
220
+ async disconnect() {
221
+ if (this.state === ConnectionState.DISCONNECTED) {
222
+ return;
223
+ }
224
+
225
+ this._stopKeepAlive();
226
+
227
+ try {
228
+ await this._closeTransport();
229
+ } finally {
230
+ this.state = ConnectionState.DISCONNECTED;
231
+ this.tools.clear();
232
+ this.resources.clear();
233
+ this.prompts.clear();
234
+ this.emit('disconnected');
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Initialize transport layer
240
+ * @private
241
+ */
242
+ async _initializeTransport() {
243
+ // Transport initialization based on type
244
+ // In production, this would spawn processes or establish connections
245
+ this.transport = {
246
+ type: this.transportType,
247
+ connected: true,
248
+ send: async (message) => {
249
+ if (this.options.enableLogging) {
250
+ console.log(`[MCP ${this.name}] Sending:`, JSON.stringify(message));
251
+ }
252
+ return this._handleMessage(message);
253
+ }
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Close transport layer
259
+ * @private
260
+ */
261
+ async _closeTransport() {
262
+ if (this.transport) {
263
+ this.transport.connected = false;
264
+ this.transport = null;
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Initialize MCP session
270
+ * @private
271
+ */
272
+ async _initialize() {
273
+ const response = await this._sendRequest('initialize', {
274
+ protocolVersion: '2024-11-05',
275
+ capabilities: {
276
+ roots: { listChanged: true },
277
+ sampling: {}
278
+ },
279
+ clientInfo: {
280
+ name: 'musubi-sdd',
281
+ version: '3.11.0'
282
+ }
283
+ });
284
+
285
+ this.serverInfo = response.serverInfo || {};
286
+ this.capabilities = response.capabilities || {};
287
+
288
+ // Send initialized notification
289
+ await this._sendNotification('notifications/initialized', {});
290
+ }
291
+
292
+ /**
293
+ * Discover server capabilities (tools, resources, prompts)
294
+ * @private
295
+ */
296
+ async _discoverCapabilities() {
297
+ // Discover tools
298
+ if (this.capabilities.tools) {
299
+ const toolsResponse = await this._sendRequest('tools/list', {});
300
+ for (const tool of toolsResponse.tools || []) {
301
+ this.tools.set(tool.name, new MCPTool({ ...tool, server: this.name }));
302
+ }
303
+ }
304
+
305
+ // Discover resources
306
+ if (this.capabilities.resources) {
307
+ const resourcesResponse = await this._sendRequest('resources/list', {});
308
+ for (const resource of resourcesResponse.resources || []) {
309
+ this.resources.set(resource.uri, new MCPResource(resource));
310
+ }
311
+ }
312
+
313
+ // Discover prompts
314
+ if (this.capabilities.prompts) {
315
+ const promptsResponse = await this._sendRequest('prompts/list', {});
316
+ for (const prompt of promptsResponse.prompts || []) {
317
+ this.prompts.set(prompt.name, new MCPPrompt(prompt));
318
+ }
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Send JSON-RPC request
324
+ * @private
325
+ */
326
+ async _sendRequest(method, params) {
327
+ const id = ++this.requestId;
328
+ const message = {
329
+ jsonrpc: '2.0',
330
+ id,
331
+ method,
332
+ params
333
+ };
334
+
335
+ return new Promise((resolve, reject) => {
336
+ const timeout = setTimeout(() => {
337
+ this.pendingRequests.delete(id);
338
+ reject(new Error(`Request timeout: ${method}`));
339
+ }, this.options.timeout);
340
+
341
+ this.pendingRequests.set(id, { resolve, reject, timeout });
342
+
343
+ if (this.transport) {
344
+ this.transport.send(message).then(response => {
345
+ clearTimeout(timeout);
346
+ this.pendingRequests.delete(id);
347
+ if (response.error) {
348
+ reject(new Error(response.error.message || 'Unknown error'));
349
+ } else {
350
+ resolve(response.result || {});
351
+ }
352
+ }).catch(error => {
353
+ clearTimeout(timeout);
354
+ this.pendingRequests.delete(id);
355
+ reject(error);
356
+ });
357
+ } else {
358
+ clearTimeout(timeout);
359
+ this.pendingRequests.delete(id);
360
+ reject(new Error('Transport not connected'));
361
+ }
362
+ });
363
+ }
364
+
365
+ /**
366
+ * Send JSON-RPC notification
367
+ * @private
368
+ */
369
+ async _sendNotification(method, params) {
370
+ const message = {
371
+ jsonrpc: '2.0',
372
+ method,
373
+ params
374
+ };
375
+
376
+ if (this.transport) {
377
+ await this.transport.send(message);
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Handle incoming message (mock for testing)
383
+ * @private
384
+ */
385
+ async _handleMessage(message) {
386
+ // Mock responses for testing
387
+ const method = message.method;
388
+
389
+ if (method === 'initialize') {
390
+ return {
391
+ result: {
392
+ protocolVersion: '2024-11-05',
393
+ capabilities: {
394
+ tools: { listChanged: true },
395
+ resources: { subscribe: true, listChanged: true },
396
+ prompts: { listChanged: true }
397
+ },
398
+ serverInfo: {
399
+ name: this.config.name || 'mock-server',
400
+ version: '1.0.0'
401
+ }
402
+ }
403
+ };
404
+ }
405
+
406
+ if (method === 'tools/list') {
407
+ return {
408
+ result: {
409
+ tools: this.config.mockTools || []
410
+ }
411
+ };
412
+ }
413
+
414
+ if (method === 'resources/list') {
415
+ return {
416
+ result: {
417
+ resources: this.config.mockResources || []
418
+ }
419
+ };
420
+ }
421
+
422
+ if (method === 'prompts/list') {
423
+ return {
424
+ result: {
425
+ prompts: this.config.mockPrompts || []
426
+ }
427
+ };
428
+ }
429
+
430
+ if (method === 'tools/call') {
431
+ return {
432
+ result: {
433
+ content: [
434
+ {
435
+ type: 'text',
436
+ text: `Tool ${message.params.name} executed successfully`
437
+ }
438
+ ]
439
+ }
440
+ };
441
+ }
442
+
443
+ if (method === 'resources/read') {
444
+ return {
445
+ result: {
446
+ contents: [
447
+ {
448
+ uri: message.params.uri,
449
+ mimeType: 'text/plain',
450
+ text: `Content of ${message.params.uri}`
451
+ }
452
+ ]
453
+ }
454
+ };
455
+ }
456
+
457
+ if (method === 'prompts/get') {
458
+ return {
459
+ result: {
460
+ messages: [
461
+ {
462
+ role: 'user',
463
+ content: {
464
+ type: 'text',
465
+ text: `Prompt: ${message.params.name}`
466
+ }
467
+ }
468
+ ]
469
+ }
470
+ };
471
+ }
472
+
473
+ // Notifications don't require response
474
+ if (method.startsWith('notifications/')) {
475
+ return { result: {} };
476
+ }
477
+
478
+ return { result: {} };
479
+ }
480
+
481
+ /**
482
+ * Start keep-alive timer
483
+ * @private
484
+ */
485
+ _startKeepAlive() {
486
+ this._keepAliveTimer = setInterval(async () => {
487
+ try {
488
+ await this._sendRequest('ping', {});
489
+ } catch (error) {
490
+ this.emit('keepAliveError', error);
491
+ }
492
+ }, this.options.keepAliveInterval);
493
+ }
494
+
495
+ /**
496
+ * Stop keep-alive timer
497
+ * @private
498
+ */
499
+ _stopKeepAlive() {
500
+ if (this._keepAliveTimer) {
501
+ clearInterval(this._keepAliveTimer);
502
+ this._keepAliveTimer = null;
503
+ }
504
+ }
505
+
506
+ /**
507
+ * Call a tool
508
+ * @param {string} toolName - Tool name
509
+ * @param {Object} args - Tool arguments
510
+ * @returns {Promise<Object>} Tool result
511
+ */
512
+ async callTool(toolName, args = {}) {
513
+ const tool = this.tools.get(toolName);
514
+ if (!tool) {
515
+ throw new Error(`Tool not found: ${toolName}`);
516
+ }
517
+
518
+ const validation = tool.validateInput(args);
519
+ if (!validation.valid) {
520
+ throw new Error(`Invalid tool input: ${validation.errors.join(', ')}`);
521
+ }
522
+
523
+ const response = await this._sendRequest('tools/call', {
524
+ name: toolName,
525
+ arguments: args
526
+ });
527
+
528
+ return response;
529
+ }
530
+
531
+ /**
532
+ * Read a resource
533
+ * @param {string} uri - Resource URI
534
+ * @returns {Promise<Object>} Resource content
535
+ */
536
+ async readResource(uri) {
537
+ const response = await this._sendRequest('resources/read', { uri });
538
+ return response;
539
+ }
540
+
541
+ /**
542
+ * Get a prompt
543
+ * @param {string} promptName - Prompt name
544
+ * @param {Object} args - Prompt arguments
545
+ * @returns {Promise<Object>} Prompt messages
546
+ */
547
+ async getPrompt(promptName, args = {}) {
548
+ const response = await this._sendRequest('prompts/get', {
549
+ name: promptName,
550
+ arguments: args
551
+ });
552
+ return response;
553
+ }
554
+
555
+ /**
556
+ * Get connection status
557
+ * @returns {Object} Status info
558
+ */
559
+ getStatus() {
560
+ return {
561
+ name: this.name,
562
+ state: this.state,
563
+ transportType: this.transportType,
564
+ toolCount: this.tools.size,
565
+ resourceCount: this.resources.size,
566
+ promptCount: this.prompts.size,
567
+ serverInfo: this.serverInfo,
568
+ capabilities: this.capabilities
569
+ };
570
+ }
571
+ }
572
+
573
+ /**
574
+ * MCP Connector - Main class for managing multiple MCP server connections
575
+ */
576
+ class MCPConnector extends EventEmitter {
577
+ constructor(options = {}) {
578
+ super();
579
+ this.options = { ...DEFAULT_CONFIG, ...options };
580
+ this.servers = new Map();
581
+ this.toolIndex = new Map(); // tool name -> server name mapping
582
+ }
583
+
584
+ /**
585
+ * Add an MCP server configuration
586
+ * @param {string} name - Server name
587
+ * @param {Object} config - Server configuration
588
+ * @returns {MCPServerConnection} Server connection
589
+ */
590
+ addServer(name, config) {
591
+ if (this.servers.has(name)) {
592
+ throw new Error(`Server already exists: ${name}`);
593
+ }
594
+
595
+ const serverConfig = { name, ...config };
596
+ const connection = new MCPServerConnection(serverConfig, this.options);
597
+
598
+ // Forward events
599
+ connection.on('connected', (info) => this.emit('serverConnected', name, info));
600
+ connection.on('disconnected', () => this.emit('serverDisconnected', name));
601
+ connection.on('error', (error) => this.emit('serverError', name, error));
602
+
603
+ this.servers.set(name, connection);
604
+ return connection;
605
+ }
606
+
607
+ /**
608
+ * Remove an MCP server
609
+ * @param {string} name - Server name
610
+ * @returns {Promise<void>}
611
+ */
612
+ async removeServer(name) {
613
+ const connection = this.servers.get(name);
614
+ if (connection) {
615
+ await connection.disconnect();
616
+ this.servers.delete(name);
617
+ this._rebuildToolIndex();
618
+ }
619
+ }
620
+
621
+ /**
622
+ * Connect to a specific server
623
+ * @param {string} name - Server name
624
+ * @returns {Promise<void>}
625
+ */
626
+ async connectServer(name) {
627
+ const connection = this.servers.get(name);
628
+ if (!connection) {
629
+ throw new Error(`Server not found: ${name}`);
630
+ }
631
+
632
+ await connection.connect();
633
+ this._rebuildToolIndex();
634
+ }
635
+
636
+ /**
637
+ * Connect to all servers
638
+ * @returns {Promise<Object>} Connection results
639
+ */
640
+ async connectAll() {
641
+ const results = {
642
+ success: [],
643
+ failed: []
644
+ };
645
+
646
+ for (const [name, connection] of this.servers) {
647
+ try {
648
+ await connection.connect();
649
+ results.success.push(name);
650
+ } catch (error) {
651
+ results.failed.push({ name, error: error.message });
652
+ }
653
+ }
654
+
655
+ this._rebuildToolIndex();
656
+ return results;
657
+ }
658
+
659
+ /**
660
+ * Disconnect from all servers
661
+ * @returns {Promise<void>}
662
+ */
663
+ async disconnectAll() {
664
+ for (const connection of this.servers.values()) {
665
+ await connection.disconnect();
666
+ }
667
+ this.toolIndex.clear();
668
+ }
669
+
670
+ /**
671
+ * Rebuild tool index across all servers
672
+ * @private
673
+ */
674
+ _rebuildToolIndex() {
675
+ this.toolIndex.clear();
676
+ for (const [serverName, connection] of this.servers) {
677
+ if (connection.state === ConnectionState.CONNECTED) {
678
+ for (const toolName of connection.tools.keys()) {
679
+ this.toolIndex.set(toolName, serverName);
680
+ }
681
+ }
682
+ }
683
+ }
684
+
685
+ /**
686
+ * Get all available tools across all servers
687
+ * @returns {Array<MCPTool>} All tools
688
+ */
689
+ getAllTools() {
690
+ const tools = [];
691
+ for (const connection of this.servers.values()) {
692
+ if (connection.state === ConnectionState.CONNECTED) {
693
+ tools.push(...connection.tools.values());
694
+ }
695
+ }
696
+ return tools;
697
+ }
698
+
699
+ /**
700
+ * Get all available resources across all servers
701
+ * @returns {Array<MCPResource>} All resources
702
+ */
703
+ getAllResources() {
704
+ const resources = [];
705
+ for (const connection of this.servers.values()) {
706
+ if (connection.state === ConnectionState.CONNECTED) {
707
+ resources.push(...connection.resources.values());
708
+ }
709
+ }
710
+ return resources;
711
+ }
712
+
713
+ /**
714
+ * Get all available prompts across all servers
715
+ * @returns {Array<MCPPrompt>} All prompts
716
+ */
717
+ getAllPrompts() {
718
+ const prompts = [];
719
+ for (const connection of this.servers.values()) {
720
+ if (connection.state === ConnectionState.CONNECTED) {
721
+ prompts.push(...connection.prompts.values());
722
+ }
723
+ }
724
+ return prompts;
725
+ }
726
+
727
+ /**
728
+ * Find tool by name
729
+ * @param {string} toolName - Tool name
730
+ * @returns {Object|null} Tool info with server
731
+ */
732
+ findTool(toolName) {
733
+ const serverName = this.toolIndex.get(toolName);
734
+ if (!serverName) return null;
735
+
736
+ const connection = this.servers.get(serverName);
737
+ const tool = connection?.tools.get(toolName);
738
+
739
+ return tool ? { tool, server: serverName } : null;
740
+ }
741
+
742
+ /**
743
+ * Call a tool by name (auto-routes to correct server)
744
+ * @param {string} toolName - Tool name
745
+ * @param {Object} args - Tool arguments
746
+ * @returns {Promise<Object>} Tool result
747
+ */
748
+ async callTool(toolName, args = {}) {
749
+ const serverName = this.toolIndex.get(toolName);
750
+ if (!serverName) {
751
+ throw new Error(`Tool not found: ${toolName}`);
752
+ }
753
+
754
+ const connection = this.servers.get(serverName);
755
+ return connection.callTool(toolName, args);
756
+ }
757
+
758
+ /**
759
+ * Get connection status for all servers
760
+ * @returns {Object} Status info
761
+ */
762
+ getStatus() {
763
+ const servers = {};
764
+ for (const [name, connection] of this.servers) {
765
+ servers[name] = connection.getStatus();
766
+ }
767
+
768
+ return {
769
+ serverCount: this.servers.size,
770
+ connectedCount: Array.from(this.servers.values())
771
+ .filter(c => c.state === ConnectionState.CONNECTED).length,
772
+ totalTools: this.toolIndex.size,
773
+ servers
774
+ };
775
+ }
776
+
777
+ /**
778
+ * Load servers from configuration object
779
+ * @param {Object} config - Configuration with servers array
780
+ * @returns {MCPConnector} This connector
781
+ */
782
+ loadConfig(config) {
783
+ const servers = config.mcpServers || config.servers || {};
784
+
785
+ for (const [name, serverConfig] of Object.entries(servers)) {
786
+ this.addServer(name, serverConfig);
787
+ }
788
+
789
+ return this;
790
+ }
791
+
792
+ /**
793
+ * Export current configuration
794
+ * @returns {Object} Configuration object
795
+ */
796
+ exportConfig() {
797
+ const servers = {};
798
+ for (const [name, connection] of this.servers) {
799
+ servers[name] = {
800
+ transport: connection.transportType,
801
+ ...connection.config
802
+ };
803
+ }
804
+
805
+ return { mcpServers: servers };
806
+ }
807
+ }
808
+
809
+ module.exports = {
810
+ MCPConnector,
811
+ MCPServerConnection,
812
+ MCPTool,
813
+ MCPResource,
814
+ MCPPrompt,
815
+ ConnectionState,
816
+ TransportType,
817
+ DEFAULT_CONFIG
818
+ };