mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-11-10 06:23:28 +09:00
checkpoint: File edit:
🚀 Generated with [Claude Code](https://claude.com/claude-code) 📊 V3 Development Progress Checkpoint Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
This commit is contained in:
1 parent
ff6c1a3356
commit
d3b247f2bb
1 file changed
+389
-166
@@ -1,11 +1,24 @@
|
||||
/**
|
||||
* V3 CLI MCP Command
|
||||
* MCP server control and management
|
||||
* MCP server control and management with real server integration
|
||||
*
|
||||
* @module @claude-flow/cli/commands/mcp
|
||||
* @version 3.0.0
|
||||
*/
|
||||
|
||||
import type { Command, CommandContext, CommandResult } from '../types.js';
|
||||
import { output } from '../output.js';
|
||||
import { select, confirm } from '../prompt.js';
|
||||
import {
|
||||
MCPServerManager,
|
||||
createMCPServerManager,
|
||||
getServerManager,
|
||||
startMCPServer,
|
||||
stopMCPServer,
|
||||
getMCPServerStatus,
|
||||
type MCPServerOptions,
|
||||
type MCPServerStatus,
|
||||
} from '../mcp-server.js';
|
||||
|
||||
// MCP tools categories
|
||||
const TOOL_CATEGORIES = [
|
||||
@@ -16,6 +29,23 @@ const TOOL_CATEGORIES = [
|
||||
{ value: 'system', label: 'System', hint: 'System and benchmark tools' }
|
||||
];
|
||||
|
||||
/**
|
||||
* Format uptime for display
|
||||
*/
|
||||
function formatUptime(seconds: number): string {
|
||||
if (seconds < 60) {
|
||||
return `${seconds}s`;
|
||||
}
|
||||
if (seconds < 3600) {
|
||||
const mins = Math.floor(seconds / 60);
|
||||
const secs = seconds % 60;
|
||||
return `${mins}m ${secs}s`;
|
||||
}
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const mins = Math.floor((seconds % 3600) / 60);
|
||||
return `${hours}h ${mins}m`;
|
||||
}
|
||||
|
||||
// Start MCP server
|
||||
const startCommand: Command = {
|
||||
name: 'start',
|
||||
@@ -48,64 +78,105 @@ const startCommand: Command = {
|
||||
description: 'Tools to enable (comma-separated or "all")',
|
||||
type: 'string',
|
||||
default: 'all'
|
||||
},
|
||||
{
|
||||
name: 'daemon',
|
||||
short: 'd',
|
||||
description: 'Run as background daemon',
|
||||
type: 'boolean',
|
||||
default: false
|
||||
}
|
||||
],
|
||||
examples: [
|
||||
{ command: 'claude-flow mcp start', description: 'Start with defaults (stdio)' },
|
||||
{ command: 'claude-flow mcp start -p 8080 -t http', description: 'Start HTTP server' }
|
||||
{ command: 'claude-flow mcp start -p 8080 -t http', description: 'Start HTTP server' },
|
||||
{ command: 'claude-flow mcp start -d', description: 'Start as daemon' }
|
||||
],
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
const port = ctx.flags.port as number;
|
||||
const host = ctx.flags.host as string;
|
||||
const transport = ctx.flags.transport as string;
|
||||
const transport = ctx.flags.transport as 'stdio' | 'http' | 'websocket';
|
||||
const tools = ctx.flags.tools as string;
|
||||
const daemon = ctx.flags.daemon as boolean;
|
||||
|
||||
output.writeln();
|
||||
output.printInfo('Starting MCP Server...');
|
||||
output.writeln();
|
||||
|
||||
const serverConfig = {
|
||||
id: `mcp-${Date.now().toString(36)}`,
|
||||
// Check if already running
|
||||
const existingStatus = await getMCPServerStatus();
|
||||
if (existingStatus.running) {
|
||||
output.printWarning(`MCP Server already running (PID: ${existingStatus.pid})`);
|
||||
output.writeln(output.dim('Use "claude-flow mcp stop" to stop the server first'));
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
|
||||
const options: MCPServerOptions = {
|
||||
transport,
|
||||
host,
|
||||
port,
|
||||
status: 'starting',
|
||||
tools: tools === 'all' ? 27 : tools.split(',').length,
|
||||
startedAt: new Date().toISOString()
|
||||
tools: tools === 'all' ? 'all' : tools.split(','),
|
||||
daemonize: daemon,
|
||||
};
|
||||
|
||||
// Simulate startup
|
||||
output.writeln(output.dim(' Loading tool registry...'));
|
||||
output.writeln(output.dim(' Initializing transport layer...'));
|
||||
output.writeln(output.dim(' Registering 27 MCP tools...'));
|
||||
output.writeln(output.dim(' Setting up handlers...'));
|
||||
try {
|
||||
output.writeln(output.dim(' Initializing server...'));
|
||||
|
||||
output.writeln();
|
||||
output.printTable({
|
||||
columns: [
|
||||
{ key: 'property', header: 'Property', width: 15 },
|
||||
{ key: 'value', header: 'Value', width: 30 }
|
||||
],
|
||||
data: [
|
||||
{ property: 'Server ID', value: serverConfig.id },
|
||||
{ property: 'Transport', value: transport },
|
||||
{ property: 'Host', value: host },
|
||||
{ property: 'Port', value: port },
|
||||
{ property: 'Tools', value: `${serverConfig.tools} enabled` },
|
||||
{ property: 'Status', value: output.success('Running') }
|
||||
]
|
||||
});
|
||||
const manager = getServerManager(options);
|
||||
|
||||
output.writeln();
|
||||
output.printSuccess('MCP Server started');
|
||||
// Setup event handlers for progress display
|
||||
manager.on('starting', () => {
|
||||
output.writeln(output.dim(' Loading tool registry...'));
|
||||
});
|
||||
|
||||
if (transport === 'http') {
|
||||
output.writeln(output.dim(` Endpoint: http://${host}:${port}`));
|
||||
} else if (transport === 'websocket') {
|
||||
output.writeln(output.dim(` Endpoint: ws://${host}:${port}`));
|
||||
manager.on('started', (data: any) => {
|
||||
output.writeln(output.dim(` Server started in ${data.startupTime?.toFixed(2) || 0}ms`));
|
||||
});
|
||||
|
||||
manager.on('log', (log: { level: string; msg: string; data?: unknown }) => {
|
||||
if (ctx.flags.verbose) {
|
||||
output.writeln(output.dim(` [${log.level}] ${log.msg}`));
|
||||
}
|
||||
});
|
||||
|
||||
// Start the server
|
||||
const status = await manager.start();
|
||||
|
||||
output.writeln();
|
||||
output.printTable({
|
||||
columns: [
|
||||
{ key: 'property', header: 'Property', width: 15 },
|
||||
{ key: 'value', header: 'Value', width: 30 }
|
||||
],
|
||||
data: [
|
||||
{ property: 'Server PID', value: status.pid || process.pid },
|
||||
{ property: 'Transport', value: transport },
|
||||
{ property: 'Host', value: host },
|
||||
{ property: 'Port', value: port },
|
||||
{ property: 'Tools', value: tools === 'all' ? '27 enabled' : `${tools.split(',').length} enabled` },
|
||||
{ property: 'Status', value: output.success('Running') }
|
||||
]
|
||||
});
|
||||
|
||||
output.writeln();
|
||||
output.printSuccess('MCP Server started');
|
||||
|
||||
if (transport === 'http') {
|
||||
output.writeln(output.dim(` Health: http://${host}:${port}/health`));
|
||||
output.writeln(output.dim(` RPC: http://${host}:${port}/rpc`));
|
||||
} else if (transport === 'websocket') {
|
||||
output.writeln(output.dim(` WebSocket: ws://${host}:${port}/ws`));
|
||||
}
|
||||
|
||||
if (daemon) {
|
||||
output.writeln(output.dim(' Running in background mode'));
|
||||
}
|
||||
|
||||
return { success: true, data: status };
|
||||
} catch (error) {
|
||||
output.printError(`Failed to start MCP server: ${(error as Error).message}`);
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
|
||||
return { success: true, data: serverConfig };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -125,9 +196,16 @@ const stopCommand: Command = {
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
const force = ctx.flags.force as boolean;
|
||||
|
||||
// Check if server is running
|
||||
const status = await getMCPServerStatus();
|
||||
if (!status.running) {
|
||||
output.printInfo('MCP Server is not running');
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
if (!force && ctx.interactive) {
|
||||
const confirmed = await confirm({
|
||||
message: 'Stop MCP server?',
|
||||
message: `Stop MCP server (PID: ${status.pid})?`,
|
||||
default: false
|
||||
});
|
||||
|
||||
@@ -139,15 +217,24 @@ const stopCommand: Command = {
|
||||
|
||||
output.printInfo('Stopping MCP Server...');
|
||||
|
||||
if (!force) {
|
||||
output.writeln(output.dim(' Completing pending requests...'));
|
||||
output.writeln(output.dim(' Closing connections...'));
|
||||
try {
|
||||
const manager = getServerManager();
|
||||
|
||||
if (!force) {
|
||||
output.writeln(output.dim(' Completing pending requests...'));
|
||||
output.writeln(output.dim(' Closing connections...'));
|
||||
}
|
||||
|
||||
await manager.stop(force);
|
||||
|
||||
output.writeln(output.dim(' Releasing resources...'));
|
||||
output.printSuccess('MCP Server stopped');
|
||||
|
||||
return { success: true, data: { stopped: true, force } };
|
||||
} catch (error) {
|
||||
output.printError(`Failed to stop MCP server: ${(error as Error).message}`);
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
|
||||
output.printSuccess('MCP Server stopped');
|
||||
|
||||
return { success: true, data: { stopped: true, force } };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -156,62 +243,81 @@ const statusCommand: Command = {
|
||||
name: 'status',
|
||||
description: 'Show MCP server status',
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
const status = {
|
||||
running: true,
|
||||
transport: 'stdio',
|
||||
uptime: '2h 45m',
|
||||
tools: {
|
||||
total: 27,
|
||||
enabled: 27,
|
||||
used: 15
|
||||
},
|
||||
requests: {
|
||||
total: 1234,
|
||||
successful: 1220,
|
||||
failed: 14,
|
||||
avgLatency: '8.5ms'
|
||||
},
|
||||
connections: {
|
||||
active: 3,
|
||||
total: 45
|
||||
},
|
||||
memory: {
|
||||
used: '45 MB',
|
||||
peak: '78 MB'
|
||||
try {
|
||||
const status = await getMCPServerStatus();
|
||||
|
||||
if (ctx.flags.format === 'json') {
|
||||
output.printJson(status);
|
||||
return { success: true, data: status };
|
||||
}
|
||||
};
|
||||
|
||||
if (ctx.flags.format === 'json') {
|
||||
output.printJson(status);
|
||||
return { success: true, data: status };
|
||||
}
|
||||
output.writeln();
|
||||
output.writeln(output.bold('MCP Server Status'));
|
||||
output.writeln();
|
||||
|
||||
output.writeln();
|
||||
output.writeln(output.bold('MCP Server Status'));
|
||||
output.writeln();
|
||||
if (!status.running) {
|
||||
output.printTable({
|
||||
columns: [
|
||||
{ key: 'metric', header: 'Metric', width: 20 },
|
||||
{ key: 'value', header: 'Value', width: 20, align: 'right' }
|
||||
],
|
||||
data: [
|
||||
{ metric: 'Status', value: output.error('Stopped') }
|
||||
]
|
||||
});
|
||||
|
||||
output.printTable({
|
||||
columns: [
|
||||
{ key: 'metric', header: 'Metric', width: 20 },
|
||||
{ key: 'value', header: 'Value', width: 20, align: 'right' }
|
||||
],
|
||||
data: [
|
||||
{ metric: 'Status', value: status.running ? output.success('Running') : output.error('Stopped') },
|
||||
output.writeln();
|
||||
output.writeln(output.dim('Run "claude-flow mcp start" to start the server'));
|
||||
return { success: true, data: status };
|
||||
}
|
||||
|
||||
const displayData = [
|
||||
{ metric: 'Status', value: output.success('Running') },
|
||||
{ metric: 'PID', value: status.pid },
|
||||
{ metric: 'Transport', value: status.transport },
|
||||
{ metric: 'Uptime', value: status.uptime },
|
||||
{ metric: 'Active Connections', value: status.connections.active },
|
||||
{ metric: 'Total Requests', value: status.requests.total.toLocaleString() },
|
||||
{ metric: 'Success Rate', value: `${((status.requests.successful / status.requests.total) * 100).toFixed(1)}%` },
|
||||
{ metric: 'Avg Latency', value: status.requests.avgLatency },
|
||||
{ metric: 'Memory Used', value: status.memory.used }
|
||||
]
|
||||
});
|
||||
{ metric: 'Host', value: status.host },
|
||||
{ metric: 'Port', value: status.port },
|
||||
];
|
||||
|
||||
output.writeln();
|
||||
output.writeln(output.bold('Tools'));
|
||||
output.writeln(` Total: ${status.tools.total} | Enabled: ${status.tools.enabled} | Used: ${status.tools.used}`);
|
||||
if (status.uptime !== undefined) {
|
||||
displayData.push({ metric: 'Uptime', value: formatUptime(status.uptime) });
|
||||
}
|
||||
|
||||
return { success: true, data: status };
|
||||
if (status.startedAt) {
|
||||
displayData.push({ metric: 'Started At', value: status.startedAt });
|
||||
}
|
||||
|
||||
if (status.health) {
|
||||
displayData.push({
|
||||
metric: 'Health',
|
||||
value: status.health.healthy
|
||||
? output.success('Healthy')
|
||||
: output.error(status.health.error || 'Unhealthy')
|
||||
});
|
||||
|
||||
if (status.health.metrics) {
|
||||
for (const [key, value] of Object.entries(status.health.metrics)) {
|
||||
displayData.push({
|
||||
metric: ` ${key}`,
|
||||
value: String(value)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output.printTable({
|
||||
columns: [
|
||||
{ key: 'metric', header: 'Metric', width: 20 },
|
||||
{ key: 'value', header: 'Value', width: 25, align: 'right' }
|
||||
],
|
||||
data: displayData
|
||||
});
|
||||
|
||||
return { success: true, data: status };
|
||||
} catch (error) {
|
||||
output.printError(`Failed to get status: ${(error as Error).message}`);
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -237,45 +343,61 @@ const toolsCommand: Command = {
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
const category = ctx.flags.category as string;
|
||||
|
||||
// All 27 MCP tools
|
||||
const tools = [
|
||||
// Coordination
|
||||
{ name: 'swarm_init', category: 'coordination', description: 'Initialize swarm topology', enabled: true },
|
||||
{ name: 'agent_spawn', category: 'coordination', description: 'Spawn agent for coordination', enabled: true },
|
||||
{ name: 'task_orchestrate', category: 'coordination', description: 'Orchestrate task workflows', enabled: true },
|
||||
{ name: 'swarm_scale', category: 'coordination', description: 'Scale swarm size', enabled: true },
|
||||
{ name: 'agent_coordinate', category: 'coordination', description: 'Coordinate agents', enabled: true },
|
||||
// Try to get tools from running server, fall back to static list
|
||||
let tools: Array<{ name: string; category: string; description: string; enabled: boolean }>;
|
||||
|
||||
// Monitoring
|
||||
{ name: 'swarm_status', category: 'monitoring', description: 'Get swarm status', enabled: true },
|
||||
{ name: 'agent_list', category: 'monitoring', description: 'List agents', enabled: true },
|
||||
{ name: 'agent_metrics', category: 'monitoring', description: 'Get agent metrics', enabled: true },
|
||||
{ name: 'task_status', category: 'monitoring', description: 'Get task status', enabled: true },
|
||||
{ name: 'task_results', category: 'monitoring', description: 'Get task results', enabled: true },
|
||||
{ name: 'swarm_monitor', category: 'monitoring', description: 'Real-time monitoring', enabled: true },
|
||||
try {
|
||||
// Import tool registry
|
||||
const { getAllTools, getToolsByCategory, getToolStats } = await import('../../../../mcp/tools/index.js');
|
||||
const allTools = category ? getToolsByCategory(category) : getAllTools();
|
||||
|
||||
// Memory & Neural
|
||||
{ name: 'memory_store', category: 'memory', description: 'Store in memory', enabled: true },
|
||||
{ name: 'memory_retrieve', category: 'memory', description: 'Retrieve from memory', enabled: true },
|
||||
{ name: 'memory_search', category: 'memory', description: 'Search memory', enabled: true },
|
||||
{ name: 'memory_usage', category: 'memory', description: 'Memory usage stats', enabled: true },
|
||||
{ name: 'neural_status', category: 'memory', description: 'Neural system status', enabled: true },
|
||||
{ name: 'neural_train', category: 'memory', description: 'Train neural patterns', enabled: true },
|
||||
{ name: 'neural_patterns', category: 'memory', description: 'List patterns', enabled: true },
|
||||
tools = allTools.map(tool => ({
|
||||
name: tool.name,
|
||||
category: tool.category || 'uncategorized',
|
||||
description: tool.description,
|
||||
enabled: true
|
||||
}));
|
||||
} catch {
|
||||
// Fallback to static tool list
|
||||
tools = [
|
||||
// Agent tools
|
||||
{ name: 'agent/spawn', category: 'agent', description: 'Spawn a new agent', enabled: true },
|
||||
{ name: 'agent/list', category: 'agent', description: 'List all agents', enabled: true },
|
||||
{ name: 'agent/terminate', category: 'agent', description: 'Terminate an agent', enabled: true },
|
||||
{ name: 'agent/status', category: 'agent', description: 'Get agent status', enabled: true },
|
||||
|
||||
// GitHub
|
||||
{ name: 'github_swarm', category: 'github', description: 'GitHub swarm coordination', enabled: true },
|
||||
{ name: 'repo_analyze', category: 'github', description: 'Analyze repository', enabled: true },
|
||||
{ name: 'pr_enhance', category: 'github', description: 'Enhance pull request', enabled: true },
|
||||
{ name: 'issue_triage', category: 'github', description: 'Triage issues', enabled: true },
|
||||
{ name: 'code_review', category: 'github', description: 'Code review', enabled: true },
|
||||
// Swarm tools
|
||||
{ name: 'swarm/init', category: 'swarm', description: 'Initialize swarm topology', enabled: true },
|
||||
{ name: 'swarm/status', category: 'swarm', description: 'Get swarm status', enabled: true },
|
||||
{ name: 'swarm/scale', category: 'swarm', description: 'Scale swarm size', enabled: true },
|
||||
|
||||
// System
|
||||
{ name: 'benchmark_run', category: 'system', description: 'Run benchmarks', enabled: true },
|
||||
{ name: 'features_detect', category: 'system', description: 'Detect features', enabled: true },
|
||||
{ name: 'config_get', category: 'system', description: 'Get configuration', enabled: true },
|
||||
{ name: 'config_set', category: 'system', description: 'Set configuration', enabled: true }
|
||||
].filter(t => !category || t.category === category);
|
||||
// Memory tools
|
||||
{ name: 'memory/store', category: 'memory', description: 'Store in memory', enabled: true },
|
||||
{ name: 'memory/search', category: 'memory', description: 'Search memory', enabled: true },
|
||||
{ name: 'memory/list', category: 'memory', description: 'List memory entries', enabled: true },
|
||||
|
||||
// Config tools
|
||||
{ name: 'config/load', category: 'config', description: 'Load configuration', enabled: true },
|
||||
{ name: 'config/save', category: 'config', description: 'Save configuration', enabled: true },
|
||||
{ name: 'config/validate', category: 'config', description: 'Validate configuration', enabled: true },
|
||||
|
||||
// Hooks tools
|
||||
{ name: 'hooks/pre-edit', category: 'hooks', description: 'Pre-edit hook', enabled: true },
|
||||
{ name: 'hooks/post-edit', category: 'hooks', description: 'Post-edit hook', enabled: true },
|
||||
{ name: 'hooks/pre-command', category: 'hooks', description: 'Pre-command hook', enabled: true },
|
||||
{ name: 'hooks/post-command', category: 'hooks', description: 'Post-command hook', enabled: true },
|
||||
{ name: 'hooks/route', category: 'hooks', description: 'Route task to agent', enabled: true },
|
||||
{ name: 'hooks/explain', category: 'hooks', description: 'Explain routing', enabled: true },
|
||||
{ name: 'hooks/pretrain', category: 'hooks', description: 'Pretrain from repo', enabled: true },
|
||||
{ name: 'hooks/metrics', category: 'hooks', description: 'Learning metrics', enabled: true },
|
||||
{ name: 'hooks/list', category: 'hooks', description: 'List hooks', enabled: true },
|
||||
|
||||
// System tools
|
||||
{ name: 'system/info', category: 'system', description: 'System information', enabled: true },
|
||||
{ name: 'system/health', category: 'system', description: 'Health status', enabled: true },
|
||||
{ name: 'system/metrics', category: 'system', description: 'Server metrics', enabled: true },
|
||||
].filter(t => !category || t.category === category);
|
||||
}
|
||||
|
||||
if (ctx.flags.format === 'json') {
|
||||
output.printJson(tools);
|
||||
@@ -298,9 +420,9 @@ const toolsCommand: Command = {
|
||||
|
||||
output.printTable({
|
||||
columns: [
|
||||
{ key: 'name', header: 'Tool', width: 20 },
|
||||
{ key: 'name', header: 'Tool', width: 25 },
|
||||
{ key: 'description', header: 'Description', width: 35 },
|
||||
{ key: 'enabled', header: 'Status', width: 10, format: (v) => v ? output.success('Enabled') : output.dim('Disabled') }
|
||||
{ key: 'enabled', header: 'Status', width: 10, format: (v: boolean) => v ? output.success('Enabled') : output.dim('Disabled') }
|
||||
],
|
||||
data: catTools,
|
||||
border: false
|
||||
@@ -378,7 +500,7 @@ const execCommand: Command = {
|
||||
}
|
||||
],
|
||||
examples: [
|
||||
{ command: 'claude-flow mcp exec -t swarm_init -p \'{"topology":"mesh"}\'', description: 'Execute tool' }
|
||||
{ command: 'claude-flow mcp exec -t swarm/init -p \'{"topology":"mesh"}\'', description: 'Execute tool' }
|
||||
],
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
const tool = ctx.flags.tool as string || ctx.args[0];
|
||||
@@ -405,26 +527,86 @@ const execCommand: Command = {
|
||||
output.writeln(output.dim(` Parameters: ${JSON.stringify(params)}`));
|
||||
}
|
||||
|
||||
// Simulate tool execution
|
||||
const result = {
|
||||
tool,
|
||||
params,
|
||||
success: true,
|
||||
duration: `${Math.random() * 50 + 5 | 0}ms`,
|
||||
result: {
|
||||
message: `Tool ${tool} executed successfully`,
|
||||
data: { /* simulated result */ }
|
||||
try {
|
||||
// Try to execute through running server or directly
|
||||
const { getToolByName } = await import('../../../../mcp/tools/index.js');
|
||||
const toolDef = getToolByName(tool);
|
||||
|
||||
if (!toolDef) {
|
||||
output.printError(`Tool not found: ${tool}`);
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
};
|
||||
|
||||
output.writeln();
|
||||
output.printSuccess(`Tool executed in ${result.duration}`);
|
||||
const startTime = performance.now();
|
||||
const result = await toolDef.handler(params, {
|
||||
sessionId: `cli-${Date.now().toString(36)}`,
|
||||
requestId: `exec-${Date.now()}`,
|
||||
});
|
||||
const duration = performance.now() - startTime;
|
||||
|
||||
if (ctx.flags.format === 'json') {
|
||||
output.printJson(result);
|
||||
output.writeln();
|
||||
output.printSuccess(`Tool executed in ${duration.toFixed(2)}ms`);
|
||||
|
||||
if (ctx.flags.format === 'json') {
|
||||
output.printJson({ tool, params, result, duration });
|
||||
} else {
|
||||
output.writeln();
|
||||
output.writeln(output.bold('Result:'));
|
||||
output.printJson(result);
|
||||
}
|
||||
|
||||
return { success: true, data: { tool, params, result, duration } };
|
||||
} catch (error) {
|
||||
output.printError(`Tool execution failed: ${(error as Error).message}`);
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { success: true, data: result };
|
||||
// Health check command
|
||||
const healthCommand: Command = {
|
||||
name: 'health',
|
||||
description: 'Check MCP server health',
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
try {
|
||||
const status = await getMCPServerStatus();
|
||||
|
||||
if (!status.running) {
|
||||
output.printError('MCP Server is not running');
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
|
||||
const manager = getServerManager();
|
||||
const health = await manager.checkHealth();
|
||||
|
||||
if (ctx.flags.format === 'json') {
|
||||
output.printJson(health);
|
||||
return { success: true, data: health };
|
||||
}
|
||||
|
||||
output.writeln();
|
||||
output.writeln(output.bold('MCP Server Health'));
|
||||
output.writeln();
|
||||
|
||||
if (health.healthy) {
|
||||
output.printSuccess('Server is healthy');
|
||||
} else {
|
||||
output.printError(`Server is unhealthy: ${health.error || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
if (health.metrics) {
|
||||
output.writeln();
|
||||
output.writeln(output.bold('Metrics:'));
|
||||
for (const [key, value] of Object.entries(health.metrics)) {
|
||||
output.writeln(` ${key}: ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
return { success: health.healthy, data: health };
|
||||
} catch (error) {
|
||||
output.printError(`Health check failed: ${(error as Error).message}`);
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -457,18 +639,12 @@ const logsCommand: Command = {
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
const lines = ctx.flags.lines as number;
|
||||
|
||||
// Simulated logs
|
||||
// Simulated logs for now - would read from actual log file
|
||||
const logs = [
|
||||
{ time: '10:45:23', level: 'info', message: 'MCP Server started on stdio' },
|
||||
{ time: '10:45:24', level: 'info', message: 'Registered 27 tools' },
|
||||
{ time: '10:46:01', level: 'debug', message: 'Received request: swarm_init' },
|
||||
{ time: '10:46:01', level: 'info', message: 'Swarm initialized: hierarchical' },
|
||||
{ time: '10:47:15', level: 'debug', message: 'Received request: agent_spawn' },
|
||||
{ time: '10:47:16', level: 'info', message: 'Agent spawned: coder-1' },
|
||||
{ time: '10:48:30', level: 'warn', message: 'Memory usage high: 75%' },
|
||||
{ time: '10:49:00', level: 'debug', message: 'Received request: memory_store' },
|
||||
{ time: '10:49:01', level: 'info', message: 'Memory stored: patterns/auth' },
|
||||
{ time: '10:50:00', level: 'info', message: 'Heartbeat: 3 active connections' }
|
||||
{ time: new Date().toISOString(), level: 'info', message: 'MCP Server started on stdio' },
|
||||
{ time: new Date().toISOString(), level: 'info', message: 'Registered 27 tools' },
|
||||
{ time: new Date().toISOString(), level: 'debug', message: 'Received request: tools/list' },
|
||||
{ time: new Date().toISOString(), level: 'info', message: 'Session initialized' },
|
||||
].slice(-lines);
|
||||
|
||||
output.writeln();
|
||||
@@ -498,16 +674,61 @@ const logsCommand: Command = {
|
||||
}
|
||||
};
|
||||
|
||||
// Restart command
|
||||
const restartCommand: Command = {
|
||||
name: 'restart',
|
||||
description: 'Restart MCP server',
|
||||
options: [
|
||||
{
|
||||
name: 'force',
|
||||
short: 'f',
|
||||
description: 'Force restart without graceful shutdown',
|
||||
type: 'boolean',
|
||||
default: false
|
||||
}
|
||||
],
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
const force = ctx.flags.force as boolean;
|
||||
|
||||
output.printInfo('Restarting MCP Server...');
|
||||
|
||||
try {
|
||||
const manager = getServerManager();
|
||||
const status = await manager.restart();
|
||||
|
||||
output.printSuccess('MCP Server restarted');
|
||||
output.writeln(output.dim(` PID: ${status.pid}`));
|
||||
|
||||
return { success: true, data: status };
|
||||
} catch (error) {
|
||||
output.printError(`Failed to restart: ${(error as Error).message}`);
|
||||
return { success: false, exitCode: 1 };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Main MCP command
|
||||
export const mcpCommand: Command = {
|
||||
name: 'mcp',
|
||||
description: 'MCP server management',
|
||||
subcommands: [startCommand, stopCommand, statusCommand, toolsCommand, toggleCommand, execCommand, logsCommand],
|
||||
subcommands: [
|
||||
startCommand,
|
||||
stopCommand,
|
||||
statusCommand,
|
||||
healthCommand,
|
||||
restartCommand,
|
||||
toolsCommand,
|
||||
toggleCommand,
|
||||
execCommand,
|
||||
logsCommand
|
||||
],
|
||||
options: [],
|
||||
examples: [
|
||||
{ command: 'claude-flow mcp start', description: 'Start MCP server' },
|
||||
{ command: 'claude-flow mcp start -t http -p 8080', description: 'Start HTTP server on port 8080' },
|
||||
{ command: 'claude-flow mcp status', description: 'Show server status' },
|
||||
{ command: 'claude-flow mcp tools', description: 'List tools' },
|
||||
{ command: 'claude-flow mcp status', description: 'Show status' }
|
||||
{ command: 'claude-flow mcp stop', description: 'Stop the server' }
|
||||
],
|
||||
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
||||
output.writeln();
|
||||
@@ -517,13 +738,15 @@ export const mcpCommand: Command = {
|
||||
output.writeln();
|
||||
output.writeln('Subcommands:');
|
||||
output.printList([
|
||||
`${output.highlight('start')} - Start MCP server`,
|
||||
`${output.highlight('stop')} - Stop MCP server`,
|
||||
`${output.highlight('status')} - Show server status`,
|
||||
`${output.highlight('tools')} - List available tools`,
|
||||
`${output.highlight('toggle')} - Enable/disable tools`,
|
||||
`${output.highlight('exec')} - Execute a tool`,
|
||||
`${output.highlight('logs')} - Show server logs`
|
||||
`${output.highlight('start')} - Start MCP server`,
|
||||
`${output.highlight('stop')} - Stop MCP server`,
|
||||
`${output.highlight('status')} - Show server status`,
|
||||
`${output.highlight('health')} - Check server health`,
|
||||
`${output.highlight('restart')} - Restart MCP server`,
|
||||
`${output.highlight('tools')} - List available tools`,
|
||||
`${output.highlight('toggle')} - Enable/disable tools`,
|
||||
`${output.highlight('exec')} - Execute a tool`,
|
||||
`${output.highlight('logs')} - Show server logs`
|
||||
]);
|
||||
|
||||
return { success: true };
|
||||
|
||||
Reference in new issue
Block a user