@claude-flow/cli 3.0.0-alpha.1

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 (229) hide show
  1. package/.agentic-flow/intelligence.json +16 -0
  2. package/.claude-flow/metrics/agent-metrics.json +1 -0
  3. package/.claude-flow/metrics/performance.json +87 -0
  4. package/.claude-flow/metrics/task-metrics.json +10 -0
  5. package/README.md +1186 -0
  6. package/__tests__/README.md +140 -0
  7. package/__tests__/TEST_SUMMARY.md +144 -0
  8. package/__tests__/cli.test.ts +558 -0
  9. package/__tests__/commands.test.ts +726 -0
  10. package/__tests__/config-adapter.test.ts +362 -0
  11. package/__tests__/config-loading.test.ts +106 -0
  12. package/__tests__/coverage/.tmp/coverage-0.json +1 -0
  13. package/__tests__/coverage/.tmp/coverage-1.json +1 -0
  14. package/__tests__/coverage/.tmp/coverage-2.json +1 -0
  15. package/__tests__/coverage/.tmp/coverage-3.json +1 -0
  16. package/__tests__/coverage/.tmp/coverage-4.json +1 -0
  17. package/__tests__/coverage/.tmp/coverage-5.json +1 -0
  18. package/__tests__/mcp-client.test.ts +480 -0
  19. package/__tests__/p1-commands.test.ts +1064 -0
  20. package/bin/cli.js +14 -0
  21. package/dist/src/commands/agent.d.ts +8 -0
  22. package/dist/src/commands/agent.d.ts.map +1 -0
  23. package/dist/src/commands/agent.js +803 -0
  24. package/dist/src/commands/agent.js.map +1 -0
  25. package/dist/src/commands/config.d.ts +8 -0
  26. package/dist/src/commands/config.d.ts.map +1 -0
  27. package/dist/src/commands/config.js +406 -0
  28. package/dist/src/commands/config.js.map +1 -0
  29. package/dist/src/commands/hive-mind.d.ts +8 -0
  30. package/dist/src/commands/hive-mind.d.ts.map +1 -0
  31. package/dist/src/commands/hive-mind.js +627 -0
  32. package/dist/src/commands/hive-mind.js.map +1 -0
  33. package/dist/src/commands/hooks.d.ts +8 -0
  34. package/dist/src/commands/hooks.d.ts.map +1 -0
  35. package/dist/src/commands/hooks.js +2098 -0
  36. package/dist/src/commands/hooks.js.map +1 -0
  37. package/dist/src/commands/index.d.ts +51 -0
  38. package/dist/src/commands/index.d.ts.map +1 -0
  39. package/dist/src/commands/index.js +105 -0
  40. package/dist/src/commands/index.js.map +1 -0
  41. package/dist/src/commands/init.d.ts +8 -0
  42. package/dist/src/commands/init.d.ts.map +1 -0
  43. package/dist/src/commands/init.js +532 -0
  44. package/dist/src/commands/init.js.map +1 -0
  45. package/dist/src/commands/mcp.d.ts +11 -0
  46. package/dist/src/commands/mcp.d.ts.map +1 -0
  47. package/dist/src/commands/mcp.js +662 -0
  48. package/dist/src/commands/mcp.js.map +1 -0
  49. package/dist/src/commands/memory.d.ts +8 -0
  50. package/dist/src/commands/memory.d.ts.map +1 -0
  51. package/dist/src/commands/memory.js +911 -0
  52. package/dist/src/commands/memory.js.map +1 -0
  53. package/dist/src/commands/migrate.d.ts +8 -0
  54. package/dist/src/commands/migrate.d.ts.map +1 -0
  55. package/dist/src/commands/migrate.js +398 -0
  56. package/dist/src/commands/migrate.js.map +1 -0
  57. package/dist/src/commands/process.d.ts +10 -0
  58. package/dist/src/commands/process.d.ts.map +1 -0
  59. package/dist/src/commands/process.js +566 -0
  60. package/dist/src/commands/process.js.map +1 -0
  61. package/dist/src/commands/session.d.ts +8 -0
  62. package/dist/src/commands/session.d.ts.map +1 -0
  63. package/dist/src/commands/session.js +750 -0
  64. package/dist/src/commands/session.js.map +1 -0
  65. package/dist/src/commands/start.d.ts +8 -0
  66. package/dist/src/commands/start.d.ts.map +1 -0
  67. package/dist/src/commands/start.js +398 -0
  68. package/dist/src/commands/start.js.map +1 -0
  69. package/dist/src/commands/status.d.ts +8 -0
  70. package/dist/src/commands/status.d.ts.map +1 -0
  71. package/dist/src/commands/status.js +560 -0
  72. package/dist/src/commands/status.js.map +1 -0
  73. package/dist/src/commands/swarm.d.ts +8 -0
  74. package/dist/src/commands/swarm.d.ts.map +1 -0
  75. package/dist/src/commands/swarm.js +573 -0
  76. package/dist/src/commands/swarm.js.map +1 -0
  77. package/dist/src/commands/task.d.ts +8 -0
  78. package/dist/src/commands/task.d.ts.map +1 -0
  79. package/dist/src/commands/task.js +671 -0
  80. package/dist/src/commands/task.js.map +1 -0
  81. package/dist/src/commands/workflow.d.ts +8 -0
  82. package/dist/src/commands/workflow.d.ts.map +1 -0
  83. package/dist/src/commands/workflow.js +617 -0
  84. package/dist/src/commands/workflow.js.map +1 -0
  85. package/dist/src/config-adapter.d.ts +15 -0
  86. package/dist/src/config-adapter.d.ts.map +1 -0
  87. package/dist/src/config-adapter.js +185 -0
  88. package/dist/src/config-adapter.js.map +1 -0
  89. package/dist/src/index.d.ts +55 -0
  90. package/dist/src/index.d.ts.map +1 -0
  91. package/dist/src/index.js +312 -0
  92. package/dist/src/index.js.map +1 -0
  93. package/dist/src/infrastructure/in-memory-repositories.d.ts +68 -0
  94. package/dist/src/infrastructure/in-memory-repositories.d.ts.map +1 -0
  95. package/dist/src/infrastructure/in-memory-repositories.js +264 -0
  96. package/dist/src/infrastructure/in-memory-repositories.js.map +1 -0
  97. package/dist/src/init/claudemd-generator.d.ts +15 -0
  98. package/dist/src/init/claudemd-generator.d.ts.map +1 -0
  99. package/dist/src/init/claudemd-generator.js +626 -0
  100. package/dist/src/init/claudemd-generator.js.map +1 -0
  101. package/dist/src/init/executor.d.ts +11 -0
  102. package/dist/src/init/executor.d.ts.map +1 -0
  103. package/dist/src/init/executor.js +647 -0
  104. package/dist/src/init/executor.js.map +1 -0
  105. package/dist/src/init/helpers-generator.d.ts +42 -0
  106. package/dist/src/init/helpers-generator.d.ts.map +1 -0
  107. package/dist/src/init/helpers-generator.js +613 -0
  108. package/dist/src/init/helpers-generator.js.map +1 -0
  109. package/dist/src/init/index.d.ts +12 -0
  110. package/dist/src/init/index.d.ts.map +1 -0
  111. package/dist/src/init/index.js +15 -0
  112. package/dist/src/init/index.js.map +1 -0
  113. package/dist/src/init/mcp-generator.d.ts +18 -0
  114. package/dist/src/init/mcp-generator.d.ts.map +1 -0
  115. package/dist/src/init/mcp-generator.js +71 -0
  116. package/dist/src/init/mcp-generator.js.map +1 -0
  117. package/dist/src/init/settings-generator.d.ts +14 -0
  118. package/dist/src/init/settings-generator.d.ts.map +1 -0
  119. package/dist/src/init/settings-generator.js +257 -0
  120. package/dist/src/init/settings-generator.js.map +1 -0
  121. package/dist/src/init/statusline-generator.d.ts +14 -0
  122. package/dist/src/init/statusline-generator.d.ts.map +1 -0
  123. package/dist/src/init/statusline-generator.js +206 -0
  124. package/dist/src/init/statusline-generator.js.map +1 -0
  125. package/dist/src/init/types.d.ts +240 -0
  126. package/dist/src/init/types.d.ts.map +1 -0
  127. package/dist/src/init/types.js +210 -0
  128. package/dist/src/init/types.js.map +1 -0
  129. package/dist/src/mcp-client.d.ts +92 -0
  130. package/dist/src/mcp-client.d.ts.map +1 -0
  131. package/dist/src/mcp-client.js +189 -0
  132. package/dist/src/mcp-client.js.map +1 -0
  133. package/dist/src/mcp-server.d.ts +153 -0
  134. package/dist/src/mcp-server.d.ts.map +1 -0
  135. package/dist/src/mcp-server.js +448 -0
  136. package/dist/src/mcp-server.js.map +1 -0
  137. package/dist/src/mcp-tools/agent-tools.d.ts +8 -0
  138. package/dist/src/mcp-tools/agent-tools.d.ts.map +1 -0
  139. package/dist/src/mcp-tools/agent-tools.js +90 -0
  140. package/dist/src/mcp-tools/agent-tools.js.map +1 -0
  141. package/dist/src/mcp-tools/config-tools.d.ts +8 -0
  142. package/dist/src/mcp-tools/config-tools.d.ts.map +1 -0
  143. package/dist/src/mcp-tools/config-tools.js +86 -0
  144. package/dist/src/mcp-tools/config-tools.js.map +1 -0
  145. package/dist/src/mcp-tools/hooks-tools.d.ts +41 -0
  146. package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -0
  147. package/dist/src/mcp-tools/hooks-tools.js +1646 -0
  148. package/dist/src/mcp-tools/hooks-tools.js.map +1 -0
  149. package/dist/src/mcp-tools/index.d.ts +12 -0
  150. package/dist/src/mcp-tools/index.d.ts.map +1 -0
  151. package/dist/src/mcp-tools/index.js +11 -0
  152. package/dist/src/mcp-tools/index.js.map +1 -0
  153. package/dist/src/mcp-tools/memory-tools.d.ts +8 -0
  154. package/dist/src/mcp-tools/memory-tools.d.ts.map +1 -0
  155. package/dist/src/mcp-tools/memory-tools.js +87 -0
  156. package/dist/src/mcp-tools/memory-tools.js.map +1 -0
  157. package/dist/src/mcp-tools/swarm-tools.d.ts +8 -0
  158. package/dist/src/mcp-tools/swarm-tools.d.ts.map +1 -0
  159. package/dist/src/mcp-tools/swarm-tools.js +67 -0
  160. package/dist/src/mcp-tools/swarm-tools.js.map +1 -0
  161. package/dist/src/mcp-tools/types.d.ts +31 -0
  162. package/dist/src/mcp-tools/types.d.ts.map +1 -0
  163. package/dist/src/mcp-tools/types.js +7 -0
  164. package/dist/src/mcp-tools/types.js.map +1 -0
  165. package/dist/src/output.d.ts +117 -0
  166. package/dist/src/output.d.ts.map +1 -0
  167. package/dist/src/output.js +471 -0
  168. package/dist/src/output.js.map +1 -0
  169. package/dist/src/parser.d.ts +41 -0
  170. package/dist/src/parser.d.ts.map +1 -0
  171. package/dist/src/parser.js +353 -0
  172. package/dist/src/parser.js.map +1 -0
  173. package/dist/src/prompt.d.ts +44 -0
  174. package/dist/src/prompt.d.ts.map +1 -0
  175. package/dist/src/prompt.js +501 -0
  176. package/dist/src/prompt.js.map +1 -0
  177. package/dist/src/types.d.ts +198 -0
  178. package/dist/src/types.d.ts.map +1 -0
  179. package/dist/src/types.js +38 -0
  180. package/dist/src/types.js.map +1 -0
  181. package/dist/tsconfig.tsbuildinfo +1 -0
  182. package/docs/CONFIG_LOADING.md +236 -0
  183. package/docs/IMPLEMENTATION_COMPLETE.md +421 -0
  184. package/docs/MCP_CLIENT_GUIDE.md +620 -0
  185. package/docs/REFACTORING_SUMMARY.md +247 -0
  186. package/package.json +29 -0
  187. package/src/commands/agent.ts +941 -0
  188. package/src/commands/config.ts +452 -0
  189. package/src/commands/hive-mind.ts +762 -0
  190. package/src/commands/hooks.ts +2603 -0
  191. package/src/commands/index.ts +115 -0
  192. package/src/commands/init.ts +597 -0
  193. package/src/commands/mcp.ts +753 -0
  194. package/src/commands/memory.ts +1063 -0
  195. package/src/commands/migrate.ts +447 -0
  196. package/src/commands/process.ts +617 -0
  197. package/src/commands/session.ts +891 -0
  198. package/src/commands/start.ts +457 -0
  199. package/src/commands/status.ts +705 -0
  200. package/src/commands/swarm.ts +648 -0
  201. package/src/commands/task.ts +792 -0
  202. package/src/commands/workflow.ts +742 -0
  203. package/src/config-adapter.ts +210 -0
  204. package/src/index.ts +383 -0
  205. package/src/infrastructure/in-memory-repositories.ts +310 -0
  206. package/src/init/claudemd-generator.ts +631 -0
  207. package/src/init/executor.ts +756 -0
  208. package/src/init/helpers-generator.ts +628 -0
  209. package/src/init/index.ts +60 -0
  210. package/src/init/mcp-generator.ts +83 -0
  211. package/src/init/settings-generator.ts +274 -0
  212. package/src/init/statusline-generator.ts +211 -0
  213. package/src/init/types.ts +447 -0
  214. package/src/mcp-client.ts +227 -0
  215. package/src/mcp-server.ts +571 -0
  216. package/src/mcp-tools/agent-tools.ts +92 -0
  217. package/src/mcp-tools/config-tools.ts +88 -0
  218. package/src/mcp-tools/hooks-tools.ts +1819 -0
  219. package/src/mcp-tools/index.ts +12 -0
  220. package/src/mcp-tools/memory-tools.ts +89 -0
  221. package/src/mcp-tools/swarm-tools.ts +69 -0
  222. package/src/mcp-tools/types.ts +33 -0
  223. package/src/output.ts +593 -0
  224. package/src/parser.ts +417 -0
  225. package/src/prompt.ts +619 -0
  226. package/src/types.ts +287 -0
  227. package/tsconfig.json +16 -0
  228. package/tsconfig.tsbuildinfo +1 -0
  229. package/vitest.config.ts +13 -0
