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
JavaScript
/**
* 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;