@sparkleideas/shared 3.0.0-alpha.7
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/README.md +323 -0
- package/__tests__/hooks/bash-safety.test.ts +289 -0
- package/__tests__/hooks/file-organization.test.ts +335 -0
- package/__tests__/hooks/git-commit.test.ts +336 -0
- package/__tests__/hooks/index.ts +23 -0
- package/__tests__/hooks/session-hooks.test.ts +357 -0
- package/__tests__/hooks/task-hooks.test.ts +193 -0
- package/docs/EVENTS_IMPLEMENTATION_SUMMARY.md +388 -0
- package/docs/EVENTS_QUICK_REFERENCE.md +470 -0
- package/docs/EVENTS_README.md +352 -0
- package/package.json +39 -0
- package/src/core/config/defaults.ts +207 -0
- package/src/core/config/index.ts +15 -0
- package/src/core/config/loader.ts +271 -0
- package/src/core/config/schema.ts +188 -0
- package/src/core/config/validator.ts +209 -0
- package/src/core/event-bus.ts +236 -0
- package/src/core/index.ts +22 -0
- package/src/core/interfaces/agent.interface.ts +251 -0
- package/src/core/interfaces/coordinator.interface.ts +363 -0
- package/src/core/interfaces/event.interface.ts +267 -0
- package/src/core/interfaces/index.ts +19 -0
- package/src/core/interfaces/memory.interface.ts +332 -0
- package/src/core/interfaces/task.interface.ts +223 -0
- package/src/core/orchestrator/event-coordinator.ts +122 -0
- package/src/core/orchestrator/health-monitor.ts +214 -0
- package/src/core/orchestrator/index.ts +89 -0
- package/src/core/orchestrator/lifecycle-manager.ts +263 -0
- package/src/core/orchestrator/session-manager.ts +279 -0
- package/src/core/orchestrator/task-manager.ts +317 -0
- package/src/events/domain-events.ts +584 -0
- package/src/events/event-store.test.ts +387 -0
- package/src/events/event-store.ts +588 -0
- package/src/events/example-usage.ts +293 -0
- package/src/events/index.ts +90 -0
- package/src/events/projections.ts +561 -0
- package/src/events/state-reconstructor.ts +349 -0
- package/src/events.ts +367 -0
- package/src/hooks/INTEGRATION.md +658 -0
- package/src/hooks/README.md +532 -0
- package/src/hooks/example-usage.ts +499 -0
- package/src/hooks/executor.ts +379 -0
- package/src/hooks/hooks.test.ts +421 -0
- package/src/hooks/index.ts +131 -0
- package/src/hooks/registry.ts +333 -0
- package/src/hooks/safety/bash-safety.ts +604 -0
- package/src/hooks/safety/file-organization.ts +473 -0
- package/src/hooks/safety/git-commit.ts +623 -0
- package/src/hooks/safety/index.ts +46 -0
- package/src/hooks/session-hooks.ts +559 -0
- package/src/hooks/task-hooks.ts +513 -0
- package/src/hooks/types.ts +357 -0
- package/src/hooks/verify-exports.test.ts +125 -0
- package/src/index.ts +195 -0
- package/src/mcp/connection-pool.ts +438 -0
- package/src/mcp/index.ts +183 -0
- package/src/mcp/server.ts +774 -0
- package/src/mcp/session-manager.ts +428 -0
- package/src/mcp/tool-registry.ts +566 -0
- package/src/mcp/transport/http.ts +557 -0
- package/src/mcp/transport/index.ts +294 -0
- package/src/mcp/transport/stdio.ts +324 -0
- package/src/mcp/transport/websocket.ts +484 -0
- package/src/mcp/types.ts +565 -0
- package/src/plugin-interface.ts +663 -0
- package/src/plugin-loader.ts +638 -0
- package/src/plugin-registry.ts +604 -0
- package/src/plugins/index.ts +34 -0
- package/src/plugins/official/hive-mind-plugin.ts +330 -0
- package/src/plugins/official/index.ts +24 -0
- package/src/plugins/official/maestro-plugin.ts +508 -0
- package/src/plugins/types.ts +108 -0
- package/src/resilience/bulkhead.ts +277 -0
- package/src/resilience/circuit-breaker.ts +326 -0
- package/src/resilience/index.ts +26 -0
- package/src/resilience/rate-limiter.ts +420 -0
- package/src/resilience/retry.ts +224 -0
- package/src/security/index.ts +39 -0
- package/src/security/input-validation.ts +265 -0
- package/src/security/secure-random.ts +159 -0
- package/src/services/index.ts +16 -0
- package/src/services/v3-progress.service.ts +505 -0
- package/src/types/agent.types.ts +144 -0
- package/src/types/index.ts +22 -0
- package/src/types/mcp.types.ts +300 -0
- package/src/types/memory.types.ts +263 -0
- package/src/types/swarm.types.ts +255 -0
- package/src/types/task.types.ts +205 -0
- package/src/types.ts +367 -0
- package/src/utils/secure-logger.d.ts +69 -0
- package/src/utils/secure-logger.d.ts.map +1 -0
- package/src/utils/secure-logger.js +208 -0
- package/src/utils/secure-logger.js.map +1 -0
- package/src/utils/secure-logger.ts +257 -0
- package/tmp.json +0 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 MCP Server Implementation
|
|
3
|
+
*
|
|
4
|
+
* Optimized MCP server with:
|
|
5
|
+
* - Connection pooling for efficient resource usage
|
|
6
|
+
* - Fast tool registration (<10ms)
|
|
7
|
+
* - Optimized request routing (<50ms overhead)
|
|
8
|
+
* - Multiple transport support (stdio, http, websocket, in-process)
|
|
9
|
+
* - Session management with timeout handling
|
|
10
|
+
* - Comprehensive metrics and monitoring
|
|
11
|
+
*
|
|
12
|
+
* Performance Targets:
|
|
13
|
+
* - Server startup: <400ms
|
|
14
|
+
* - Tool registration: <10ms
|
|
15
|
+
* - Tool execution: <50ms overhead
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { EventEmitter } from 'events';
|
|
19
|
+
import { platform, arch } from 'os';
|
|
20
|
+
import {
|
|
21
|
+
MCPServerConfig,
|
|
22
|
+
MCPRequest,
|
|
23
|
+
MCPResponse,
|
|
24
|
+
MCPNotification,
|
|
25
|
+
MCPSession,
|
|
26
|
+
MCPTool,
|
|
27
|
+
MCPInitializeParams,
|
|
28
|
+
MCPInitializeResult,
|
|
29
|
+
MCPCapabilities,
|
|
30
|
+
MCPProtocolVersion,
|
|
31
|
+
MCPServerMetrics,
|
|
32
|
+
MCPServerError,
|
|
33
|
+
ErrorCodes,
|
|
34
|
+
ITransport,
|
|
35
|
+
TransportType,
|
|
36
|
+
ILogger,
|
|
37
|
+
ToolContext,
|
|
38
|
+
} from './types.js';
|
|
39
|
+
import { ToolRegistry, createToolRegistry } from './tool-registry.js';
|
|
40
|
+
import { SessionManager, createSessionManager } from './session-manager.js';
|
|
41
|
+
import { ConnectionPool, createConnectionPool } from './connection-pool.js';
|
|
42
|
+
import { createTransport, TransportManager, createTransportManager } from './transport/index.js';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Default server configuration
|
|
46
|
+
*/
|
|
47
|
+
const DEFAULT_CONFIG: Partial<MCPServerConfig> = {
|
|
48
|
+
name: 'Claude-Flow MCP Server V3',
|
|
49
|
+
version: '3.0.0',
|
|
50
|
+
transport: 'stdio',
|
|
51
|
+
host: 'localhost',
|
|
52
|
+
port: 3000,
|
|
53
|
+
enableMetrics: true,
|
|
54
|
+
enableCaching: true,
|
|
55
|
+
cacheTTL: 10000,
|
|
56
|
+
logLevel: 'info',
|
|
57
|
+
requestTimeout: 30000,
|
|
58
|
+
maxRequestSize: 10 * 1024 * 1024,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* MCP Server Interface
|
|
63
|
+
*/
|
|
64
|
+
export interface IMCPServer {
|
|
65
|
+
start(): Promise<void>;
|
|
66
|
+
stop(): Promise<void>;
|
|
67
|
+
registerTool(tool: MCPTool): boolean;
|
|
68
|
+
registerTools(tools: MCPTool[]): { registered: number; failed: string[] };
|
|
69
|
+
getHealthStatus(): Promise<{
|
|
70
|
+
healthy: boolean;
|
|
71
|
+
error?: string;
|
|
72
|
+
metrics?: Record<string, number>;
|
|
73
|
+
}>;
|
|
74
|
+
getMetrics(): MCPServerMetrics;
|
|
75
|
+
getSessions(): MCPSession[];
|
|
76
|
+
getSession(sessionId: string): MCPSession | undefined;
|
|
77
|
+
terminateSession(sessionId: string): boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* V3 MCP Server
|
|
82
|
+
*/
|
|
83
|
+
export class MCPServer extends EventEmitter implements IMCPServer {
|
|
84
|
+
private readonly config: MCPServerConfig;
|
|
85
|
+
private readonly toolRegistry: ToolRegistry;
|
|
86
|
+
private readonly sessionManager: SessionManager;
|
|
87
|
+
private readonly connectionPool?: ConnectionPool;
|
|
88
|
+
private readonly transportManager: TransportManager;
|
|
89
|
+
private transport?: ITransport;
|
|
90
|
+
private running = false;
|
|
91
|
+
private startTime?: Date;
|
|
92
|
+
private startupDuration?: number;
|
|
93
|
+
private currentSession?: MCPSession;
|
|
94
|
+
|
|
95
|
+
// Server information
|
|
96
|
+
private readonly serverInfo = {
|
|
97
|
+
name: 'Claude-Flow MCP Server V3',
|
|
98
|
+
version: '3.0.0',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Protocol version
|
|
102
|
+
private readonly protocolVersion: MCPProtocolVersion = {
|
|
103
|
+
major: 2024,
|
|
104
|
+
minor: 11,
|
|
105
|
+
patch: 5,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Server capabilities
|
|
109
|
+
private readonly capabilities: MCPCapabilities = {
|
|
110
|
+
logging: { level: 'info' },
|
|
111
|
+
tools: { listChanged: true },
|
|
112
|
+
resources: { listChanged: false, subscribe: false },
|
|
113
|
+
prompts: { listChanged: false },
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Request statistics
|
|
117
|
+
private requestStats = {
|
|
118
|
+
total: 0,
|
|
119
|
+
successful: 0,
|
|
120
|
+
failed: 0,
|
|
121
|
+
totalResponseTime: 0,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
constructor(
|
|
125
|
+
config: Partial<MCPServerConfig>,
|
|
126
|
+
private readonly logger: ILogger,
|
|
127
|
+
private readonly orchestrator?: unknown,
|
|
128
|
+
private readonly swarmCoordinator?: unknown
|
|
129
|
+
) {
|
|
130
|
+
super();
|
|
131
|
+
this.config = { ...DEFAULT_CONFIG, ...config } as MCPServerConfig;
|
|
132
|
+
|
|
133
|
+
// Initialize components
|
|
134
|
+
this.toolRegistry = createToolRegistry(logger);
|
|
135
|
+
this.sessionManager = createSessionManager(logger, {
|
|
136
|
+
maxSessions: 100,
|
|
137
|
+
sessionTimeout: 30 * 60 * 1000,
|
|
138
|
+
});
|
|
139
|
+
this.transportManager = createTransportManager(logger);
|
|
140
|
+
|
|
141
|
+
// Initialize connection pool if enabled
|
|
142
|
+
if (this.config.connectionPool) {
|
|
143
|
+
this.connectionPool = createConnectionPool(
|
|
144
|
+
this.config.connectionPool,
|
|
145
|
+
logger,
|
|
146
|
+
this.config.transport
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Setup event handlers
|
|
151
|
+
this.setupEventHandlers();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Start the MCP server
|
|
156
|
+
*/
|
|
157
|
+
async start(): Promise<void> {
|
|
158
|
+
if (this.running) {
|
|
159
|
+
throw new MCPServerError('Server already running');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const startTime = performance.now();
|
|
163
|
+
this.startTime = new Date();
|
|
164
|
+
|
|
165
|
+
this.logger.info('Starting MCP server', {
|
|
166
|
+
name: this.config.name,
|
|
167
|
+
version: this.config.version,
|
|
168
|
+
transport: this.config.transport,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
// Create and start transport
|
|
173
|
+
this.transport = createTransport(this.config.transport, this.logger, {
|
|
174
|
+
type: this.config.transport,
|
|
175
|
+
host: this.config.host,
|
|
176
|
+
port: this.config.port,
|
|
177
|
+
corsEnabled: this.config.corsEnabled,
|
|
178
|
+
corsOrigins: this.config.corsOrigins,
|
|
179
|
+
auth: this.config.auth,
|
|
180
|
+
maxRequestSize: String(this.config.maxRequestSize),
|
|
181
|
+
requestTimeout: this.config.requestTimeout,
|
|
182
|
+
} as any);
|
|
183
|
+
|
|
184
|
+
// Setup request handler
|
|
185
|
+
this.transport.onRequest(async (request) => {
|
|
186
|
+
return await this.handleRequest(request);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Setup notification handler
|
|
190
|
+
this.transport.onNotification(async (notification) => {
|
|
191
|
+
await this.handleNotification(notification);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Start transport
|
|
195
|
+
await this.transport.start();
|
|
196
|
+
|
|
197
|
+
// Register built-in tools
|
|
198
|
+
await this.registerBuiltInTools();
|
|
199
|
+
|
|
200
|
+
this.running = true;
|
|
201
|
+
this.startupDuration = performance.now() - startTime;
|
|
202
|
+
|
|
203
|
+
this.logger.info('MCP server started', {
|
|
204
|
+
startupTime: `${this.startupDuration.toFixed(2)}ms`,
|
|
205
|
+
tools: this.toolRegistry.getToolCount(),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
this.emit('server:started', {
|
|
209
|
+
startupTime: this.startupDuration,
|
|
210
|
+
tools: this.toolRegistry.getToolCount(),
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
} catch (error) {
|
|
214
|
+
this.logger.error('Failed to start MCP server', { error });
|
|
215
|
+
throw new MCPServerError('Failed to start server', ErrorCodes.INTERNAL_ERROR, { error });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Stop the MCP server
|
|
221
|
+
*/
|
|
222
|
+
async stop(): Promise<void> {
|
|
223
|
+
if (!this.running) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
this.logger.info('Stopping MCP server');
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
// Stop transport
|
|
231
|
+
if (this.transport) {
|
|
232
|
+
await this.transport.stop();
|
|
233
|
+
this.transport = undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Clear sessions
|
|
237
|
+
this.sessionManager.clearAll();
|
|
238
|
+
|
|
239
|
+
// Clear connection pool
|
|
240
|
+
if (this.connectionPool) {
|
|
241
|
+
await this.connectionPool.clear();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this.running = false;
|
|
245
|
+
this.currentSession = undefined;
|
|
246
|
+
|
|
247
|
+
this.logger.info('MCP server stopped');
|
|
248
|
+
this.emit('server:stopped');
|
|
249
|
+
|
|
250
|
+
} catch (error) {
|
|
251
|
+
this.logger.error('Error stopping MCP server', { error });
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Register a tool
|
|
258
|
+
*/
|
|
259
|
+
registerTool(tool: MCPTool): boolean {
|
|
260
|
+
return this.toolRegistry.register(tool);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Register multiple tools
|
|
265
|
+
*/
|
|
266
|
+
registerTools(tools: MCPTool[]): { registered: number; failed: string[] } {
|
|
267
|
+
return this.toolRegistry.registerBatch(tools);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Unregister a tool
|
|
272
|
+
*/
|
|
273
|
+
unregisterTool(name: string): boolean {
|
|
274
|
+
return this.toolRegistry.unregister(name);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get health status
|
|
279
|
+
*/
|
|
280
|
+
async getHealthStatus(): Promise<{
|
|
281
|
+
healthy: boolean;
|
|
282
|
+
error?: string;
|
|
283
|
+
metrics?: Record<string, number>;
|
|
284
|
+
}> {
|
|
285
|
+
try {
|
|
286
|
+
const transportHealth = this.transport
|
|
287
|
+
? await this.transport.getHealthStatus()
|
|
288
|
+
: { healthy: false, error: 'Transport not initialized' };
|
|
289
|
+
|
|
290
|
+
const sessionMetrics = this.sessionManager.getSessionMetrics();
|
|
291
|
+
const poolStats = this.connectionPool?.getStats();
|
|
292
|
+
|
|
293
|
+
const metrics: Record<string, number> = {
|
|
294
|
+
registeredTools: this.toolRegistry.getToolCount(),
|
|
295
|
+
totalRequests: this.requestStats.total,
|
|
296
|
+
successfulRequests: this.requestStats.successful,
|
|
297
|
+
failedRequests: this.requestStats.failed,
|
|
298
|
+
totalSessions: sessionMetrics.total,
|
|
299
|
+
activeSessions: sessionMetrics.active,
|
|
300
|
+
...(transportHealth.metrics || {}),
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
if (poolStats) {
|
|
304
|
+
metrics.poolConnections = poolStats.totalConnections;
|
|
305
|
+
metrics.poolIdleConnections = poolStats.idleConnections;
|
|
306
|
+
metrics.poolBusyConnections = poolStats.busyConnections;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
healthy: this.running && transportHealth.healthy,
|
|
311
|
+
error: transportHealth.error,
|
|
312
|
+
metrics,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
} catch (error) {
|
|
316
|
+
return {
|
|
317
|
+
healthy: false,
|
|
318
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get server metrics
|
|
325
|
+
*/
|
|
326
|
+
getMetrics(): MCPServerMetrics {
|
|
327
|
+
const sessionMetrics = this.sessionManager.getSessionMetrics();
|
|
328
|
+
const registryStats = this.toolRegistry.getStats();
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
totalRequests: this.requestStats.total,
|
|
332
|
+
successfulRequests: this.requestStats.successful,
|
|
333
|
+
failedRequests: this.requestStats.failed,
|
|
334
|
+
averageResponseTime: this.requestStats.total > 0
|
|
335
|
+
? this.requestStats.totalResponseTime / this.requestStats.total
|
|
336
|
+
: 0,
|
|
337
|
+
activeSessions: sessionMetrics.active,
|
|
338
|
+
toolInvocations: Object.fromEntries(
|
|
339
|
+
registryStats.topTools.map((t) => [t.name, t.calls])
|
|
340
|
+
),
|
|
341
|
+
errors: {},
|
|
342
|
+
lastReset: this.startTime || new Date(),
|
|
343
|
+
startupTime: this.startupDuration,
|
|
344
|
+
uptime: this.startTime ? Date.now() - this.startTime.getTime() : 0,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Get all sessions
|
|
350
|
+
*/
|
|
351
|
+
getSessions(): MCPSession[] {
|
|
352
|
+
return this.sessionManager.getActiveSessions();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Get session by ID
|
|
357
|
+
*/
|
|
358
|
+
getSession(sessionId: string): MCPSession | undefined {
|
|
359
|
+
return this.sessionManager.getSession(sessionId);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Terminate a session
|
|
364
|
+
*/
|
|
365
|
+
terminateSession(sessionId: string): boolean {
|
|
366
|
+
const result = this.sessionManager.closeSession(sessionId, 'Terminated by server');
|
|
367
|
+
if (this.currentSession?.id === sessionId) {
|
|
368
|
+
this.currentSession = undefined;
|
|
369
|
+
}
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Handle incoming request
|
|
375
|
+
*/
|
|
376
|
+
private async handleRequest(request: MCPRequest): Promise<MCPResponse> {
|
|
377
|
+
const startTime = performance.now();
|
|
378
|
+
this.requestStats.total++;
|
|
379
|
+
|
|
380
|
+
this.logger.debug('Handling request', {
|
|
381
|
+
id: request.id,
|
|
382
|
+
method: request.method,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
// Handle initialization
|
|
387
|
+
if (request.method === 'initialize') {
|
|
388
|
+
return await this.handleInitialize(request);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Get or create session
|
|
392
|
+
const session = this.getOrCreateSession();
|
|
393
|
+
|
|
394
|
+
// Check initialization
|
|
395
|
+
if (!session.isInitialized && request.method !== 'initialized') {
|
|
396
|
+
return this.createErrorResponse(
|
|
397
|
+
request.id,
|
|
398
|
+
ErrorCodes.SERVER_NOT_INITIALIZED,
|
|
399
|
+
'Server not initialized'
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Update session activity
|
|
404
|
+
this.sessionManager.updateActivity(session.id);
|
|
405
|
+
|
|
406
|
+
// Route request
|
|
407
|
+
const response = await this.routeRequest(request);
|
|
408
|
+
|
|
409
|
+
const duration = performance.now() - startTime;
|
|
410
|
+
this.requestStats.successful++;
|
|
411
|
+
this.requestStats.totalResponseTime += duration;
|
|
412
|
+
|
|
413
|
+
this.logger.debug('Request completed', {
|
|
414
|
+
id: request.id,
|
|
415
|
+
method: request.method,
|
|
416
|
+
duration: `${duration.toFixed(2)}ms`,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
return response;
|
|
420
|
+
|
|
421
|
+
} catch (error) {
|
|
422
|
+
const duration = performance.now() - startTime;
|
|
423
|
+
this.requestStats.failed++;
|
|
424
|
+
this.requestStats.totalResponseTime += duration;
|
|
425
|
+
|
|
426
|
+
this.logger.error('Request failed', {
|
|
427
|
+
id: request.id,
|
|
428
|
+
method: request.method,
|
|
429
|
+
error,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
return this.createErrorResponse(
|
|
433
|
+
request.id,
|
|
434
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
435
|
+
error instanceof Error ? error.message : 'Internal error'
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Handle notification
|
|
442
|
+
*/
|
|
443
|
+
private async handleNotification(notification: MCPNotification): Promise<void> {
|
|
444
|
+
this.logger.debug('Handling notification', { method: notification.method });
|
|
445
|
+
|
|
446
|
+
switch (notification.method) {
|
|
447
|
+
case 'initialized':
|
|
448
|
+
this.logger.info('Client initialized notification received');
|
|
449
|
+
break;
|
|
450
|
+
|
|
451
|
+
case 'notifications/cancelled':
|
|
452
|
+
this.logger.debug('Request cancelled', notification.params);
|
|
453
|
+
break;
|
|
454
|
+
|
|
455
|
+
default:
|
|
456
|
+
this.logger.debug('Unknown notification', { method: notification.method });
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Handle initialize request
|
|
462
|
+
*/
|
|
463
|
+
private async handleInitialize(request: MCPRequest): Promise<MCPResponse> {
|
|
464
|
+
const params = request.params as unknown as MCPInitializeParams | undefined;
|
|
465
|
+
|
|
466
|
+
if (!params) {
|
|
467
|
+
return this.createErrorResponse(
|
|
468
|
+
request.id,
|
|
469
|
+
ErrorCodes.INVALID_PARAMS,
|
|
470
|
+
'Invalid params'
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Create and initialize session
|
|
475
|
+
const session = this.sessionManager.createSession(this.config.transport);
|
|
476
|
+
this.sessionManager.initializeSession(session.id, params);
|
|
477
|
+
this.currentSession = session;
|
|
478
|
+
|
|
479
|
+
const result: MCPInitializeResult = {
|
|
480
|
+
protocolVersion: this.protocolVersion,
|
|
481
|
+
capabilities: this.capabilities,
|
|
482
|
+
serverInfo: this.serverInfo,
|
|
483
|
+
instructions: 'Claude-Flow MCP Server V3 ready for tool execution',
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
this.logger.info('Session initialized', {
|
|
487
|
+
sessionId: session.id,
|
|
488
|
+
clientInfo: params.clientInfo,
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
jsonrpc: '2.0',
|
|
493
|
+
id: request.id,
|
|
494
|
+
result,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Route request to appropriate handler
|
|
500
|
+
*/
|
|
501
|
+
private async routeRequest(request: MCPRequest): Promise<MCPResponse> {
|
|
502
|
+
switch (request.method) {
|
|
503
|
+
case 'tools/list':
|
|
504
|
+
return this.handleToolsList(request);
|
|
505
|
+
|
|
506
|
+
case 'tools/call':
|
|
507
|
+
return this.handleToolsCall(request);
|
|
508
|
+
|
|
509
|
+
case 'resources/list':
|
|
510
|
+
return this.handleResourcesList(request);
|
|
511
|
+
|
|
512
|
+
case 'prompts/list':
|
|
513
|
+
return this.handlePromptsList(request);
|
|
514
|
+
|
|
515
|
+
case 'ping':
|
|
516
|
+
return {
|
|
517
|
+
jsonrpc: '2.0',
|
|
518
|
+
id: request.id,
|
|
519
|
+
result: { pong: true, timestamp: Date.now() },
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
default:
|
|
523
|
+
// Try to execute as tool call (backwards compatibility)
|
|
524
|
+
if (this.toolRegistry.hasTool(request.method)) {
|
|
525
|
+
return this.handleToolExecution(request);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return this.createErrorResponse(
|
|
529
|
+
request.id,
|
|
530
|
+
ErrorCodes.METHOD_NOT_FOUND,
|
|
531
|
+
`Method not found: ${request.method}`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Handle tools/list request
|
|
538
|
+
*/
|
|
539
|
+
private handleToolsList(request: MCPRequest): MCPResponse {
|
|
540
|
+
const tools = this.toolRegistry.listTools().map((t) => ({
|
|
541
|
+
name: t.name,
|
|
542
|
+
description: t.description,
|
|
543
|
+
inputSchema: this.toolRegistry.getTool(t.name)?.inputSchema,
|
|
544
|
+
}));
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
jsonrpc: '2.0',
|
|
548
|
+
id: request.id,
|
|
549
|
+
result: { tools },
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Handle tools/call request
|
|
555
|
+
*/
|
|
556
|
+
private async handleToolsCall(request: MCPRequest): Promise<MCPResponse> {
|
|
557
|
+
const params = request.params as { name: string; arguments?: Record<string, unknown> };
|
|
558
|
+
|
|
559
|
+
if (!params?.name) {
|
|
560
|
+
return this.createErrorResponse(
|
|
561
|
+
request.id,
|
|
562
|
+
ErrorCodes.INVALID_PARAMS,
|
|
563
|
+
'Tool name is required'
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const context: ToolContext = {
|
|
568
|
+
sessionId: this.currentSession?.id || 'unknown',
|
|
569
|
+
requestId: request.id,
|
|
570
|
+
orchestrator: this.orchestrator,
|
|
571
|
+
swarmCoordinator: this.swarmCoordinator,
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const result = await this.toolRegistry.execute(
|
|
575
|
+
params.name,
|
|
576
|
+
params.arguments || {},
|
|
577
|
+
context
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
return {
|
|
581
|
+
jsonrpc: '2.0',
|
|
582
|
+
id: request.id,
|
|
583
|
+
result,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Handle direct tool execution (backwards compatibility)
|
|
589
|
+
*/
|
|
590
|
+
private async handleToolExecution(request: MCPRequest): Promise<MCPResponse> {
|
|
591
|
+
const context: ToolContext = {
|
|
592
|
+
sessionId: this.currentSession?.id || 'unknown',
|
|
593
|
+
requestId: request.id,
|
|
594
|
+
orchestrator: this.orchestrator,
|
|
595
|
+
swarmCoordinator: this.swarmCoordinator,
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const result = await this.toolRegistry.execute(
|
|
599
|
+
request.method,
|
|
600
|
+
(request.params as Record<string, unknown>) || {},
|
|
601
|
+
context
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
return {
|
|
605
|
+
jsonrpc: '2.0',
|
|
606
|
+
id: request.id,
|
|
607
|
+
result,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Handle resources/list request
|
|
613
|
+
*/
|
|
614
|
+
private handleResourcesList(request: MCPRequest): MCPResponse {
|
|
615
|
+
return {
|
|
616
|
+
jsonrpc: '2.0',
|
|
617
|
+
id: request.id,
|
|
618
|
+
result: { resources: [] },
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Handle prompts/list request
|
|
624
|
+
*/
|
|
625
|
+
private handlePromptsList(request: MCPRequest): MCPResponse {
|
|
626
|
+
return {
|
|
627
|
+
jsonrpc: '2.0',
|
|
628
|
+
id: request.id,
|
|
629
|
+
result: { prompts: [] },
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Get or create current session
|
|
635
|
+
*/
|
|
636
|
+
private getOrCreateSession(): MCPSession {
|
|
637
|
+
if (this.currentSession) {
|
|
638
|
+
return this.currentSession;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const session = this.sessionManager.createSession(this.config.transport);
|
|
642
|
+
this.currentSession = session;
|
|
643
|
+
return session;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Create error response
|
|
648
|
+
*/
|
|
649
|
+
private createErrorResponse(
|
|
650
|
+
id: string | number | null,
|
|
651
|
+
code: number,
|
|
652
|
+
message: string
|
|
653
|
+
): MCPResponse {
|
|
654
|
+
return {
|
|
655
|
+
jsonrpc: '2.0',
|
|
656
|
+
id,
|
|
657
|
+
error: { code, message },
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Register built-in tools
|
|
663
|
+
*/
|
|
664
|
+
private async registerBuiltInTools(): Promise<void> {
|
|
665
|
+
// System info tool
|
|
666
|
+
this.registerTool({
|
|
667
|
+
name: 'system/info',
|
|
668
|
+
description: 'Get system information',
|
|
669
|
+
inputSchema: { type: 'object', properties: {} },
|
|
670
|
+
handler: async () => ({
|
|
671
|
+
name: this.serverInfo.name,
|
|
672
|
+
version: this.serverInfo.version,
|
|
673
|
+
platform: platform(),
|
|
674
|
+
arch: arch(),
|
|
675
|
+
runtime: 'Node.js',
|
|
676
|
+
uptime: this.startTime ? Date.now() - this.startTime.getTime() : 0,
|
|
677
|
+
}),
|
|
678
|
+
category: 'system',
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// Health check tool
|
|
682
|
+
this.registerTool({
|
|
683
|
+
name: 'system/health',
|
|
684
|
+
description: 'Get system health status',
|
|
685
|
+
inputSchema: { type: 'object', properties: {} },
|
|
686
|
+
handler: async () => await this.getHealthStatus(),
|
|
687
|
+
category: 'system',
|
|
688
|
+
cacheable: true,
|
|
689
|
+
cacheTTL: 2000,
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
// Metrics tool
|
|
693
|
+
this.registerTool({
|
|
694
|
+
name: 'system/metrics',
|
|
695
|
+
description: 'Get server metrics',
|
|
696
|
+
inputSchema: { type: 'object', properties: {} },
|
|
697
|
+
handler: async () => this.getMetrics(),
|
|
698
|
+
category: 'system',
|
|
699
|
+
cacheable: true,
|
|
700
|
+
cacheTTL: 1000,
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// Tools list tool
|
|
704
|
+
this.registerTool({
|
|
705
|
+
name: 'tools/list-detailed',
|
|
706
|
+
description: 'List all registered tools with details',
|
|
707
|
+
inputSchema: {
|
|
708
|
+
type: 'object',
|
|
709
|
+
properties: {
|
|
710
|
+
category: { type: 'string', description: 'Filter by category' },
|
|
711
|
+
},
|
|
712
|
+
},
|
|
713
|
+
handler: async (input: unknown) => {
|
|
714
|
+
const params = input as { category?: string };
|
|
715
|
+
if (params.category) {
|
|
716
|
+
return this.toolRegistry.getByCategory(params.category);
|
|
717
|
+
}
|
|
718
|
+
return this.toolRegistry.listTools();
|
|
719
|
+
},
|
|
720
|
+
category: 'system',
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
this.logger.info('Built-in tools registered', {
|
|
724
|
+
count: 4,
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Setup event handlers
|
|
730
|
+
*/
|
|
731
|
+
private setupEventHandlers(): void {
|
|
732
|
+
// Tool events
|
|
733
|
+
this.toolRegistry.on('tool:registered', (name) => {
|
|
734
|
+
this.emit('tool:registered', name);
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
this.toolRegistry.on('tool:called', (data) => {
|
|
738
|
+
this.emit('tool:called', data);
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
this.toolRegistry.on('tool:completed', (data) => {
|
|
742
|
+
this.emit('tool:completed', data);
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
this.toolRegistry.on('tool:error', (data) => {
|
|
746
|
+
this.emit('tool:error', data);
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
// Session events
|
|
750
|
+
this.sessionManager.on('session:created', (session) => {
|
|
751
|
+
this.emit('session:created', session);
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
this.sessionManager.on('session:closed', (data) => {
|
|
755
|
+
this.emit('session:closed', data);
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
this.sessionManager.on('session:expired', (session) => {
|
|
759
|
+
this.emit('session:expired', session);
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Create an MCP server instance
|
|
766
|
+
*/
|
|
767
|
+
export function createMCPServer(
|
|
768
|
+
config: Partial<MCPServerConfig>,
|
|
769
|
+
logger: ILogger,
|
|
770
|
+
orchestrator?: unknown,
|
|
771
|
+
swarmCoordinator?: unknown
|
|
772
|
+
): MCPServer {
|
|
773
|
+
return new MCPServer(config, logger, orchestrator, swarmCoordinator);
|
|
774
|
+
}
|