@@ -0,0 +1,571 @@
1
+ /**
2
+ * V3 CLI MCP Server Management
3
+ *
4
+ * Provides server lifecycle management for MCP integration:
5
+ * - Start/stop/status methods with process management
6
+ * - Health check endpoint integration
7
+ * - Graceful shutdown handling
8
+ * - PID file management for daemon detection
9
+ * - Event-based status monitoring
10
+ *
11
+ * Performance Targets:
12
+ * - Server startup: <400ms
13
+ * - Health check: <10ms
14
+ * - Graceful shutdown: <5s
15
+ *
16
+ * @module @claude-flow/cli/mcp-server
17
+ * @version 3.0.0
18
+ */
19
+
20
+ import { EventEmitter } from 'events';
21
+ import { spawn, ChildProcess } from 'child_process';
22
+ import { createServer, Server } from 'http';
23
+ import * as path from 'path';
24
+ import * as fs from 'fs';
25
+ import * as os from 'os';
26
+
27
+ /**
28
+ * MCP Server configuration
29
+ */
30
+ export interface MCPServerOptions {
31
+ transport?: 'stdio' | 'http' | 'websocket';
32
+ host?: string;
33
+ port?: number;
34
+ pidFile?: string;
35
+ logFile?: string;
36
+ tools?: string[] | 'all';
37
+ daemonize?: boolean;
38
+ timeout?: number;
39
+ }
40
+
41
+ /**
42
+ * MCP Server status
43
+ */
44
+ export interface MCPServerStatus {
45
+ running: boolean;
46
+ pid?: number;
47
+ transport?: string;
48
+ host?: string;
49
+ port?: number;
50
+ uptime?: number;
51
+ tools?: number;
52
+ startedAt?: string;
53
+ health?: {
54
+ healthy: boolean;
55
+ error?: string;
56
+ metrics?: Record<string, number>;
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Default configuration
62
+ */
63
+ const DEFAULT_OPTIONS: Required<MCPServerOptions> = {
64
+ transport: 'stdio',
65
+ host: 'localhost',
66
+ port: 3000,
67
+ pidFile: path.join(os.tmpdir(), 'claude-flow-mcp.pid'),
68
+ logFile: path.join(os.tmpdir(), 'claude-flow-mcp.log'),
69
+ tools: 'all',
70
+ daemonize: false,
71
+ timeout: 30000,
72
+ };
73
+
74
+ /**
75
+ * MCP Server Manager
76
+ *
77
+ * Manages the lifecycle of the MCP server process
78
+ */
79
+ export class MCPServerManager extends EventEmitter {
80
+ private options: Required<MCPServerOptions>;
81
+ private process?: ChildProcess;
82
+ private server?: Server;
83
+ private startTime?: Date;
84
+ private healthCheckInterval?: NodeJS.Timeout;
85
+
86
+ constructor(options: MCPServerOptions = {}) {
87
+ super();
88
+ this.options = { ...DEFAULT_OPTIONS, ...options };
89
+ }
90
+
91
+ /**
92
+ * Start the MCP server
93
+ */
94
+ async start(): Promise<MCPServerStatus> {
95
+ // Check if already running
96
+ const status = await this.getStatus();
97
+ if (status.running) {
98
+ throw new Error(`MCP Server already running (PID: ${status.pid})`);
99
+ }
100
+
101
+ const startTime = performance.now();
102
+ this.startTime = new Date();
103
+
104
+ this.emit('starting', { options: this.options });
105
+
106
+ try {
107
+ if (this.options.transport === 'stdio') {
108
+ // For stdio transport, spawn the server process
109
+ await this.startStdioServer();
110
+ } else {
111
+ // For HTTP/WebSocket, start in-process server
112
+ await this.startHttpServer();
113
+ }
114
+
115
+ const duration = performance.now() - startTime;
116
+
117
+ // Write PID file
118
+ await this.writePidFile();
119
+
120
+ // Start health check monitoring
121
+ this.startHealthMonitoring();
122
+
123
+ const finalStatus = await this.getStatus();
124
+
125
+ this.emit('started', {
126
+ ...finalStatus,
127
+ startupTime: duration,
128
+ });
129
+
130
+ return finalStatus;
131
+ } catch (error) {
132
+ this.emit('error', error);
133
+ throw error;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Stop the MCP server
139
+ */
140
+ async stop(force = false): Promise<void> {
141
+ const status = await this.getStatus();
142
+
143
+ if (!status.running) {
144
+ return;
145
+ }
146
+
147
+ this.emit('stopping', { force });
148
+
149
+ try {
150
+ // Stop health monitoring
151
+ if (this.healthCheckInterval) {
152
+ clearInterval(this.healthCheckInterval);
153
+ this.healthCheckInterval = undefined;
154
+ }
155
+
156
+ if (this.process) {
157
+ // Graceful shutdown
158
+ if (!force) {
159
+ this.process.kill('SIGTERM');
160
+ await this.waitForExit(5000);
161
+ }
162
+
163
+ // Force kill if still running
164
+ if (this.process && !this.process.killed) {
165
+ this.process.kill('SIGKILL');
166
+ }
167
+
168
+ this.process = undefined;
169
+ }
170
+
171
+ if (this.server) {
172
+ await new Promise<void>((resolve) => {
173
+ this.server!.close(() => resolve());
174
+ });
175
+ this.server = undefined;
176
+ }
177
+
178
+ // Remove PID file
179
+ await this.removePidFile();
180
+
181
+ this.startTime = undefined;
182
+ this.emit('stopped');
183
+ } catch (error) {
184
+ this.emit('error', error);
185
+ throw error;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Get server status
191
+ */
192
+ async getStatus(): Promise<MCPServerStatus> {
193
+ // Check PID file
194
+ const pid = await this.readPidFile();
195
+
196
+ if (!pid) {
197
+ return { running: false };
198
+ }
199
+
200
+ // Check if process is running
201
+ const isRunning = this.isProcessRunning(pid);
202
+
203
+ if (!isRunning) {
204
+ // Clean up stale PID file
205
+ await this.removePidFile();
206
+ return { running: false };
207
+ }
208
+
209
+ // Build status
210
+ const status: MCPServerStatus = {
211
+ running: true,
212
+ pid,
213
+ transport: this.options.transport,
214
+ host: this.options.host,
215
+ port: this.options.port,
216
+ startedAt: this.startTime?.toISOString(),
217
+ uptime: this.startTime
218
+ ? Math.floor((Date.now() - this.startTime.getTime()) / 1000)
219
+ : undefined,
220
+ };
221
+
222
+ // Get health status for HTTP transport
223
+ if (this.options.transport !== 'stdio') {
224
+ status.health = await this.checkHealth();
225
+ }
226
+
227
+ return status;
228
+ }
229
+
230
+ /**
231
+ * Check server health
232
+ */
233
+ async checkHealth(): Promise<{
234
+ healthy: boolean;
235
+ error?: string;
236
+ metrics?: Record<string, number>;
237
+ }> {
238
+ if (this.options.transport === 'stdio') {
239
+ // For stdio, just check if process is running
240
+ const pid = await this.readPidFile();
241
+ return {
242
+ healthy: pid !== null && this.isProcessRunning(pid),
243
+ };
244
+ }
245
+
246
+ // For HTTP/WebSocket, make health check request
247
+ try {
248
+ const response = await this.httpRequest(
249
+ `http://${this.options.host}:${this.options.port}/health`,
250
+ 'GET',
251
+ this.options.timeout
252
+ );
253
+
254
+ return {
255
+ healthy: response.status === 'ok',
256
+ metrics: {
257
+ connections: response.connections || 0,
258
+ },
259
+ };
260
+ } catch (error) {
261
+ return {
262
+ healthy: false,
263
+ error: error instanceof Error ? error.message : 'Unknown error',
264
+ };
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Restart the server
270
+ */
271
+ async restart(): Promise<MCPServerStatus> {
272
+ await this.stop();
273
+ return await this.start();
274
+ }
275
+
276
+ /**
277
+ * Start stdio server process
278
+ */
279
+ private async startStdioServer(): Promise<void> {
280
+ // Resolve server script path relative to this file
281
+ const serverScript = path.resolve(
282
+ __dirname,
283
+ '../../../mcp/server-entry.ts'
284
+ );
285
+
286
+ // Check if tsx is available
287
+ const command = 'npx';
288
+ const args = [
289
+ 'tsx',
290
+ serverScript,
291
+ '--transport', this.options.transport,
292
+ '--host', this.options.host,
293
+ '--port', String(this.options.port),
294
+ ];
295
+
296
+ if (this.options.tools !== 'all') {
297
+ args.push('--tools', this.options.tools.join(','));
298
+ }
299
+
300
+ this.process = spawn(command, args, {
301
+ stdio: this.options.daemonize ? 'ignore' : ['pipe', 'pipe', 'pipe'],
302
+ detached: this.options.daemonize,
303
+ env: {
304
+ ...process.env,
305
+ NODE_ENV: process.env.NODE_ENV || 'production',
306
+ MCP_SERVER_MODE: 'true',
307
+ },
308
+ });
309
+
310
+ if (this.options.daemonize) {
311
+ this.process.unref();
312
+ }
313
+
314
+ // Handle process events
315
+ this.process.on('error', (error) => {
316
+ this.emit('error', error);
317
+ });
318
+
319
+ this.process.on('exit', (code, signal) => {
320
+ this.emit('exit', { code, signal });
321
+ this.process = undefined;
322
+ });
323
+
324
+ // Wait for server to be ready
325
+ await this.waitForReady();
326
+ }
327
+
328
+ /**
329
+ * Start HTTP server in-process
330
+ */
331
+ private async startHttpServer(): Promise<void> {
332
+ // Dynamically import the MCP server
333
+ // Note: Path is relative to the compiled output location
334
+ const mcpServerPath = path.resolve(__dirname, '../../../mcp/server.js');
335
+ const { MCPServer, createMCPServer } = await import(mcpServerPath);
336
+
337
+ const logger = {
338
+ debug: (msg: string, data?: unknown) => this.emit('log', { level: 'debug', msg, data }),
339
+ info: (msg: string, data?: unknown) => this.emit('log', { level: 'info', msg, data }),
340
+ warn: (msg: string, data?: unknown) => this.emit('log', { level: 'warn', msg, data }),
341
+ error: (msg: string, data?: unknown) => this.emit('log', { level: 'error', msg, data }),
342
+ };
343
+
344
+ const mcpServer = createMCPServer(
345
+ {
346
+ name: 'Claude-Flow MCP Server V3',
347
+ version: '3.0.0',
348
+ transport: this.options.transport as 'http' | 'websocket',
349
+ host: this.options.host,
350
+ port: this.options.port,
351
+ enableMetrics: true,
352
+ enableCaching: true,
353
+ },
354
+ logger
355
+ );
356
+
357
+ await mcpServer.start();
358
+
359
+ // Store reference for stopping
360
+ (this as any)._mcpServer = mcpServer;
361
+ }
362
+
363
+ /**
364
+ * Wait for server to be ready
365
+ */
366
+ private async waitForReady(timeout = 10000): Promise<void> {
367
+ const startTime = Date.now();
368
+
369
+ while (Date.now() - startTime < timeout) {
370
+ const health = await this.checkHealth();
371
+ if (health.healthy) {
372
+ return;
373
+ }
374
+ await this.sleep(100);
375
+ }
376
+
377
+ // For stdio, just check if process is running
378
+ if (this.options.transport === 'stdio' && this.process && !this.process.killed) {
379
+ return;
380
+ }
381
+
382
+ throw new Error('Server failed to start within timeout');
383
+ }
384
+
385
+ /**
386
+ * Wait for process to exit
387
+ */
388
+ private async waitForExit(timeout: number): Promise<void> {
389
+ if (!this.process) return;
390
+
391
+ return new Promise((resolve) => {
392
+ const timer = setTimeout(() => {
393
+ resolve();
394
+ }, timeout);
395
+
396
+ this.process!.once('exit', () => {
397
+ clearTimeout(timer);
398
+ resolve();
399
+ });
400
+ });
401
+ }
402
+
403
+ /**
404
+ * Start health monitoring
405
+ */
406
+ private startHealthMonitoring(): void {
407
+ this.healthCheckInterval = setInterval(async () => {
408
+ try {
409
+ const health = await this.checkHealth();
410
+ this.emit('health', health);
411
+
412
+ if (!health.healthy) {
413
+ this.emit('unhealthy', health);
414
+ }
415
+ } catch (error) {
416
+ this.emit('health-error', error);
417
+ }
418
+ }, 30000);
419
+ }
420
+
421
+ /**
422
+ * Write PID file
423
+ */
424
+ private async writePidFile(): Promise<void> {
425
+ const pid = this.process?.pid || process.pid;
426
+ await fs.promises.writeFile(this.options.pidFile, String(pid), 'utf8');
427
+ }
428
+
429
+ /**
430
+ * Read PID file
431
+ */
432
+ private async readPidFile(): Promise<number | null> {
433
+ try {
434
+ const content = await fs.promises.readFile(this.options.pidFile, 'utf8');
435
+ const pid = parseInt(content.trim(), 10);
436
+ return isNaN(pid) ? null : pid;
437
+ } catch {
438
+ return null;
439
+ }
440
+ }
441
+
442
+ /**
443
+ * Remove PID file
444
+ */
445
+ private async removePidFile(): Promise<void> {
446
+ try {
447
+ await fs.promises.unlink(this.options.pidFile);
448
+ } catch {
449
+ // Ignore errors
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Check if process is running
455
+ */
456
+ private isProcessRunning(pid: number): boolean {
457
+ try {
458
+ process.kill(pid, 0);
459
+ return true;
460
+ } catch {
461
+ return false;
462
+ }
463
+ }
464
+
465
+ /**
466
+ * Make HTTP request
467
+ */
468
+ private async httpRequest(
469
+ url: string,
470
+ method: string,
471
+ timeout: number
472
+ ): Promise<any> {
473
+ return new Promise((resolve, reject) => {
474
+ const urlObj = new URL(url);
475
+ const http = require('http');
476
+
477
+ const req = http.request(
478
+ {
479
+ hostname: urlObj.hostname,
480
+ port: urlObj.port,
481
+ path: urlObj.pathname,
482
+ method,
483
+ timeout,
484
+ },
485
+ (res: any) => {
486
+ let data = '';
487
+ res.on('data', (chunk: string) => {
488
+ data += chunk;
489
+ });
490
+ res.on('end', () => {
491
+ try {
492
+ resolve(JSON.parse(data));
493
+ } catch {
494
+ resolve({ status: res.statusCode === 200 ? 'ok' : 'error' });
495
+ }
496
+ });
497
+ }
498
+ );
499
+
500
+ req.on('error', reject);
501
+ req.on('timeout', () => {
502
+ req.destroy();
503
+ reject(new Error('Request timeout'));
504
+ });
505
+
506
+ req.end();
507
+ });
508
+ }
509
+
510
+ /**
511
+ * Sleep utility
512
+ */
513
+ private sleep(ms: number): Promise<void> {
514
+ return new Promise((resolve) => setTimeout(resolve, ms));
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Create MCP server manager
520
+ */
521
+ export function createMCPServerManager(
522
+ options?: MCPServerOptions
523
+ ): MCPServerManager {
524
+ return new MCPServerManager(options);
525
+ }
526
+
527
+ /**
528
+ * Singleton server manager instance
529
+ */
530
+ let serverManager: MCPServerManager | null = null;
531
+
532
+ /**
533
+ * Get or create server manager singleton
534
+ */
535
+ export function getServerManager(
536
+ options?: MCPServerOptions
537
+ ): MCPServerManager {
538
+ if (!serverManager) {
539
+ serverManager = new MCPServerManager(options);
540
+ }
541
+ return serverManager;
542
+ }
543
+
544
+ /**
545
+ * Quick start MCP server
546
+ */
547
+ export async function startMCPServer(
548
+ options?: MCPServerOptions
549
+ ): Promise<MCPServerStatus> {
550
+ const manager = getServerManager(options);
551
+ return await manager.start();
552
+ }
553
+
554
+ /**
555
+ * Quick stop MCP server
556
+ */
557
+ export async function stopMCPServer(force = false): Promise<void> {
558
+ if (serverManager) {
559
+ await serverManager.stop(force);
560
+ }
561
+ }
562
+
563
+ /**
564
+ * Get MCP server status
565
+ */
566
+ export async function getMCPServerStatus(): Promise<MCPServerStatus> {
567
+ const manager = getServerManager();
568
+ return await manager.getStatus();
569
+ }
570
+
571
+ export default MCPServerManager;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Agent MCP Tools for CLI
3
+ *
4
+ * Tool definitions for agent lifecycle management.
5
+ */
6
+
7
+ import type { MCPTool } from './types.js';
8
+
9
+ export const agentTools: MCPTool[] = [
10
+ {
11
+ name: 'agent/spawn',
12
+ description: 'Spawn a new agent',
13
+ category: 'agent',
14
+ inputSchema: {
15
+ type: 'object',
16
+ properties: {
17
+ agentType: { type: 'string', description: 'Type of agent to spawn' },
18
+ agentId: { type: 'string', description: 'Optional custom agent ID' },
19
+ config: { type: 'object', description: 'Agent configuration' },
20
+ },
21
+ required: ['agentType'],
22
+ },
23
+ handler: async (input) => {
24
+ // Stub implementation - actual coordinator integration at runtime
25
+ return {
26
+ success: true,
27
+ agentId: (input.agentId as string) || `agent-${Date.now()}`,
28
+ agentType: input.agentType,
29
+ status: 'spawned',
30
+ };
31
+ },
32
+ },
33
+ {
34
+ name: 'agent/terminate',
35
+ description: 'Terminate an agent',
36
+ category: 'agent',
37
+ inputSchema: {
38
+ type: 'object',
39
+ properties: {
40
+ agentId: { type: 'string', description: 'ID of agent to terminate' },
41
+ force: { type: 'boolean', description: 'Force immediate termination' },
42
+ },
43
+ required: ['agentId'],
44
+ },
45
+ handler: async (input) => {
46
+ return {
47
+ success: true,
48
+ agentId: input.agentId,
49
+ terminated: true,
50
+ };
51
+ },
52
+ },
53
+ {
54
+ name: 'agent/status',
55
+ description: 'Get agent status',
56
+ category: 'agent',
57
+ inputSchema: {
58
+ type: 'object',
59
+ properties: {
60
+ agentId: { type: 'string', description: 'ID of agent' },
61
+ },
62
+ required: ['agentId'],
63
+ },
64
+ handler: async (input) => {
65
+ return {
66
+ agentId: input.agentId,
67
+ status: 'idle',
68
+ health: 1.0,
69
+ taskCount: 0,
70
+ };
71
+ },
72
+ },
73
+ {
74
+ name: 'agent/list',
75
+ description: 'List all agents',
76
+ category: 'agent',
77
+ inputSchema: {
78
+ type: 'object',
79
+ properties: {
80
+ status: { type: 'string', description: 'Filter by status' },
81
+ domain: { type: 'string', description: 'Filter by domain' },
82
+ },
83
+ },
84
+ handler: async (input) => {
85
+ return {
86
+ agents: [],
87
+ total: 0,
88
+ filters: input,
89
+ };
90
+ },
91
+ },
92
+ ];