bc-code-intelligence-mcp
Version:
BC Code Intelligence MCP Server - Complete Specialist Bundle with AI-driven expert consultation, seamless handoffs, and context-preserving workflows
974 lines (963 loc) • 61.7 kB
JavaScript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { readFileSync, existsSync } from 'fs';
import { getAllToolDefinitions, STREAMLINED_TOOL_NAMES, SpecialistTools, SpecialistDiscoveryTools, AgentOnboardingTools, SpecialistHandoffTools } from './tools/index.js';
import { createStreamlinedHandlers } from './streamlined-handlers.js';
import { KnowledgeService } from './services/knowledge-service.js';
import { CodeAnalysisService } from './services/code-analysis-service.js';
import { MethodologyService } from './services/methodology-service.js';
import { WorkflowService } from './services/workflow-service.js';
import { getDomainList } from './types/bc-knowledge.js';
import { MultiContentLayerService } from './services/multi-content-layer-service.js';
import { SpecialistSessionManager } from './services/specialist-session-manager.js';
import { SpecialistDiscoveryService } from './services/specialist-discovery.js';
import { EnhancedPromptService } from './services/enhanced-prompt-service.js';
import { ConfigurationLoader } from './config/config-loader.js';
import { ConfigurationValidator } from './config/config-validator.js';
import { ConfigDiagnosticTools } from './tools/config-diagnostic-tools.js';
import { domainWorkflows } from './workflows/domain-workflows.js';
import { LayerSourceType } from './types/index.js';
import { WorkspaceTools } from './tools/workspace-tools.js';
/**
* BC Code Intelligence MCP Server
*
* Business Central Code Intelligence Model Context Protocol Server
* Surfaces atomic BC knowledge topics for intelligent AI consumption
* via GitHub Copilot, Claude, and other LLM tools.
*/
class BCCodeIntelligenceServer {
server;
knowledgeService;
codeAnalysisService;
methodologyService;
workflowService;
layerService;
specialistSessionManager;
specialistTools;
specialistDiscoveryService;
specialistDiscoveryTools;
enhancedPromptService;
agentOnboardingTools;
specialistHandoffTools;
configDiagnosticTools;
configuration;
configLoader;
workspaceRoot = null;
availableMcps = [];
hasWarnedAboutWorkspace = false;
workspaceTools;
servicesInitialized = false;
getPackageVersion() {
try {
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const packagePath = join(__dirname, '..', 'package.json');
console.error(`🔍 Looking for package.json at: ${packagePath}`);
console.error(` Exists: ${existsSync(packagePath)}`);
if (!existsSync(packagePath)) {
console.error(`⚠️ package.json not found at expected location`);
return '1.0.0'; // fallback
}
const packageJson = JSON.parse(readFileSync(packagePath, 'utf8'));
const version = packageJson.version || '1.0.0';
console.error(` Version: ${version}`);
return version;
}
catch (error) {
console.error(`⚠️ Error reading package.json:`, error instanceof Error ? error.message : String(error));
return '1.0.0'; // fallback
}
}
constructor() {
// Log startup diagnostics
console.error(`[startup] MCP Server starting...`);
console.error(`[startup] Process CWD: ${process.cwd()}`);
console.error(`[startup] Node version: ${process.version}`);
// Initialize MCP server
this.server = new Server({
name: 'bc-code-intelligence-mcp',
version: this.getPackageVersion(),
});
// Initialize configuration loader
this.configLoader = new ConfigurationLoader();
// Initialize workspace tools
const workspaceContext = {
setWorkspaceInfo: this.setWorkspaceInfo.bind(this),
getWorkspaceInfo: () => ({
workspace_root: this.workspaceRoot,
available_mcps: this.availableMcps
})
};
this.workspaceTools = new WorkspaceTools(workspaceContext);
// Services will be initialized asynchronously in run()
this.setupToolHandlers();
this.setupPrompts();
}
setupToolHandlers() {
// List available tools - now using centralized registry
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
const tools = getAllToolDefinitions({
specialistTools: this.specialistTools,
specialistDiscoveryTools: this.specialistDiscoveryTools,
onboardingTools: this.agentOnboardingTools,
handoffTools: this.specialistHandoffTools
});
// Add workspace tools (always available)
tools.push(...this.workspaceTools.getToolDefinitions());
// Add configuration diagnostic tools if available AND enabled
if (this.configDiagnosticTools) {
tools.push(...this.configDiagnosticTools.getToolDefinitions());
}
return { tools };
});
// Handle tool calls - now using centralized tool names
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
// Workspace tools are always available (no interception)
if (['set_workspace_info', 'get_workspace_info', 'set_workspace_root', 'get_workspace_root'].includes(name)) {
return await this.workspaceTools.handleToolCall(request);
}
// Intercept all other tools if services not initialized
if (!this.servicesInitialized) {
return {
content: [{
type: 'text',
text: `⚠️ **Workspace Not Configured**
The BC Code Intelligence server needs workspace information to load project-specific configuration and knowledge layers.
**Option 1: Set workspace info** (recommended for project-specific layers and MCP ecosystem awareness)
\`\`\`
set_workspace_info({
workspace_root: "C:/your/project/path",
available_mcps: [] // REQUIRED: Examine your available tools and infer MCP servers (see tool description)
})
\`\`\`
**How to populate available_mcps:**
Check which tools you have available and add the corresponding MCP server IDs:
- Have \`search_telemetry_traces\`? Add "bc-telemetry-buddy"
- Have \`reserve_object_ids\`? Add "al-objid-mcp-server"
- Have \`analyze_dependencies\`? Add "al-dependency-mcp-server"
- Have \`get_lsp_diagnostics\`? Add "serena-mcp"
- Have \`create_work_item\`? Add "azure-devops-mcp"
- Have \`track_time_entry\`? Add "clockify-mcp"
- Have \`translate_xliff\`? Add "nab-al-tools-mcp"
**Option 2: Use user-level config** (works without workspace)
Place a configuration file at:
- Windows: \`%USERPROFILE%\\.bckb\\config.yml\`
- Linux/Mac: \`~/.bckb/config.yml\`
Use absolute paths in the config for git/local layers.
Currently only embedded knowledge is loaded. Call \`set_workspace_info\` to enable project layers and MCP ecosystem awareness.`
}]
};
}
// Check if it's a specialist tool
if (this.specialistTools && ['suggest_specialist', 'get_specialist_advice', 'list_specialists'].includes(name)) {
return await this.specialistTools.handleToolCall(request);
}
// Check if it's a specialist discovery tool
if (this.specialistDiscoveryTools && ['discover_specialists', 'browse_specialists', 'get_specialist_info'].includes(name)) {
return await this.specialistDiscoveryTools.handleToolCall(request);
}
// Check if it's an agent onboarding tool
if (this.agentOnboardingTools && ['introduce_bc_specialists', 'get_specialist_introduction', 'suggest_next_specialist'].includes(name)) {
return await this.agentOnboardingTools.handleToolCall(request);
}
// Check if it's a specialist handoff tool
if (this.specialistHandoffTools && ['handoff_to_specialist', 'bring_in_specialist', 'get_handoff_summary'].includes(name)) {
return await this.specialistHandoffTools.handleToolCall(request);
}
// Check if it's a configuration diagnostic tool
if (this.configDiagnosticTools && ['diagnose_git_layer', 'validate_layer_config', 'test_azure_devops_pat', 'get_layer_diagnostics', 'diagnose_local_layer', 'reload_layers'].includes(name)) {
return await this.configDiagnosticTools.handleToolCall(request);
}
// Create streamlined handlers with all services
const handlers = createStreamlinedHandlers(this.server, {
knowledgeService: this.knowledgeService,
codeAnalysisService: this.codeAnalysisService,
methodologyService: this.methodologyService,
workflowService: this.workflowService,
layerService: this.layerService
});
// Execute the appropriate handler
const handler = handlers[name];
if (!handler) {
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
}
return await handler(args);
}
catch (error) {
if (error instanceof McpError) {
throw error;
}
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`);
}
});
}
/**
* Setup prompts for workflow pipelines
*/
setupPrompts() {
console.error('🎯 Setting up MCP Prompts for workflow pipelines...');
// Define workflow prompts that guide users through structured pipelines
const workflowPrompts = [
{
name: 'code_optimization',
description: 'Optimize existing Business Central code using systematic analysis phases',
arguments: [
{
name: 'code_location',
description: 'Path to the code file or description of the code to optimize',
required: false // No more required fields - specialist will ask conversationally
}
]
},
{
name: 'architecture_review',
description: 'Conduct comprehensive architecture review of Business Central solution',
arguments: [
{
name: 'scope',
description: 'Scope of review (module, solution, or specific components)',
required: false // Specialist will ask about scope naturally
}
]
},
{
name: 'security_audit',
description: 'Perform security analysis and compliance check for Business Central implementation',
arguments: [
{
name: 'audit_scope',
description: 'Security audit scope (permissions, data access, API security, etc.)',
required: false // Specialist will gather this in conversation
}
]
},
{
name: 'perf_review',
description: 'Analyze and optimize Business Central performance issues',
arguments: [
{
name: 'performance_concern',
description: 'Description of performance issue or area to analyze',
required: false
}
]
},
{
name: 'integration_design',
description: 'Design robust integration patterns for Business Central',
arguments: [
{
name: 'integration_type',
description: 'Type of integration (API, data sync, external service, etc.)',
required: false
}
]
},
{
name: 'upgrade_planning',
description: 'Plan Business Central version upgrade with risk assessment',
arguments: [
{
name: 'current_version',
description: 'Current Business Central version',
required: false
},
{
name: 'target_version',
description: 'Target Business Central version',
required: false
}
]
},
{
name: 'testing_strategy',
description: 'Develop comprehensive testing strategy for Business Central solutions',
arguments: [
{
name: 'testing_scope',
description: 'Scope of testing (unit, integration, user acceptance, etc.)',
required: false
}
]
},
{
name: 'dev_onboarding',
description: 'Guide new developer through Business Central development onboarding',
arguments: [
{
name: 'experience_level',
description: 'Developer experience level (beginner, intermediate, expert)',
required: false
},
{
name: 'focus_area',
description: 'Primary focus area for onboarding (development, customization, integration)',
required: false
}
]
},
{
name: 'app_takeover',
description: 'Analyze and orient developer taking over an unfamiliar Business Central app',
arguments: [
{
name: 'app_source',
description: 'Source of the app (path, repository, AppSource, or description)',
required: false
},
{
name: 'takeover_context',
description: 'Context for takeover (maintenance, enhancement, migration, or handoff scenario)',
required: false
}
]
},
{
name: 'spec_analysis',
description: 'Analyze requirements and specifications to determine development readiness',
arguments: [
{
name: 'spec_source',
description: 'Source of specifications (document, user story, requirements, or description)',
required: false
},
{
name: 'analysis_focus',
description: 'Analysis focus (completeness, feasibility, technical-gaps, or dependencies)',
required: false
}
]
},
{
name: 'bug_investigation',
description: 'Systematically investigate and resolve Business Central bugs and issues',
arguments: [
{
name: 'bug_context',
description: 'Available context (call-stack, repro-steps, snapshot, sandbox-access, or description)',
required: false
},
{
name: 'issue_severity',
description: 'Issue severity level (critical, high, medium, low)',
required: false
}
]
},
{
name: 'monolith_to_modules',
description: 'Refactor monolithic Business Central code into modular architecture using SOLID principles',
arguments: [
{
name: 'current_structure',
description: 'Current code structure (monolithic-object, large-codeunit, tightly-coupled, or description)',
required: false
},
{
name: 'modularization_goal',
description: 'Modularization goal (dependency-injection, interface-patterns, loose-coupling, or testability)',
required: false
}
]
},
{
name: 'data_flow_tracing',
description: 'Trace data flow and dependencies across Business Central objects and codeunits',
arguments: [
{
name: 'trace_target',
description: 'What to trace (field-usage, table-relationships, posting-flow, or process-chain)',
required: false
},
{
name: 'trace_scope',
description: 'Tracing scope (single-object, module-level, cross-module, or end-to-end)',
required: false
}
]
},
{
name: 'full_review',
description: 'Conduct comprehensive review and analysis without implementation changes',
arguments: [
{
name: 'review_target',
description: 'What to review (code, architecture, documentation, processes)',
required: false
},
{
name: 'review_depth',
description: 'Review depth (surface, detailed, comprehensive)',
required: false
}
]
}
];
// Register prompt list handler
this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
prompts: workflowPrompts.map(p => ({
name: p.name,
description: p.description,
arguments: p.arguments
}))
}));
// Register get prompt handler for all workflows
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const prompt = workflowPrompts.find(p => p.name === name);
if (!prompt) {
throw new McpError(ErrorCode.InvalidRequest, `Unknown prompt: ${name}`);
}
try {
// Convert workflow name to type and create start request
const workflowTypeMap = {
'code_optimization': 'new-bc-app',
'architecture_review': 'enhance-bc-app',
'security_audit': 'debug-bc-issues',
'perf_review': 'debug-bc-issues',
'integration_design': 'add-ecosystem-features',
'upgrade_planning': 'upgrade-bc-version',
'testing_strategy': 'modernize-bc-code',
'dev_onboarding': 'onboard-developer',
'app_takeover': 'enhance-bc-app',
'spec_analysis': 'review-bc-code',
'bug_investigation': 'debug-bc-issues',
'monolith_to_modules': 'modernize-bc-code',
'data_flow_tracing': 'review-bc-code',
'full_review': 'review-bc-code'
};
const workflowType = workflowTypeMap[name];
if (!workflowType) {
throw new Error(`Unknown workflow type: ${name}`);
}
const startRequest = {
workflow_type: workflowType,
project_context: args?.code_location || args?.scope || args?.audit_scope ||
args?.performance_concern || args?.integration_type ||
args?.testing_scope || args?.review_target ||
'General workflow request',
bc_version: args?.target_version || args?.current_version,
additional_context: args
};
// Start the workflow session
const session = await this.workflowService.startWorkflow(startRequest);
// Get the initial guidance for this workflow
const initialGuidance = await this.workflowService.getPhaseGuidance(session.id);
// Enhance with specialist routing
const userContext = args?.code_location || args?.scope || args?.audit_scope ||
args?.performance_concern || args?.integration_type ||
args?.testing_scope || args?.review_target ||
'General workflow request';
const enhancedResult = await this.enhancedPromptService.enhanceWorkflowPrompt(name, userContext, initialGuidance);
// Construct explicit prompt that bypasses VS Code prompt creation
const promptContent = `# ${prompt.description}
**IMPORTANT: This is a complete, ready-to-use prompt. Do not create additional prompts or ask for more information. Proceed directly with the requested workflow.**
${enhancedResult.enhancedContent}
## 🎯 Next Actions
**Use these MCP tools immediately to proceed:**
${enhancedResult.routingOptions.map(option => `- ${option.replace('🎯 Start session with', '**Use MCP tool:**')}`).join('\n')}
**Remember:** You have access to 20+ MCP tools from bc-code-intelligence-mcp. Use them actively for specialist consultation and knowledge access.`;
return {
description: `Starting ${workflowType} workflow with specialist guidance`,
messages: [
{
role: 'user',
content: {
type: 'text',
text: promptContent
}
}
]
};
}
catch (error) {
throw new McpError(ErrorCode.InternalError, `Failed to start workflow: ${error instanceof Error ? error.message : String(error)}`);
}
});
console.error('✅ MCP Prompts configured for workflow orchestration');
}
/**
* Initialize all services with configuration
*/
async initializeServices(configResult) {
// Store configuration
this.configuration = configResult.config;
// Initialize layer service with configuration
this.layerService = new MultiContentLayerService();
let totalTopics = 0;
// Initialize legacy knowledge service for backward compatibility
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const legacyConfig = {
knowledge_base_path: process.env['BCKB_KB_PATH'] || join(__dirname, '../embedded-knowledge'),
indexes_path: process.env['BCKB_INDEXES_PATH'] || join(__dirname, '../embedded-knowledge/indexes'),
methodologies_path: process.env['BCKB_METHODOLOGIES_PATH'] || join(__dirname, '../embedded-knowledge/methodologies'),
cache_size: this.configuration.cache.max_size_mb * 1024, // Convert MB to entries approximation
max_search_results: 20,
default_bc_version: 'BC22',
enable_fuzzy_search: true,
search_threshold: 0.6
};
// Initialize specialist services using a dedicated MultiContentLayerService FIRST
this.layerService = new MultiContentLayerService();
// Iterate over configured layers and instantiate each based on type
for (const layerConfig of this.configuration.layers) {
if (!layerConfig.enabled) {
console.error(`⏭️ Skipping disabled layer: ${layerConfig.name}`);
continue;
}
let layer;
try {
switch (layerConfig.source.type) {
case LayerSourceType.EMBEDDED: {
// Embedded layer - ALWAYS use the server's embedded knowledge directory
// The 'path' field is ignored for embedded layers since they reference the built-in knowledge
const embeddedPath = join(__dirname, '../embedded-knowledge');
console.error(`📋 Embedded layer using built-in knowledge: ${embeddedPath}`);
const { EmbeddedKnowledgeLayer } = await import('./layers/embedded-layer.js');
layer = new EmbeddedKnowledgeLayer(embeddedPath);
break;
}
case LayerSourceType.LOCAL: {
// Local filesystem layer - use ProjectKnowledgeLayer
const { ProjectKnowledgeLayer } = await import('./layers/project-layer.js');
layer = new ProjectKnowledgeLayer(layerConfig.source.path);
// Override name and priority from config
layer.name = layerConfig.name;
layer.priority = layerConfig.priority;
break;
}
case LayerSourceType.GIT: {
// Git repository layer
const { GitKnowledgeLayer } = await import('./layers/git-layer.js');
const gitSource = layerConfig.source; // GitLayerSource
layer = new GitKnowledgeLayer(layerConfig.name, layerConfig.priority, {
type: LayerSourceType.GIT,
url: gitSource.url,
branch: gitSource.branch,
subpath: gitSource.subpath
}, layerConfig.auth);
break;
}
case LayerSourceType.HTTP:
case LayerSourceType.NPM: {
// Future layer types - not yet implemented
// HTTP: Would load knowledge from HTTP endpoints (ZIP/tarball downloads)
// NPM: Would load knowledge from NPM packages
console.warn(`⚠️ Layer type '${layerConfig.source.type}' not yet implemented - skipping ${layerConfig.name}`);
continue;
}
default:
console.error(`❌ Unknown layer type: ${layerConfig.source.type} - skipping ${layerConfig.name}`);
continue;
}
console.error(`📋 Successfully instantiated layer: ${layerConfig.name}`);
this.layerService.addLayer(layer);
}
catch (layerError) {
// CRITICAL FIX: Handle individual layer instantiation failures gracefully
// This prevents one failing layer (e.g. git auth issues) from breaking the entire service
console.error(`❌ Failed to instantiate layer '${layerConfig.name}': ${layerError instanceof Error ? layerError.message : String(layerError)}`);
if (layerConfig.source.type === LayerSourceType.GIT) {
console.error(`💡 Git layer '${layerConfig.name}' failed - check repository URL, authentication, or network connection`);
}
else if (layerConfig.source.type === LayerSourceType.LOCAL) {
console.error(`💡 Local layer '${layerConfig.name}' failed - check that path '${layerConfig.source.path}' exists and is readable`);
}
// Continue to next layer instead of aborting entire initialization
continue;
}
}
await this.layerService.initialize();
// Now create KnowledgeService with the initialized layerService
this.knowledgeService = new KnowledgeService(legacyConfig, this.layerService);
await this.knowledgeService.initialize();
this.codeAnalysisService = new CodeAnalysisService(this.knowledgeService);
this.methodologyService = new MethodologyService(this.knowledgeService, legacyConfig.methodologies_path);
// Report layer-by-layer counts after initialization
const layerStats = this.layerService.getStatistics();
for (const stats of layerStats) {
console.error(`📁 Layer '${stats.name}': ${stats.topicCount} topics`);
totalTopics += stats.topicCount;
}
// Get session storage configuration from layer service
const sessionStorageConfig = this.layerService.getSessionStorageConfig();
this.specialistSessionManager = new SpecialistSessionManager(this.layerService, sessionStorageConfig);
this.specialistTools = new SpecialistTools(this.layerService, this.specialistSessionManager, this.knowledgeService);
// Initialize specialist discovery service and tools
this.specialistDiscoveryService = new SpecialistDiscoveryService(this.layerService);
this.specialistDiscoveryTools = new SpecialistDiscoveryTools(this.specialistDiscoveryService, this.specialistSessionManager, this.layerService);
// Initialize enhanced prompt service for specialist routing
this.enhancedPromptService = new EnhancedPromptService(this.specialistDiscoveryService, this.specialistSessionManager, this.workflowService);
// Initialize agent onboarding tools for natural specialist introduction
this.agentOnboardingTools = new AgentOnboardingTools(this.specialistDiscoveryService, this.layerService);
// Initialize specialist handoff tools for seamless transitions
this.specialistHandoffTools = new SpecialistHandoffTools(this.specialistSessionManager, this.specialistDiscoveryService, this.layerService);
// Initialize configuration diagnostic tools ONLY if enabled (reduces token overhead)
if (this.configuration.developer.enable_diagnostic_tools) {
this.configDiagnosticTools = new ConfigDiagnosticTools(this.layerService, this.configLoader);
console.error('🔧 Configuration diagnostic tools enabled');
}
else {
console.error('💡 Tip: Set developer.enable_diagnostic_tools=true for git layer diagnostics');
}
// Initialize workflow service with specialist discovery
const specialistDiscoveryService = new SpecialistDiscoveryService(this.layerService);
this.workflowService = new WorkflowService(this.knowledgeService, this.methodologyService, specialistDiscoveryService);
// Report final totals
const specialists = await this.layerService.getAllSpecialists();
console.error(`📊 Total: ${totalTopics} topics, ${specialists.length} specialists`);
// Validate tool contracts at startup
await this.validateToolContracts();
}
/**
* Validate that all tool schemas match service implementations
*/
async validateToolContracts() {
try {
const handlers = createStreamlinedHandlers(this.server, {
knowledgeService: this.knowledgeService,
codeAnalysisService: this.codeAnalysisService,
methodologyService: this.methodologyService,
workflowService: this.workflowService,
layerService: this.layerService
});
const tools = getAllToolDefinitions({
specialistTools: this.specialistTools,
specialistDiscoveryTools: this.specialistDiscoveryTools,
onboardingTools: this.agentOnboardingTools,
handoffTools: this.specialistHandoffTools
});
let hasIssues = false;
for (const tool of tools) {
// Only validate core streamlined tools (others handle their own routing)
if (Object.values(STREAMLINED_TOOL_NAMES).includes(tool.name)) {
if (!handlers[tool.name]) {
console.error(`❌ No handler found for core tool: ${tool.name}`);
hasIssues = true;
}
}
}
if (hasIssues) {
console.error('💥 Contract validation failed! Server may have dead ends.');
// Don't fail startup, but warn loudly
}
}
catch (error) {
console.error(`⚠️ Contract validation error: ${error}`);
// Don't fail startup for validation errors
}
}
/**
* Generate comprehensive system analytics
*/
async generateSystemAnalytics(includeTopicAnalytics, includeLayerPerformance, includeConfigurationInsights) {
const analytics = {
timestamp: new Date().toISOString(),
system_overview: {
server_version: this.getPackageVersion(),
layers_active: this.layerService?.getLayers().length || 0,
configuration_loaded: !!this.configuration,
total_topics: this.layerService?.getAllTopicIds().length || 0
}
};
if (includeTopicAnalytics && this.layerService) {
analytics.topic_analytics = await this.generateTopicAnalytics();
}
if (includeLayerPerformance && this.layerService) {
analytics.layer_performance = this.generateLayerPerformanceAnalytics();
}
if (includeConfigurationInsights && this.configuration) {
analytics.configuration_insights = await this.generateConfigurationInsights();
}
return analytics;
}
/**
* Generate topic distribution and coverage analytics
*/
async generateTopicAnalytics() {
const allTopicIds = this.layerService.getAllTopicIds();
const domainDistribution = {};
const difficultyDistribution = {};
const overrideStats = this.layerService.getOverriddenTopics();
// Analyze a sample of topics for domain/difficulty distribution
const sampleSize = Math.min(50, allTopicIds.length);
const sampleTopics = allTopicIds.slice(0, sampleSize);
for (const topicId of sampleTopics) {
const resolution = await this.layerService.resolveTopic(topicId);
if (resolution) {
const domains = getDomainList(resolution.topic.frontmatter.domain);
const difficulty = resolution.topic.frontmatter.difficulty;
// Count each domain the topic belongs to
for (const domain of domains) {
domainDistribution[domain] = (domainDistribution[domain] || 0) + 1;
}
if (difficulty) {
difficultyDistribution[difficulty] = (difficultyDistribution[difficulty] || 0) + 1;
}
}
}
return {
total_topics: allTopicIds.length,
analyzed_sample: sampleSize,
domain_distribution: domainDistribution,
difficulty_distribution: difficultyDistribution,
override_statistics: {
total_overrides: Object.keys(overrideStats).length,
override_percentage: allTopicIds.length > 0
? ((Object.keys(overrideStats).length / allTopicIds.length) * 100).toFixed(1) + '%'
: '0%'
},
coverage_insights: {
domains_covered: Object.keys(domainDistribution).length,
difficulty_levels: Object.keys(difficultyDistribution).length,
most_common_domain: Object.entries(domainDistribution).sort(([, a], [, b]) => b - a)[0]?.[0] || 'N/A',
most_common_difficulty: Object.entries(difficultyDistribution).sort(([, a], [, b]) => b - a)[0]?.[0] || 'N/A'
}
};
}
/**
* Generate layer performance analytics
*/
generateLayerPerformanceAnalytics() {
const layerStats = this.layerService.getLayerStatistics();
const layerMetrics = this.layerService.getStatistics();
const formattedMetrics = layerMetrics.map(stats => {
return {
name: stats.name,
priority: stats.priority,
enabled: stats.enabled,
topic_count: stats.topicCount,
index_count: stats.indexCount,
memory_usage_mb: stats.memoryUsage?.total ? (stats.memoryUsage.total / (1024 * 1024)).toFixed(2) : 'N/A',
load_time_ms: stats.loadTimeMs || 0,
type: 'MultiContentLayer'
};
});
const totalTopics = layerMetrics.reduce((sum, stats) => sum + stats.topicCount, 0);
return {
system_totals: {
total_layers: layerMetrics.length,
total_topics: totalTopics,
total_indexes: layerMetrics.reduce((sum, stats) => sum + stats.indexCount, 0),
total_memory_mb: 'N/A' // Memory tracking not implemented in new system
},
layer_metrics: formattedMetrics,
performance_insights: {
fastest_layer: formattedMetrics.sort((a, b) => a.load_time_ms - b.load_time_ms)[0]?.name || 'N/A',
most_topics: formattedMetrics.sort((a, b) => b.topic_count - a.topic_count)[0]?.name || 'N/A',
layer_efficiency: layerMetrics.length > 0
? (totalTopics / layerMetrics.length).toFixed(1) + ' topics/layer avg'
: 'N/A'
}
};
}
/**
* Generate configuration optimization insights
*/
async generateConfigurationInsights() {
const validator = new ConfigurationValidator();
const validation = await validator.validate(this.configuration);
const insights = {
configuration_quality: {
overall_score: validation.score,
is_valid: validation.valid,
error_count: validation.errors.length,
warning_count: validation.warnings.length
},
layer_configuration: {
total_layers: this.configuration.layers.length,
enabled_layers: this.configuration.layers.filter(l => l.enabled).length,
layer_types: this.configuration.layers.reduce((acc, layer) => {
acc[layer.source.type] = (acc[layer.source.type] || 0) + 1;
return acc;
}, {}),
priority_distribution: this.configuration.layers.map(l => l.priority).sort((a, b) => a - b)
},
optimization_recommendations: []
};
// Generate optimization recommendations
if (this.configuration.layers.filter(l => l.enabled).length < 2) {
insights.optimization_recommendations.push({
type: 'layer_diversity',
message: 'Consider adding more layer types (git, local overrides) for better customization',
impact: 'medium'
});
}
if (this.configuration.performance.max_concurrent_loads < 3) {
insights.optimization_recommendations.push({
type: 'performance',
message: 'Increase max_concurrent_loads for better performance on modern systems',
impact: 'low'
});
}
if (!this.configuration.security.validate_sources) {
insights.optimization_recommendations.push({
type: 'security',
message: 'Enable source validation for better security',
impact: 'high'
});
}
if (validation.warnings.length > 0) {
insights.optimization_recommendations.push({
type: 'configuration',
message: `Address ${validation.warnings.length} configuration warnings`,
impact: 'medium'
});
}
return insights;
}
async generateOptimizationWorkflow(params) {
// Use domain workflows for comprehensive scenario coverage
const baseWorkflows = domainWorkflows;
// Additional legacy workflow mapping
const legacyWorkflows = {
'slow report': {
steps: [
{
step_number: 1,
title: 'Analyze Current Data Access Patterns',
description: 'Review report dataset access, joins, and aggregations to identify bottlenecks',
related_topics: ['query-performance-patterns', 'sift-technology-fundamentals'],
validation_criteria: ['Query execution times documented', 'Data volume assessed'],
estimated_time: '30 minutes'
},
{
step_number: 2,
title: 'Implement SIFT Indexes',
description: 'Add SIFT indexes for aggregation operations and enable MaintainSIFTIndex',
related_topics: ['sift-index-fundamentals', 'maintainsiftindex-property-behavior'],
validation_criteria: ['SIFT keys created', 'MaintainSIFTIndex enabled', 'Aggregations use CalcSums'],
estimated_time: '45 minutes'
},
{
step_number: 3,
title: 'Optimize Field Loading',
description: 'Use SetLoadFields to reduce memory usage and network traffic',
related_topics: ['setloadfields-optimization', 'memory-optimization'],
validation_criteria: ['SetLoadFields implemented', 'Only required fields loaded'],
estimated_time: '20 minutes'
},
{
step_number: 4,
title: 'Performance Testing and Validation',
description: 'Measure performance improvements and validate against targets',
related_topics: ['performance-monitoring', 'performance-best-practices'],
validation_criteria: ['Performance metrics collected', 'Target response time achieved'],
estimated_time: '30 minutes'
}
],
learning_path: ['sift-technology-fundamentals', 'query-performance-patterns', 'performance-monitoring'],
success_metrics: ['Report execution time reduced by 70%+', 'Memory usage optimized', 'User satisfaction improved'],
common_pitfalls: ['Not enabling MaintainSIFTIndex', 'Loading unnecessary fields', 'Missing performance baselines']
}
};
// Merge domain workflows with legacy workflows
const allWorkflows = { ...baseWorkflows, ...legacyWorkflows };
// Find matching workflow or create generic one
const scenario = params.scenario.toLowerCase();
let workflow = null;
for (const [key, value] of Object.entries(allWorkflows)) {
if (scenario.includes(key)) {
workflow = value;
break;
}
}
if (!workflow) {
// Generate generic optimization workflow
workflow = {
steps: [
{
step_number: 1,
title: 'Identify Performance Bottlenecks',
description: 'Analyze the scenario to pinpoint specific performance issues',
related_topics: ['performance-monitoring', 'query-performance-patterns'],
validation_criteria: ['Bottlenecks identified', 'Performance baseline established'],
estimated_time: '30 minutes'
},
{
step_number: 2,
title: 'Apply Targeted Optimizations',
description: 'Implement specific BC optimization patterns based on identified issues',
related_topics: ['performance-best-practices', 'memory-optimization'],
validation_criteria: ['Optimizations implemented', 'Code patterns improved'],
estimated_time: '60 minutes'
},
{
step_number: 3,
title: 'Validate and Monitor',
description: 'Test improvements and establish ongoing monitoring',
related_topics: ['performance-monitoring'],
validation_criteria: ['Performance improved', 'Monitoring established'],
estimated_time: '20 minutes'
}
],
learning_path: ['performance-best-practices', 'performance-monitoring'],
success_metrics: ['Measurable performance improvement', 'Sustainable solution implemented'],
common_pitfalls: ['Premature optimization', 'Insufficient testing', 'Missing monitoring']
};
}
return {
scenario: params.scenario,
workflow,
constraints: params.constraints || [],
target_performance: params.target_performance
};
}
async run() {
try {
// Ultra-early diagnostics for platform issues
console.error('=== BC Code Intelligence MCP Server Startup Diagnostics ===');
console.error(`Platform: ${process.platform}`);
console.error(`Node version: ${process.version}`);
console.error(`Architecture: ${process.arch}`);
console.error(`Working directory: ${process.cwd()}`);
console.error(`Script path: ${process.argv[1]}`);
const version = this.getPackageVersion();
console.error(`🚀 BC Code Intelligence MCP Server v${version} starting...`);
// Verify embedded knowledge path BEFORE any service initialization
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const embeddedPath = join(__dirname, '..', 'embedded-knowledge');
console.error(`Embedded knowledge path: ${embeddedPath}`);
console.error(`Embedded knowledge exists: ${existsSync(embeddedPath)}`);
if (existsSync(embeddedPath)) {
const expectedDirs = ['domains', 'specialists', 'methodologies'];
for (const dir of expectedDirs) {
const dirPath = join(embeddedPath, dir);
console.error(` ${dir}/: ${existsSync(dirPath)}`);
}
}
// Try to load user-level configuration first (company layers)
// If no user config exists, fall back to embedded-only mode
console.error('📦 Checking for user-level configuration (company layers)...');
try {
const userConfigResult = await this.configLoader.loadConfiguration();
if (userConfigResult.config.layers && userConfigResult.config.layers.length > 1) {
// User has configured layers (embedded + company/git layers)
console.error(`✅ Found user-level configuration with ${userConfigResult.config.layers.length} layers`);
this.configuration = userConfigResult.config;
try {
await this.initializeWithConfiguration(userConfigResult);
}
catch (configError) {
// CRITICAL FIX: If user config initialization fails (e.g. git layer auth failure),
// fall back to embedded-only mode instead of crashing the server
console.error('❌ Failed to initialize with user configuration:', configError instanceof Error ? configError.message : String(configError));
console.error('🔄 Falling back to embedded-only mode...');
await this.initializeEmbeddedOnly();
}
}
else {
// No user config or only embedded layer - use embedded-only mode
console.error('📦 No user-level configuration found, loading embedded knowledge only...');
await this.initializeEmbeddedOnly();
}
}
catch (error)