@sethdouglasford/claude-flow
Version:
Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology
417 lines • 14.6 kB
JavaScript
/**
* MCP (Model Context Protocol) server implementation
*/
import { MCPError as MCPErrorClass, MCPMethodNotFoundError } from "../utils/errors.js";
import { StdioTransport } from "./transports/stdio.js";
import { HttpTransport } from "./transports/http.js";
import { ToolRegistry } from "./tools.js";
import { PromptRegistry } from "./prompts.js";
import { RequestRouter } from "./router.js";
import { SessionManager } from "./session-manager.js";
import { AuthManager } from "./auth.js";
import { LoadBalancer, RequestQueue } from "./load-balancer.js";
import { createClaudeFlowTools } from "./claude-flow-tools.js";
// import { createSwarmTools, SwarmToolContext } from "./swarm-tools.js"; // File missing, temporarily disabled
import { platform, arch } from "node:os";
import { performance } from "node:perf_hooks";
/**
* MCP server implementation
*/
export class MCPServer {
config;
eventBus;
logger;
orchestrator;
swarmCoordinator;
agentManager;
resourceManager;
messagebus;
monitor;
transport;
toolRegistry;
promptRegistry;
router;
sessionManager;
authManager;
loadBalancer;
requestQueue;
running = false;
currentSession;
serverInfo = {
name: "claude-flow",
version: "1.5.5",
};
supportedProtocolVersion = {
major: 2024,
minor: 11,
patch: 5,
};
serverCapabilities = {
logging: {
level: "info",
},
tools: {
listChanged: true,
},
resources: {
listChanged: false,
subscribe: false,
},
prompts: {
listChanged: true,
},
};
constructor(config, eventBus, logger, orchestrator, // Reference to orchestrator instance
swarmCoordinator, // Reference to swarm coordinator instance
agentManager, // Reference to agent manager instance
resourceManager, // Reference to resource manager instance
messagebus, // Reference to message bus instance
monitor) {
this.config = config;
this.eventBus = eventBus;
this.logger = logger;
this.orchestrator = orchestrator;
this.swarmCoordinator = swarmCoordinator;
this.agentManager = agentManager;
this.resourceManager = resourceManager;
this.messagebus = messagebus;
this.monitor = monitor;
// Initialize registries
this.toolRegistry = new ToolRegistry(this.logger);
this.promptRegistry = new PromptRegistry(this.logger);
// Initialize router with both registries
this.router = new RequestRouter(this.toolRegistry, this.promptRegistry, this.logger);
// Initialize managers
this.sessionManager = new SessionManager(this.config, this.logger);
this.authManager = new AuthManager(this.config.auth ?? { enabled: false, method: "token" }, this.logger);
// Initialize load balancer if configured
if (this.config.loadBalancer?.enabled) {
this.loadBalancer = new LoadBalancer(this.config.loadBalancer, this.logger);
this.requestQueue = new RequestQueue(1000, 30000, this.logger);
}
// Create transport
this.transport = this.createTransport();
// Register built-in tools
this.registerBuiltInTools();
// Register Claude-Flow specific tools
this.registerClaudeFlowTools();
}
async start() {
if (this.running) {
throw new MCPErrorClass("Server is already running");
}
try {
// Load Claude prompts from .claude directory
await this.promptRegistry.loadClaudePrompts();
// Start transport
await this.transport.start();
// Set up request handling
this.transport.onRequest(this.handleRequest.bind(this));
this.running = true;
this.logger.info("MCP server started", {
transport: this.config.transport,
tools: this.toolRegistry.listTools().length,
prompts: this.promptRegistry.listPrompts().length,
});
// Emit start event
this.eventBus.emit("mcp:server:started", {
transport: this.config.transport,
capabilities: this.serverCapabilities,
});
}
catch (error) {
this.logger.error("Failed to start MCP server", error);
throw error;
}
}
async stop() {
if (!this.running) {
return;
}
try {
// Stop transport
await this.transport.stop();
// Clean up sessions
const sessions = this.sessionManager.getActiveSessions();
for (const session of sessions) {
this.sessionManager.removeSession(session.id);
}
this.running = false;
this.logger.info("MCP server stopped");
// Emit stop event
this.eventBus.emit("mcp:server:stopped", {});
}
catch (error) {
this.logger.error("Error stopping MCP server", error);
throw error;
}
}
registerTool(tool) {
this.toolRegistry.register(tool);
}
async getHealthStatus() {
try {
const metrics = this.getMetrics();
const healthy = this.running &&
this.transport !== undefined &&
metrics.activeSessions >= 0;
return {
healthy,
metrics: {
uptime: performance.now(),
sessions: metrics.activeSessions,
tools: this.toolRegistry.listTools().length,
prompts: this.promptRegistry.listPrompts().length,
requests: metrics.totalRequests,
},
};
}
catch (error) {
return {
healthy: false,
error: error instanceof Error ? error.message : String(error),
};
}
}
getMetrics() {
const sessions = this.sessionManager.getActiveSessions();
const routerMetrics = this.router.getMetrics();
return {
totalRequests: routerMetrics.totalRequests,
successfulRequests: routerMetrics.successfulRequests,
failedRequests: routerMetrics.failedRequests,
averageResponseTime: 0, // TODO: Implement response time tracking
activeSessions: sessions.length,
toolInvocations: {}, // TODO: Implement tool invocation tracking
errors: {}, // TODO: Implement error categorization
lastReset: new Date(),
};
}
getSessions() {
return this.sessionManager.getActiveSessions();
}
getSession(sessionId) {
return this.sessionManager.getSession(sessionId);
}
terminateSession(sessionId) {
this.sessionManager.removeSession(sessionId);
}
async handleRequest(request) {
try {
// Handle initialization separately
if (request.method === "initialize") {
return await this.handleInitialize(request);
}
// Get or create session
const session = this.getOrCreateSession();
// Check if session is initialized for non-initialize requests
if (!session.isInitialized) {
return {
jsonrpc: "2.0",
id: request.id,
error: {
code: -32002,
message: "Server not initialized",
},
};
}
// Update session activity
this.sessionManager.updateActivity(session.id);
// Check load balancer constraints
if (this.loadBalancer) {
const allowed = await this.loadBalancer.shouldAllowRequest(session, request);
if (!allowed) {
return {
jsonrpc: "2.0",
id: request.id,
error: {
code: -32000,
message: "Rate limit exceeded or circuit breaker open",
},
};
}
}
// Record request start
const requestMetrics = this.loadBalancer?.recordRequestStart(session, request);
try {
// Process request through router
const result = await this.router.route(request);
const response = {
jsonrpc: "2.0",
id: request.id,
result,
};
// Record success
if (requestMetrics) {
this.loadBalancer?.recordRequestEnd(requestMetrics, response);
}
return response;
}
catch (error) {
// Record failure
if (requestMetrics) {
this.loadBalancer?.recordRequestEnd(requestMetrics, undefined, error);
}
throw error;
}
}
catch (error) {
this.logger.error("Error handling MCP request", {
id: request.id,
method: request.method,
error,
});
return {
jsonrpc: "2.0",
id: request.id,
error: this.errorToMCPError(error),
};
}
}
async handleInitialize(request) {
try {
const params = request.params;
if (!params) {
return {
jsonrpc: "2.0",
id: request.id,
error: {
code: -32602,
message: "Invalid params",
},
};
}
// Create session
const session = this.sessionManager.createSession(this.config.transport);
this.currentSession = session;
// Initialize session
this.sessionManager.initializeSession(session.id, params);
// Prepare response
const result = {
protocolVersion: this.supportedProtocolVersion,
capabilities: this.serverCapabilities,
serverInfo: this.serverInfo,
instructions: "Claude-Flow MCP Server ready for tool execution and custom prompts",
};
this.logger.info("Session initialized", {
sessionId: session.id,
clientInfo: params.clientInfo,
protocolVersion: params.protocolVersion,
tools: this.toolRegistry.listTools().length,
prompts: this.promptRegistry.listPrompts().length,
availableSlashCommands: this.promptRegistry.listPrompts().map(p => `/mcp__claude-flow__${p.name}`),
});
return {
jsonrpc: "2.0",
id: request.id,
result,
};
}
catch (error) {
this.logger.error("Error during initialization", error);
return {
jsonrpc: "2.0",
id: request.id,
error: this.errorToMCPError(error),
};
}
}
getOrCreateSession() {
if (this.currentSession) {
return this.currentSession;
}
// For stdio transport, create a default session
const session = this.sessionManager.createSession(this.config.transport);
this.currentSession = session;
return session;
}
createTransport() {
switch (this.config.transport) {
case "stdio":
return new StdioTransport(this.logger);
case "http":
return new HttpTransport(this.config.host || "localhost", this.config.port || 3000, this.config.tlsEnabled ?? false, this.logger);
default:
throw new MCPErrorClass(`Unknown transport type: ${this.config.transport}`);
}
}
registerBuiltInTools() {
// System information tool
this.registerTool({
name: "system/info",
description: "Get system information",
inputSchema: {
type: "object",
properties: {},
},
handler: async () => {
return {
version: "1.0.0",
platform: platform(),
arch: arch(),
runtime: "Node.js",
uptime: performance.now(),
};
},
});
// Health check tool
this.registerTool({
name: "system/health",
description: "Get system health status",
inputSchema: {
type: "object",
properties: {},
},
handler: async () => {
return await this.getHealthStatus();
},
});
// List tools
this.registerTool({
name: "tools/list",
description: "List all available tools",
inputSchema: {
type: "object",
properties: {},
},
handler: async () => {
return this.toolRegistry.listTools();
},
});
}
registerClaudeFlowTools() {
// Create Claude-Flow specific tools
const tools = createClaudeFlowTools(this.logger);
// Register all tools
for (const tool of tools) {
this.registerTool(tool);
}
this.logger.info("Registered Claude-Flow tools", { count: tools.length });
}
errorToMCPError(error) {
if (error instanceof MCPErrorClass) {
return {
code: -32000,
message: error.message,
data: error.details,
};
}
if (error instanceof MCPMethodNotFoundError) {
return {
code: -32601,
message: error.message,
};
}
if (error instanceof Error) {
return {
code: -32603,
message: error.message,
};
}
return {
code: -32603,
message: "Internal error",
};
}
}
//# sourceMappingURL=server.js.map