mcp-adr-analysis-server
Version:
MCP server for analyzing Architectural Decision Records and project architecture
295 lines • 9.79 kB
TypeScript
/**
* Research Orchestrator
*
* Coordinates multi-source research with cascading fallback:
* 1. Project Files (local, fast, free)
* 2. Knowledge Graph (in-memory, instant)
* 3. Environment Resources (live runtime data)
* 4. Web Search (external, last resort)
*/
import { type ResearchPlan, type ResearchTaskTracker, type CreateResearchTaskOptions } from './research-task-integration.js';
export interface ResearchSource {
type: 'project_files' | 'knowledge_graph' | 'environment' | 'web_search';
found?: boolean;
data: any;
confidence: number;
timestamp: string;
}
export interface ResearchAnswer {
question: string;
sources: ResearchSource[];
confidence: number;
needsWebSearch: boolean;
answer?: string;
metadata: {
duration: number;
sourcesQueried: string[];
filesAnalyzed: number;
cached?: boolean;
};
}
/**
* Research Orchestrator Class
*
* @deprecated This class is deprecated as of v2.2.0 and will be removed in v4.0.0.
* Use atomic tools instead per ADR-018 (Atomic Tools Architecture):
* - For codebase search: Use `searchCodebase` from `tools/search-codebase-tool.ts`
* - For external research: Use `llm-web-search-tool.ts` (if needed)
*
* **Deprecation Rationale** (see ADR-018):
* - Sequential execution blocking (2-8 seconds per call)
* - 5,000-6,000 tokens overhead per session
* - Causes 37+ test timeout failures due to complex ESM mocking
* - 850+ second test suite execution time
* - Conflicts with CE-MCP directive-based architecture (ADR-014)
*
* **Migration Guide**:
* ```typescript
* // OLD: Using ResearchOrchestrator
* const orchestrator = new ResearchOrchestrator('/path/to/project', 'docs/adrs');
* const result = await orchestrator.answerResearchQuestion('Docker configuration');
*
* // NEW: Using atomic searchCodebase tool
* import { searchCodebase } from './tools/search-codebase-tool.js';
* const result = await searchCodebase({
* query: 'Docker configuration',
* projectPath: '/path/to/project'
* });
* ```
*
* @description Coordinates multi-source research with cascading fallback strategy.
* Implements a hierarchical approach to answering research questions by querying
* sources in order of preference: project files → knowledge graph → environment → web search.
*
* Features:
* - Intelligent confidence scoring for each source
* - Configurable confidence thresholds
* - Result caching for performance optimization
* - Firecrawl integration for web search capabilities
* - Comprehensive error handling and fallback mechanisms
*
* @example
* ```typescript
* const orchestrator = new ResearchOrchestrator('/path/to/project', 'docs/adrs');
* orchestrator.setConfidenceThreshold(0.8);
*
* const result = await orchestrator.answerResearchQuestion(
* 'What authentication methods are used in this project?'
* );
*
* console.log(`Answer: ${result.answer}`);
* console.log(`Confidence: ${result.confidence}`);
* console.log(`Sources: ${result.sources.map(s => s.type).join(', ')}`);
* ```
*
* @since 2.0.0
* @category Research
* @category Orchestration
*/
export declare class ResearchOrchestrator {
private logger;
private projectPath;
private adrDirectory;
private confidenceThreshold;
private kgManager;
private cache;
private cacheTtl;
private firecrawl;
private config;
constructor(projectPath?: string, adrDirectory?: string);
/**
* Answer a research question using cascading source hierarchy
*
* @deprecated Use atomic searchCodebase() tool instead. See class-level @deprecated tag for details.
*
* @description Executes comprehensive research using a cascading approach:
* 1. Project files search (fastest, most relevant)
* 2. Knowledge graph query (instant, context-aware)
* 3. Environment resources query (live data)
* 4. Web search fallback (external, when confidence is low)
*
* Results are cached for 5 minutes to improve performance for repeated queries.
*
* @param {string} question - The research question to investigate
*
* @returns {Promise<ResearchAnswer>} Comprehensive research results with:
* - `answer`: Synthesized answer from all sources
* - `confidence`: Overall confidence score (0-1)
* - `sources`: Array of source results with individual confidence scores
* - `needsWebSearch`: Whether web search is recommended
* - `metadata`: Execution metadata (duration, files analyzed, etc.)
*
* @throws {Error} When question is empty or research orchestration fails
*
* @example
* ```typescript
* const result = await orchestrator.answerResearchQuestion(
* 'How does authentication work in this project?'
* );
*
* if (result.confidence >= 0.8) {
* console.log('High confidence answer:', result.answer);
* } else if (result.needsWebSearch) {
* console.log('Consider web search for more information');
* }
*
* result.sources.forEach(source => {
* console.log(`${source.type}: ${(source.confidence * 100).toFixed(1)}%`);
* });
* ```
*
* @since 2.0.0
* @category Research
* @category Public API
*/
answerResearchQuestion(question: string): Promise<ResearchAnswer>;
/**
* SOURCE 1: Search project files (Enhanced with tree-sitter and file ops)
*/
private searchProjectFiles;
/**
* Check if file should be parsed with tree-sitter
*/
private shouldParse;
/**
* SOURCE 2: Query knowledge graph
*/
private queryKnowledgeGraph;
/**
* SOURCE 3: Query environment resources
*/
private queryEnvironment;
/**
* Calculate confidence score from multiple sources
*/
private calculateConfidence;
/**
* Synthesize answer from multiple sources
*/
private synthesizeAnswer;
/**
* Calculate relevance score for content (legacy method - kept for compatibility)
*/
private calculateRelevanceLegacy;
/**
* Extract keywords from question
*/
private extractKeywords;
/**
* Set confidence threshold for web search fallback
*/
setConfidenceThreshold(threshold: number): void;
/**
* SOURCE 4: Perform web search using Firecrawl (LLM-managed)
*/
private performWebSearch;
/**
* Search using Firecrawl with LLM-driven query optimization
*/
private searchWithFirecrawl;
/**
* Generate fallback search results when Firecrawl is not available
*/
private generateFallbackSearchResults;
/**
* Generate search URLs using LLM
*/
private generateSearchUrls;
/**
* Calculate relevance score using LLM
*/
private calculateRelevance;
/**
* Generate search queries based on research question
*/
private generateSearchQueries;
/**
* Generate cache key for research question
*/
private generateCacheKey;
/**
* Get cached result if available and not expired
*/
private getCachedResult;
/**
* Cache a research result
*/
private setCachedResult;
/**
* Clear expired cache entries
*/
cleanupCache(): void;
/**
* Clear all cache entries
*/
clearCache(): void;
/**
* Get cache statistics
*/
getCacheStats(): {
size: number;
entries: Array<{
key: string;
age: number;
expires: number;
}>;
};
/**
* Create a research plan for LLM delegation (non-blocking)
*
* This is the recommended method for new code. Instead of executing research
* internally (which blocks for 2-8 seconds), this returns a research plan
* that the calling LLM should execute using atomic tools.
*
* Benefits:
* - Non-blocking: Returns immediately with a plan
* - LLM-controlled: The calling LLM decides execution order
* - MCP Tasks: Integrated with MCP Tasks for progress tracking
* - Cancellable: Can be cancelled between phases
*
* @param question - The research question to investigate
* @param options - Optional configuration
* @returns Task ID, research plan, and tracker for progress updates
*
* @example
* ```typescript
* const orchestrator = new ResearchOrchestrator('/path/to/project');
* const { taskId, plan, tracker } = await orchestrator.createResearchPlan(
* 'How does authentication work in this codebase?'
* );
*
* // LLM receives the plan and executes each phase:
* for (const phase of plan.phases) {
* await tracker.startPhase(phase.phase);
* const result = await executeToolCall(phase.tool, phase.params);
* await tracker.storeResult(phase.phase, result);
* await tracker.completePhase(phase.phase);
* }
*
* // Finally, synthesize and complete
* const answer = synthesize(results);
* await tracker.storeSynthesizedAnswer(answer, confidence);
* await tracker.complete({ success: true, data: { answer, confidence } });
* ```
*
* @since 3.1.0
*/
createResearchPlan(question: string, options?: {
includeWebSearch?: boolean;
confidenceThreshold?: number;
}): Promise<{
taskId: string;
plan: ResearchPlan;
tracker: ResearchTaskTracker;
}>;
/**
* Get the project path used by this orchestrator
*/
getProjectPath(): string;
/**
* Get the ADR directory used by this orchestrator
*/
getAdrDirectory(): string;
}
export type { ResearchPlan, ResearchTaskTracker, CreateResearchTaskOptions };
//# sourceMappingURL=research-orchestrator.d.ts.map