UNPKG

ultimate-mcp-server

Version:

The definitive all-in-one Model Context Protocol server for AI-assisted coding across 30+ platforms

477 lines 18.4 kB
/** * Autonomous Exploration Tools * MCP tools for self-guided codebase exploration and task execution */ import { z } from 'zod'; import { ExplorationEngine } from '../autonomous/exploration-engine.js'; import { Logger } from '../utils/logger.js'; const logger = new Logger('AutonomousTools'); // Global exploration engine instance let explorationEngine = null; // Initialize exploration engine function getExplorationEngine() { if (!explorationEngine) { explorationEngine = new ExplorationEngine(); } return explorationEngine; } // Tool definitions export const exploreCodebase = { name: 'auto_explore_codebase', description: 'Autonomously explore and understand a codebase structure', inputSchema: z.object({ rootPath: z.string().describe('Root directory path to explore'), focusAreas: z.array(z.string()).optional() .describe('Specific areas to focus on'), maxFiles: z.number().optional().default(100) .describe('Maximum files to analyze'), timeLimit: z.number().optional().default(60000) .describe('Time limit in milliseconds') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); // Create exploration task const task = { id: generateId(), type: 'explore_codebase', description: `Explore codebase at ${args.rootPath}`, parameters: { rootPath: args.rootPath }, constraints: { maxFiles: args.maxFiles, timeLimit: args.timeLimit, focusAreas: args.focusAreas }, status: 'exploring' }; // Execute exploration const result = await engine.executeTask(task); return { success: result.success, summary: result.summary, keyFindings: result.keyFindings, recommendations: result.recommendations, statistics: { filesExplored: result.workingMemory.visitedFiles.size, insightsGenerated: result.workingMemory.keyInsights.length, decisionsMode: result.workingMemory.decisions.length, languages: Object.keys(result.workingMemory.projectStructure.languages), duration: `${result.duration}ms` }, projectInfo: { totalFiles: result.workingMemory.projectStructure.fileCount, totalSize: `${Math.round(result.workingMemory.projectStructure.totalSize / 1024)} KB`, patterns: result.workingMemory.projectStructure.patterns.map(p => p.name) } }; } }; export const findImplementation = { name: 'auto_find_implementation', description: 'Autonomously find and understand a specific implementation', inputSchema: z.object({ rootPath: z.string().describe('Root directory to search in'), target: z.string().describe('What to find (function, class, feature, etc.)'), includeUsage: z.boolean().optional().default(true) .describe('Also find where it is used') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); const task = { id: generateId(), type: 'find_implementation', description: `Find implementation of ${args.target}`, parameters: { rootPath: args.rootPath, target: args.target, includeUsage: args.includeUsage }, status: 'exploring' }; const result = await engine.executeTask(task); // Extract implementation-specific findings const implementations = result.workingMemory.keyInsights .filter(i => i.description.toLowerCase().includes(args.target.toLowerCase())) .map(i => ({ file: i.filePath || 'unknown', description: i.description, relevance: i.relevance })); return { found: implementations.length > 0, target: args.target, implementations, summary: result.summary, recommendations: result.recommendations, explorationPath: result.workingMemory.navigationHistory .slice(0, 10) .map(step => ({ action: step.action, target: step.target, findings: step.findings?.slice(0, 3) })) }; } }; export const analyzeArchitecture = { name: 'auto_analyze_architecture', description: 'Autonomously analyze and understand project architecture', inputSchema: z.object({ rootPath: z.string().describe('Root directory of the project'), depth: z.enum(['shallow', 'medium', 'deep']).optional().default('medium') .describe('Analysis depth') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); const depthConfig = { shallow: { maxFiles: 50, timeLimit: 30000 }, medium: { maxFiles: 150, timeLimit: 90000 }, deep: { maxFiles: 500, timeLimit: 300000 } }; const config = depthConfig[args.depth]; const task = { id: generateId(), type: 'analyze_architecture', description: 'Analyze project architecture and patterns', parameters: { rootPath: args.rootPath }, constraints: config, status: 'exploring' }; const result = await engine.executeTask(task); // Extract architecture insights const architectureInsights = result.workingMemory.keyInsights .filter(i => i.type === 'architecture' || i.type === 'pattern') .map(i => i.description); const patterns = result.workingMemory.projectStructure.patterns; return { architecture: { patterns: patterns.map(p => ({ name: p.name, type: p.type, confidence: `${Math.round(p.confidence * 100)}%`, implications: p.implications })), insights: architectureInsights, languages: result.workingMemory.projectStructure.languages, entryPoints: result.workingMemory.keyInsights .filter(i => i.type === 'entry-point') .map(i => i.filePath || i.description) }, recommendations: result.recommendations, statistics: { totalFiles: result.workingMemory.projectStructure.fileCount, analyzedFiles: result.workingMemory.visitedFiles.size, depth: args.depth, duration: `${result.duration}ms` } }; } }; export const navigateAutonomously = { name: 'auto_navigate', description: 'Navigate to a specific target with autonomous reasoning', inputSchema: z.object({ target: z.string().describe('Where to navigate (file, directory, symbol)'), reason: z.string().describe('Why navigating there'), followUp: z.boolean().optional().default(true) .describe('Suggest follow-up actions') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); const step = await engine.navigateTo(args.target, args.reason); return { navigation: { action: step.action, target: step.target, reason: step.reason, timestamp: step.timestamp }, findings: step.findings || [], nextSteps: args.followUp ? step.nextSteps || [] : [], workingMemory: { visitedFiles: engine.getWorkingMemory().visitedFiles.size, insights: engine.getWorkingMemory().keyInsights.length } }; } }; export const planExploration = { name: 'auto_plan_exploration', description: 'Create an exploration plan for a specific goal', inputSchema: z.object({ goal: z.string().describe('What you want to achieve'), constraints: z.object({ maxSteps: z.number().optional().default(20), timeLimit: z.number().optional(), focusAreas: z.array(z.string()).optional() }).optional() }).strict(), handler: async (args) => { const engine = getExplorationEngine(); const plan = await engine.planNavigation(args.goal); // Apply constraints if (args.constraints?.maxSteps) { plan.steps = plan.steps.slice(0, args.constraints.maxSteps); } return { goal: args.goal, plan: { steps: plan.steps.map(s => ({ order: s.order, action: s.action, target: s.target, purpose: s.purpose, optional: s.optional })), estimatedDuration: `${Math.round(plan.estimatedDuration / 1000)}s`, requiredCapabilities: plan.requiredCapabilities, risks: plan.risks }, constraints: args.constraints }; } }; export const generateInsight = { name: 'auto_generate_insight', description: 'Generate and record an insight from exploration', inputSchema: z.object({ type: z.enum([ 'architecture', 'pattern', 'dependency', 'issue', 'opportunity', 'convention', 'entry-point', 'test-coverage' ]).describe('Type of insight'), description: z.string().describe('Insight description'), filePath: z.string().optional().describe('Related file path') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); const insight = await engine.generateInsight(args.type, args.description, args.filePath); return { insight: { id: insight.id, type: insight.type, description: insight.description, relevance: `${Math.round(insight.relevance * 100)}%`, timestamp: insight.timestamp, filePath: insight.filePath }, totalInsights: engine.getWorkingMemory().keyInsights.length }; } }; export const getExplorationProgress = { name: 'auto_get_progress', description: 'Get current exploration progress and statistics', inputSchema: z.object({}).strict(), handler: async () => { const engine = getExplorationEngine(); const progress = engine.getProgress(); const memory = engine.getWorkingMemory(); return { currentPhase: progress.phase, progress: `${progress.progress}%`, statistics: { filesVisited: memory.visitedFiles.size, totalFiles: memory.projectStructure.fileCount, insights: progress.insights, decisions: memory.decisions.length, navigationSteps: memory.navigationHistory.length }, recentInsights: memory.keyInsights .slice(-5) .map(i => ({ type: i.type, description: i.description, relevance: `${Math.round(i.relevance * 100)}%` })), languages: Object.entries(memory.projectStructure.languages) .map(([lang, count]) => ({ language: lang, files: count })) }; } }; export const makeAutonomousDecision = { name: 'auto_make_decision', description: 'Make an autonomous decision with reasoning', inputSchema: z.object({ question: z.string().describe('Decision question'), options: z.array(z.object({ id: z.string(), label: z.string(), description: z.string(), pros: z.array(z.string()).optional().default([]), cons: z.array(z.string()).optional().default([]) })).describe('Available options') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); // Calculate confidence for each option const optionsWithConfidence = args.options.map((opt) => ({ ...opt, confidence: calculateConfidence(opt.pros.length, opt.cons.length) })); const decision = await engine.makeDecision(args.question, optionsWithConfidence); return { decision: { question: decision.question, selected: decision.selected, rationale: decision.rationale, impact: decision.impact, timestamp: decision.timestamp }, allOptions: args.options.map((opt) => ({ id: opt.id, label: opt.label, selected: opt.id === decision.selected })) }; } }; export const traceDataFlow = { name: 'auto_trace_data_flow', description: 'Trace how data flows through the codebase', inputSchema: z.object({ rootPath: z.string().describe('Root directory'), dataPoint: z.string().describe('Data point to trace (variable, function, etc.)'), maxDepth: z.number().optional().default(5) .describe('Maximum trace depth') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); const task = { id: generateId(), type: 'trace_data_flow', description: `Trace data flow of ${args.dataPoint}`, parameters: { rootPath: args.rootPath, dataPoint: args.dataPoint }, constraints: { maxDepth: args.maxDepth }, status: 'exploring' }; const result = await engine.executeTask(task); // Extract flow-related insights const flowSteps = result.workingMemory.navigationHistory .filter(step => step.action === 'follow_import' || step.action === 'check_references') .map(step => ({ from: step.target, action: step.action, findings: step.findings })); return { dataPoint: args.dataPoint, flowTrace: flowSteps, summary: result.summary, insights: result.keyFindings.filter(f => f.toLowerCase().includes('flow') || f.toLowerCase().includes('dependency')) }; } }; export const suggestImprovements = { name: 'auto_suggest_improvements', description: 'Autonomously analyze code and suggest improvements', inputSchema: z.object({ rootPath: z.string().describe('Root directory'), focusAreas: z.array(z.enum([ 'performance', 'security', 'maintainability', 'testing', 'documentation', 'architecture' ])).optional().describe('Areas to focus on') }).strict(), handler: async (args) => { const engine = getExplorationEngine(); const task = { id: generateId(), type: 'suggest_improvements', description: 'Analyze code and suggest improvements', parameters: { rootPath: args.rootPath, focusAreas: args.focusAreas }, status: 'exploring' }; const result = await engine.executeTask(task); // Categorize recommendations const categorized = {}; for (const rec of result.recommendations) { const category = detectCategory(rec); if (!categorized[category]) { categorized[category] = []; } categorized[category].push(rec); } return { improvements: categorized, issues: result.workingMemory.keyInsights .filter(i => i.type === 'issue') .map(i => ({ description: i.description, file: i.filePath, relevance: `${Math.round(i.relevance * 100)}%` })), summary: result.summary, codebaseHealth: calculateHealth(result) }; } }; // Helper functions function generateId() { return Math.random().toString(36).substring(2) + Date.now().toString(36); } function calculateConfidence(pros, cons) { if (pros + cons === 0) return 0.5; return pros / (pros + cons); } function detectCategory(recommendation) { const lower = recommendation.toLowerCase(); if (lower.includes('test')) return 'testing'; if (lower.includes('type') || lower.includes('typescript')) return 'type-safety'; if (lower.includes('document') || lower.includes('comment')) return 'documentation'; if (lower.includes('security') || lower.includes('vulnerab')) return 'security'; if (lower.includes('performance') || lower.includes('optimize')) return 'performance'; if (lower.includes('structure') || lower.includes('architect')) return 'architecture'; return 'general'; } function calculateHealth(result) { let score = 70; // Base score // Positive factors if (result.workingMemory.keyInsights.some((i) => i.type === 'test-coverage')) { score += 10; } if (result.workingMemory.projectStructure.patterns.some((p) => p.name.includes('TypeScript'))) { score += 5; } // Negative factors const issues = result.workingMemory.keyInsights.filter((i) => i.type === 'issue'); score -= issues.length * 3; // Clamp score score = Math.max(0, Math.min(100, score)); const status = score >= 80 ? 'excellent' : score >= 60 ? 'good' : score >= 40 ? 'fair' : 'needs improvement'; return { score, status }; } // Export all autonomous exploration tools export const autonomousExplorationTools = [ exploreCodebase, findImplementation, analyzeArchitecture, navigateAutonomously, planExploration, generateInsight, getExplorationProgress, makeAutonomousDecision, traceDataFlow, suggestImprovements ]; //# sourceMappingURL=autonomous-exploration-tools.js.map