UNPKG

bc-code-intelligence-mcp

Version:

BC Code Intelligence MCP Server - Complete Specialist Bundle with AI-driven expert consultation, seamless handoffs, and context-preserving workflows

380 lines 12.9 kB
/** * BC Code Intelligence MCP Client SDK * * TypeScript/JavaScript SDK for connecting to BC Code Intelligence MCP servers * with full type safety, intelligent caching, and developer-friendly APIs. */ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { EventEmitter } from 'events'; export class BCCodeIntelClient extends EventEmitter { config; client; transport = null; connected = false; cache = new Map(); reconnectTimer; constructor(config) { super(); this.config = config; this.client = new Client({ name: 'bc-code-intel-client', version: '1.0.0', capabilities: {} }); if (this.config.debug_logging) { console.log('🔌 BC Code Intelligence Client initialized with config:', this.config); } } /** * Connect to the BC Code Intelligence MCP server */ async connect() { try { if (this.connected) { console.warn('🔌 Already connected to BC Code Intelligence server'); return; } this.transport = new StdioClientTransport({ command: this.config.server_command, args: this.config.server_args || [] }); await this.client.connect(this.transport); this.connected = true; this.emit('connected'); if (this.config.debug_logging) { console.log('✅ Connected to BC Code Intelligence MCP server'); } } catch (error) { this.emit('error', error); throw new Error(`Failed to connect to BC Code Intelligence server: ${error instanceof Error ? error.message : String(error)}`); } } /** * Disconnect from the server */ async disconnect() { if (!this.connected) return; try { if (this.transport) { await this.transport.close(); this.transport = null; } this.connected = false; this.cache.clear(); if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = undefined; } this.emit('disconnected'); if (this.config.debug_logging) { console.log('🔌 Disconnected from BC Code Intelligence server'); } } catch (error) { this.emit('error', error); } } /** * Search for BC knowledge topics */ async searchTopics(query, options = {}) { const toolArgs = { tags: options.tags, domain: options.domain, difficulty: options.difficulty, code_context: query, bc_version: options.bc_version, limit: options.limit || 10 }; const result = await this.callTool('find_bc_topics', toolArgs); return JSON.parse(result.content[0].text).results; } /** * Advanced layered search with AI-powered recommendations */ async smartSearch(query, options = {}) { const toolArgs = { query, layer_filter: options.layer_filter, include_layer_info: options.include_layer_info !== false, limit: options.limit || 10 }; const result = await this.callTool('search_layered_topics', toolArgs); const response = JSON.parse(result.content[0].text); return response.results; } /** * Get a specific topic by ID */ async getTopic(topicId, includeSamples = true) { try { const result = await this.callTool('get_topic_content', { topic_id: topicId, include_samples: includeSamples }); return JSON.parse(result.content[0].text); } catch (error) { if (this.config.debug_logging) { console.warn(`🔍 Topic not found: ${topicId}`); } return null; } } /** * Analyze AL code and get recommendations */ async analyzeCode(options) { const result = await this.callTool('analyze_code_patterns', options); return JSON.parse(result.content[0].text); } /** * Get optimization workflow for a scenario */ async getOptimizationWorkflow(scenario, constraints) { const result = await this.callTool('get_optimization_workflow', { scenario, constraints: constraints || [] }); return JSON.parse(result.content[0].text); } /** * Get system status and health information */ async getSystemStatus() { const result = await this.callTool('get_configuration_status', { include_validation: true, include_performance: true }); const response = JSON.parse(result.content[0].text); return { overall_health: response.validation?.is_valid ? 'healthy' : 'degraded', configuration_loaded: response.configuration_loaded, layers_active: response.layers_initialized, total_topics: response.layer_summary?.total_topics || 0, cache_hit_rate: response.performance?.hit_rate || 0, uptime_seconds: response.performance?.uptime_seconds || 0 }; } /** * Get layer information and statistics */ async getLayerInfo(includeStatistics = true) { const result = await this.callTool('get_layer_info', { include_statistics: includeStatistics }); return JSON.parse(result.content[0].text); } /** * Resolve topic across layers to see override information */ async resolveTopicLayers(topicId) { const result = await this.callTool('resolve_topic_layers', { topic_id: topicId, show_overrides: true }); return JSON.parse(result.content[0].text); } /** * Get comprehensive system analytics */ async getSystemAnalytics() { const result = await this.callTool('get_system_analytics', { include_topic_analytics: true, include_layer_performance: true, include_configuration_insights: true }); return JSON.parse(result.content[0].text); } /** * Reload server configuration (useful for development) */ async reloadConfiguration(force = false) { const result = await this.callTool('reload_configuration', { force, validate_only: false }); return JSON.parse(result.content[0].text); } /** * Get available MCP tools from the server */ async getAvailableTools() { try { const response = await this.client.request({ method: 'tools/list', params: {} }, CallToolRequestSchema); return response.tools || []; } catch (error) { this.emit('error', error); throw error; } } /** * Health check - verify connection and basic functionality */ async healthCheck() { const startTime = Date.now(); try { await this.getSystemStatus(); const latency = Date.now() - startTime; return { healthy: true, latency_ms: latency }; } catch (error) { const latency = Date.now() - startTime; return { healthy: false, latency_ms: latency, error: error instanceof Error ? error.message : String(error) }; } } /** * Batch operations for efficiency */ async batchGetTopics(topicIds) { const promises = topicIds.map(id => this.getTopic(id)); return Promise.all(promises); } /** * Smart topic recommendations based on current context */ async getRecommendations(currentTopic, maxRecommendations = 5) { // This would use AI-powered recommendations if available // For now, we'll simulate with related topics search const topic = await this.getTopic(currentTopic); if (!topic) return []; const relatedSearches = await Promise.all([ this.searchTopics(`domain:${topic.domain}`, { limit: 3 }), this.searchTopics(`difficulty:${topic.difficulty}`, { limit: 3 }) ]); const recommendations = [...relatedSearches[0], ...relatedSearches[1]] .filter(rec => rec.id !== currentTopic) .slice(0, maxRecommendations); return recommendations; } /** * Export client configuration (sanitized) */ getClientConfig() { const { debug_logging, ...config } = this.config; return config; } /** * Check if client is connected */ isConnected() { return this.connected; } // Private helper methods async callTool(toolName, args) { this.ensureConnected(); // Check cache first if (this.config.cache_enabled) { const cacheKey = `${toolName}:${JSON.stringify(args)}`; const cached = this.cache.get(cacheKey); if (cached && Date.now() < cached.expires) { if (this.config.debug_logging) { console.log(`💾 Cache hit for ${toolName}`); } return cached.data; } } try { const result = await this.client.request({ method: 'tools/call', params: { name: toolName, arguments: args } }, CallToolRequestSchema); // Cache the result if (this.config.cache_enabled) { const cacheKey = `${toolName}:${JSON.stringify(args)}`; const ttl = (this.config.cache_ttl_seconds || 300) * 1000; this.cache.set(cacheKey, { data: result, expires: Date.now() + ttl }); } return result; } catch (error) { this.emit('error', error); // Auto-reconnect if enabled if (this.config.auto_reconnect && !this.reconnectTimer) { this.scheduleReconnect(); } throw error; } } ensureConnected() { if (!this.connected) { throw new Error('Not connected to BC Code Intelligence server. Call connect() first.'); } } scheduleReconnect() { if (this.reconnectTimer) return; this.reconnectTimer = setTimeout(async () => { try { if (this.config.debug_logging) { console.log('🔄 Attempting to reconnect to BC Code Intelligence server...'); } await this.disconnect(); await this.connect(); this.reconnectTimer = undefined; if (this.config.debug_logging) { console.log('✅ Reconnected to BC Code Intelligence server'); } } catch (error) { if (this.config.debug_logging) { console.warn('❌ Reconnection failed:', error); } // Schedule another attempt this.reconnectTimer = undefined; this.scheduleReconnect(); } }, 5000); // Retry after 5 seconds } } /** * Convenience factory function for creating BC Code Intelligence clients */ export function createBCCodeIntelClient(config) { return new BCCodeIntelClient(config); } /** * Default configuration for common scenarios */ export const BCCodeIntelClientDefaults = { local: (serverPath) => ({ server_command: serverPath || 'node', server_args: ['dist/index.js'], auto_reconnect: true, request_timeout_ms: 10000, cache_enabled: true, cache_ttl_seconds: 300, debug_logging: false }), development: (serverPath) => ({ server_command: serverPath || 'npm', server_args: ['run', 'dev'], auto_reconnect: true, request_timeout_ms: 30000, cache_enabled: false, // Disable cache for development cache_ttl_seconds: 60, debug_logging: true }), production: (serverPath) => ({ server_command: serverPath, server_args: [], auto_reconnect: true, request_timeout_ms: 5000, cache_enabled: true, cache_ttl_seconds: 600, // 10 minutes debug_logging: false }) }; //# sourceMappingURL=bc-code-intel-client.js.map