local_project_hints
Analyze project structure to generate navigation hints with word clouds, folder analysis, and architecture detection for better codebase understanding.
Instructions
π Generate intelligent project navigation hints with word clouds, folder analysis, and architecture detection. Supports multiple output formats including markdown and HTML, with AI-powered analysis and configurable performance options. Accepts absolute paths or relative paths (when workspace can be detected).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectPath | No | Project directory path. Can be absolute (recommended) or relative to workspace. Examples: "C:\Dev\my-project", "/Users/username/project", or "." for current workspace. | |
| format | No | Output format preference - structured for detailed analysis, compact for quick overview, json for raw data, markdown for documentation, html for visual reports | compact |
| maxFiles | No | Maximum number of files to analyze for performance | |
| folderPath | No | Analyze specific folder instead of entire project (optional) | |
| includeContent | No | Include file content analysis for deeper insights (may impact performance) | |
| useAI | No | Enable AI-powered folder analysis for better purpose detection (requires OpenAI API key) | |
| maxFileSizeForSymbols | No | Maximum file size in bytes for symbol extraction (performance tuning) |
Input Schema (JSON Schema)
{
"properties": {
"folderPath": {
"description": "Analyze specific folder instead of entire project (optional)",
"type": "string"
},
"format": {
"default": "compact",
"description": "Output format preference - structured for detailed analysis, compact for quick overview, json for raw data, markdown for documentation, html for visual reports",
"enum": [
"structured",
"compact",
"json",
"markdown",
"html"
],
"type": "string"
},
"includeContent": {
"default": false,
"description": "Include file content analysis for deeper insights (may impact performance)",
"type": "boolean"
},
"maxFileSizeForSymbols": {
"default": 50000,
"description": "Maximum file size in bytes for symbol extraction (performance tuning)",
"maximum": 200000,
"minimum": 10000,
"type": "number"
},
"maxFiles": {
"default": 100,
"description": "Maximum number of files to analyze for performance",
"maximum": 200,
"minimum": 10,
"type": "number"
},
"projectPath": {
"description": "Project directory path. Can be absolute (recommended) or relative to workspace. Examples: \"C:\\Dev\\my-project\", \"/Users/username/project\", or \".\" for current workspace.",
"type": "string"
},
"useAI": {
"default": true,
"description": "Enable AI-powered folder analysis for better purpose detection (requires OpenAI API key)",
"type": "boolean"
}
},
"type": "object"
}
Implementation Reference
- Main handler function that executes the tool logic: validates input, resolves paths, generates project hints using ProjectHintsGenerator, handles different formats (compact, structured, json, markdown, html), folder-specific analysis, file composition analysis, and returns formatted results or errors.export async function handleProjectHints(args: any): Promise<any> { const { projectPath, format = 'compact', maxFiles = 100, folderPath, includeContent = false, useAI = true, maxFileSizeForSymbols = 50000, query, } = args; // Validate that projectPath is provided and is absolute if (!projectPath) { throw new Error( 'β projectPath is required. Please provide an absolute path to the project directory.' ); } const resolvedProjectPath = validateAndResolvePath(projectPath); logger.info('π Generating project hints', { originalPath: projectPath, resolvedPath: resolvedProjectPath, format, maxFiles, folderPath, }); try { const hintsGenerator = new ProjectHintsGenerator(); if (folderPath && folderPath !== '.') { // Folder-specific analysis const folderHints = await hintsGenerator.generateFolderDocumentation( resolvedProjectPath, folderPath, { useAI, maxDepth: 2, includeSubfolders: true, } ); return { success: true, hints: formatFolderHints(folderHints, format), type: 'folder-specific', metadata: { folderPath, keyFiles: folderHints.keyFiles.length, subFolders: folderHints.subFolders.length, confidence: folderHints.confidence, }, }; } else { // Use the core ProjectHintsGenerator which handles embedding-assisted features logger.info('π Generating project hints with core generator', { format, maxFiles, useEmbeddingAssisted: hintsGenerator['shouldUseEmbeddingAssistedHints']?.(), }); const hintsResult = await hintsGenerator.generateProjectHints(resolvedProjectPath, { maxFiles, includeContent, useAI, maxFileSizeForSymbols, format: 'json', // Get raw hints object for processing }); // Type guard to ensure we have the ProjectHints object const hints = hintsResult as ProjectHints; // Handle different output formats let formattedHints: string; logger.info('π¨ Formatting hints', { requestedFormat: format }); if (format === 'html') { // Regenerate with the desired format using the generator's built-in formatting logger.info('π Regenerating with built-in HTML formatting'); formattedHints = (await hintsGenerator.generateProjectHints(resolvedProjectPath, { maxFiles, includeContent, useAI, maxFileSizeForSymbols, format, })) as string; logger.info('β Generated formatted hints', { format, length: formattedHints.length, preview: formattedHints.substring(0, 100) + '...', }); } else if (format === 'structured') { // Use enhanced structured format that includes embedding-assisted features logger.info('π§ Using structured format with potential embedding enhancement'); const fileDiscovery = new FileDiscovery(resolvedProjectPath, { maxFileSize: maxFileSizeForSymbols, }); const allFiles = await fileDiscovery.discoverFiles(); const limitedFiles = fileDiscovery.sortByRelevance(allFiles).slice(0, maxFiles); // Analyze file composition across the project const fileCompositionStructured = analyzeFileComposition(allFiles, limitedFiles); const enhancedSummary = await buildEnhancedProjectSummary( resolvedProjectPath, limitedFiles, query ); // Add answer draft if query provided if (query) { const answerDraft = generateAnswerDraft(enhancedSummary, query); if (answerDraft) { (enhancedSummary as any).answerDraft = answerDraft; } } formattedHints = formatProjectHints(enhancedSummary, format); return { success: true, hints: formattedHints, type: 'enhanced-project-wide', metadata: { filesAnalyzed: enhancedSummary.summary.files, capabilities: enhancedSummary.capabilities.domains, hintsCount: enhancedSummary.hints.length, riskScore: enhancedSummary.risks.score, nextMode: enhancedSummary.next.mode, hasQuery: !!query, enhanced: true, embeddingAssisted: hintsGenerator['shouldUseEmbeddingAssistedHints']?.() || false, fileComposition: fileCompositionStructured, }, }; } else { // Use local formatting for remaining cases logger.info('π Using local formatting for', { format }); formattedHints = formatProjectHints(hints, format); } // Analyze file composition for metadata const fileDiscoveryForComposition = new FileDiscovery(resolvedProjectPath, { maxFileSize: maxFileSizeForSymbols, }); const allFilesForComposition = await fileDiscoveryForComposition.discoverFiles(); const limitedFilesForComposition = fileDiscoveryForComposition .sortByRelevance(allFilesForComposition) .slice(0, maxFiles); const fileComposition = analyzeFileComposition( allFilesForComposition, limitedFilesForComposition ); return { success: true, hints: formattedHints, type: 'project-wide', metadata: { filesAnalyzed: hints.totalFiles, foldersFound: Object.keys(hints.folderHints).length, primaryLanguages: hints.primaryLanguages, architecturePatterns: hints.architectureKeywords, topFunctions: hints.symbolHints.functions.slice(0, 10).map((f: any) => f.word), codebaseSize: hints.codebaseSize, enhanced: false, embeddingAssisted: hintsGenerator['shouldUseEmbeddingAssistedHints']?.() || false, fileComposition, }, }; } } catch (error) { logger.error('β Project hints generation failed', { error: error instanceof Error ? error.message : String(error), }); return { success: false, error: error instanceof Error ? error.message : String(error), fallback: `Could not analyze project structure for ${projectPath}. Ensure the path exists and contains supported code files.`, }; } }
- Tool definition including inputSchema with parameters for projectPath, output format, maxFiles to analyze, folderPath, includeContent, useAI, and maxFileSizeForSymbols.export const localProjectHintsTool = { name: 'local_project_hints', description: 'π Generate intelligent project navigation hints with word clouds, folder analysis, and architecture detection. Supports multiple output formats including markdown and HTML, with AI-powered analysis and configurable performance options. Accepts absolute paths or relative paths (when workspace can be detected).', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Project directory path. Can be absolute (recommended) or relative to workspace. Examples: "C:\\Dev\\my-project", "/Users/username/project", or "." for current workspace.', }, format: { type: 'string', enum: ['structured', 'compact', 'json', 'markdown', 'html'], default: 'compact', description: 'Output format preference - structured for detailed analysis, compact for quick overview, json for raw data, markdown for documentation, html for visual reports', }, maxFiles: { type: 'number', default: 100, minimum: 10, maximum: 200, description: 'Maximum number of files to analyze for performance', }, folderPath: { type: 'string', description: 'Analyze specific folder instead of entire project (optional)', }, includeContent: { type: 'boolean', default: false, description: 'Include file content analysis for deeper insights (may impact performance)', }, useAI: { type: 'boolean', default: true, description: 'Enable AI-powered folder analysis for better purpose detection (requires OpenAI API key)', }, maxFileSizeForSymbols: { type: 'number', default: 50000, minimum: 10000, maximum: 200000, description: 'Maximum file size in bytes for symbol extraction (performance tuning)', }, }, }, };
- src/index.ts:126-142 (registration)Registers localProjectHintsTool in the MCP server's tools array and maps 'local_project_hints' to handleProjectHints in the handlers object used by setRequestHandler(CallToolRequestSchema).this.tools = [ ...(allowLocalContext ? [localSemanticCompactTool] : []), localProjectHintsTool, localFileSummaryTool, frontendInsightsTool, localDebugContextTool, astGrepTool, ]; this.handlers = { ...(allowLocalContext ? { local_context: handleSemanticCompact } : {}), local_project_hints: handleProjectHints, local_file_summary: handleFileSummary, frontend_insights: handleFrontendInsights, local_debug_context: handleLocalDebugContext, ast_grep_search: handleAstGrep, };
- src/tools/localTools/index.ts:119-137 (registration)Aggregates and exports localTools array including localProjectHintsTool and localHandlers map with 'local_project_hints': handleProjectHints, imported into src/index.ts for final MCP registration.export const localTools = [ ...(allowLocalContext ? [localSemanticCompactTool] : []), localProjectHintsTool, localFileSummaryTool, frontendInsightsTool, localDebugContextTool, manageEmbeddingsTool, astGrepTool, ]; export const localHandlers = { ...(allowLocalContext ? { local_context: handleSemanticCompact } : {}), local_project_hints: handleProjectHints, local_file_summary: handleFileSummary, frontend_insights: handleFrontendInsights, local_debug_context: handleLocalDebugContext, manage_embeddings: handleManageEmbeddings, ast_grep_search: handleAstGrep, };