Bash MCP (Master Control Program)

by yannbam
Verified
import { MCPConfig, ExecutionOptions, ExecutionResult, SessionInput } from '../types'; import { logger } from '../utils/logger'; import { CommandExecutor } from './command-executor'; import { SessionManager } from './session-manager'; export class BashMCP { private config: MCPConfig; private commandExecutor: CommandExecutor; private sessionManager: SessionManager; constructor(config: MCPConfig) { this.config = config; this.commandExecutor = new CommandExecutor(config); this.sessionManager = new SessionManager(config); logger.info('Bash MCP initialized'); } /** * Execute a command with the given options */ public async executeCommand( command: string, options: ExecutionOptions = {} ): Promise<ExecutionResult> { try { // Check if this is a stateful command (using an existing session) if (options.sessionId) { logger.info(`Executing command in existing session: ${options.sessionId}`); return this.sessionManager.executeInSession(options.sessionId, command); } // Determine if we should create a new session or execute stateless if (options.cwd && this.config.session.defaultMode === 'stateful') { // Create a new session const session = this.sessionManager.createSession(options.cwd); if (!session) { return { success: false, output: '', error: 'Failed to create session', command, }; } logger.info(`Created new session ${session.id} for command execution`); return this.sessionManager.executeInSession(session.id, command); } // Execute stateless logger.info('Executing stateless command'); return this.commandExecutor.executeCommand(command, options); } catch (error) { logger.error( `Error executing command: ${error instanceof Error ? error.message : String(error)}` ); return { success: false, output: '', error: error instanceof Error ? error.message : String(error), command, }; } } /** * Send input to an interactive session */ public sendInput(input: SessionInput): Promise<ExecutionResult> { const { sessionId, input: inputText } = input; logger.info(`Sending input to session: ${sessionId}`); // Get the session const session = this.sessionManager.getSession(sessionId); if (!session) { return Promise.resolve({ success: false, output: '', error: `Session ${sessionId} not found`, command: inputText, }); } // Send the input const success = this.sessionManager.sendInput(sessionId, inputText); if (!success) { return Promise.resolve({ success: false, output: '', error: 'Failed to send input to session', command: inputText, }); } // Return a promise that resolves after collecting output return new Promise((resolve) => { // In a real implementation, we would need a more sophisticated way to collect // the output generated in response to the input. For now, we'll use a simple timeout. setTimeout(() => { resolve({ success: true, output: 'Output collected after input (placeholder)', sessionId, command: inputText, isInteractive: true, waitingForInput: true, // This would need proper detection }); }, 1000); }); } /** * Create a new interactive session */ public createSession(cwd: string): { success: boolean; sessionId?: string; error?: string } { logger.info(`Creating new session in directory: ${cwd}`); const session = this.sessionManager.createSession(cwd); if (!session) { return { success: false, error: 'Failed to create session', }; } return { success: true, sessionId: session.id, }; } /** * Close a session */ public closeSession(sessionId: string): { success: boolean; error?: string } { logger.info(`Closing session: ${sessionId}`); const success = this.sessionManager.closeSession(sessionId); if (!success) { return { success: false, error: `Failed to close session ${sessionId}`, }; } return { success: true, }; } /** * List all active sessions */ public listSessions() { return this.sessionManager.listSessions(); } /** * Shut down the MCP */ public shutdown(): void { logger.info('Shutting down Bash MCP'); this.sessionManager.shutdown(); } }