UNPKG

task-engine-ai-core

Version:

Revolutionary AI-driven task management system with complete transformation trilogy: Frontend v0.1.0, Backend v0.2.0, CLI v0.3.0 - Enterprise-grade performance with 95% improvements

301 lines (261 loc) 10.9 kB
#!/usr/bin/env node /** * MCP Bridge Server * Provides MCP interface for IDE bridge functionality */ import { FastMCP } from 'fastmcp'; import { z } from 'zod'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import logger from '../../mcp-server/src/logger.js'; import { IDEAgentInterface } from './ide-agent-interface.js'; import IDEDetection from './ide-detection.js'; import BridgeConfig from './bridge-config.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); class MCPBridgeServer { constructor() { // Get version from package.json const packagePath = path.join(__dirname, '../../package.json'); const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8')); this.options = { name: 'Task Master IDE Bridge MCP Server', version: packageJson.version }; this.server = new FastMCP(this.options); this.initialized = false; this.ideInterface = null; this.ideDetection = new IDEDetection(); this.bridgeConfig = new BridgeConfig(); this.logger = logger; // Bind methods this.init = this.init.bind(this); this.start = this.start.bind(this); this.stop = this.stop.bind(this); } /** * Initialize the MCP bridge server */ async init() { if (this.initialized) return; // Load bridge configuration await this.bridgeConfig.load(); // Register MCP tools for IDE bridge this.registerIDEBridgeTools(); this.initialized = true; return this; } /** * Register IDE bridge tools with MCP server */ registerIDEBridgeTools() { // Tool: Detect IDE this.server.addTool({ name: 'detect_ide', description: 'Detect available IDEs and their capabilities', parameters: z.object({ forceRefresh: z.boolean().optional().default(false).describe('Force refresh of IDE detection cache') }), execute: async (args) => { try { if (args.forceRefresh) { this.ideDetection.detectionCache.clear(); } const availableIDEs = await this.ideDetection.detectAvailableIDEs(); const bestIDE = await this.ideDetection.getBestIDE(); return JSON.stringify({ availableIDEs, bestIDE, timestamp: new Date().toISOString() }, null, 2); } catch (error) { this.logger.error('IDE detection failed:', error); return `Error detecting IDEs: ${error.message}`; } } }); // Tool: Connect to IDE this.server.addTool({ name: 'connect_ide', description: 'Connect to a specific IDE agent', parameters: z.object({ ideType: z.enum(['cursor', 'vscode', 'windsurf', 'auto-detect']).optional().default('auto-detect').describe('Type of IDE to connect to'), timeout: z.number().optional().default(10000).describe('Connection timeout in milliseconds') }), execute: async (args) => { try { // Disconnect existing interface if any if (this.ideInterface) { await this.ideInterface.disconnect(); } // Create new IDE interface this.ideInterface = new IDEAgentInterface({ ideType: args.ideType, responseTimeout: args.timeout }); await this.ideInterface.initialize(); const status = this.ideInterface.getStatus(); return JSON.stringify({ connected: status.connected, ideType: status.ideType, capabilities: status.capabilities, activeModel: status.activeModel, isMock: this.ideInterface.connectionInfo?.isMock || false, timestamp: new Date().toISOString() }, null, 2); } catch (error) { this.logger.error('IDE connection failed:', error); return `Error connecting to IDE: ${error.message}`; } } }); // Tool: Generate text via IDE this.server.addTool({ name: 'ide_generate_text', description: 'Generate text using the connected IDE agent', parameters: z.object({ messages: z.array(z.object({ role: z.enum(['user', 'assistant', 'system']), content: z.string() })).describe('Array of messages for the conversation'), maxTokens: z.number().optional().default(1000).describe('Maximum tokens to generate'), temperature: z.number().min(0).max(2).optional().default(0.7).describe('Temperature for generation'), modelId: z.string().optional().describe('Specific model ID to use (optional)') }), execute: async (args) => { try { if (!this.ideInterface || !this.ideInterface.initialized) { throw new Error('IDE interface not connected. Use connect_ide tool first.'); } const response = await this.ideInterface.sendRequest({ type: 'generate-text', payload: { messages: args.messages, maxTokens: args.maxTokens, temperature: args.temperature, modelId: args.modelId } }); return JSON.stringify({ text: response.text, usage: response.usage, model: response.model, provider: response.provider, timestamp: response.timestamp }, null, 2); } catch (error) { this.logger.error('IDE text generation failed:', error); return `Error generating text: ${error.message}`; } } }); // Tool: Get IDE status this.server.addTool({ name: 'ide_status', description: 'Get current IDE connection status and capabilities', parameters: z.object({}), execute: async () => { try { if (!this.ideInterface) { return JSON.stringify({ connected: false, message: 'No IDE interface initialized' }, null, 2); } const status = this.ideInterface.getStatus(); const healthCheck = await this.ideInterface.healthCheck(); return JSON.stringify({ ...status, health: healthCheck, timestamp: new Date().toISOString() }, null, 2); } catch (error) { this.logger.error('IDE status check failed:', error); return `Error getting IDE status: ${error.message}`; } } }); // Tool: Configure bridge this.server.addTool({ name: 'configure_bridge', description: 'Configure IDE bridge settings', parameters: z.object({ ideType: z.enum(['cursor', 'vscode', 'windsurf', 'auto-detect']).optional().describe('IDE type to configure'), enabled: z.boolean().optional().describe('Enable or disable the bridge'), port: z.number().min(1024).max(65535).optional().describe('Bridge server port'), fallbackToExternal: z.boolean().optional().describe('Allow fallback to external APIs') }), execute: async (args) => { try { if (args.ideType) { await this.bridgeConfig.set('ide.type', args.ideType); } if (typeof args.enabled === 'boolean') { await this.bridgeConfig.set('bridge.enabled', args.enabled); } if (args.port) { await this.bridgeConfig.set('bridge.port', args.port); } if (typeof args.fallbackToExternal === 'boolean') { await this.bridgeConfig.set('ide.fallbackToExternal', args.fallbackToExternal); } const status = this.bridgeConfig.getStatus(); return JSON.stringify({ message: 'Bridge configuration updated', status, timestamp: new Date().toISOString() }, null, 2); } catch (error) { this.logger.error('Bridge configuration failed:', error); return `Error configuring bridge: ${error.message}`; } } }); } /** * Start the MCP bridge server */ async start() { if (!this.initialized) { await this.init(); } // Start the FastMCP server await this.server.start({ transportType: 'stdio', timeout: 120000 // 2 minutes timeout }); this.logger.info('MCP Bridge Server started'); return this; } /** * Stop the MCP bridge server */ async stop() { if (this.ideInterface) { await this.ideInterface.disconnect(); } if (this.server) { await this.server.stop(); } this.logger.info('MCP Bridge Server stopped'); } } // Start server if called directly if (import.meta.url === `file://${process.argv[1]}`) { const server = new MCPBridgeServer(); // Handle graceful shutdown process.on('SIGINT', async () => { await server.stop(); process.exit(0); }); process.on('SIGTERM', async () => { await server.stop(); process.exit(0); }); server.start().catch((error) => { logger.error(`Failed to start MCP Bridge Server: ${error.message}`); process.exit(1); }); } export default MCPBridgeServer;