Skip to main content
Glama
sbarron

Ambiance MCP Server

by sbarron

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

TableJSON Schema
NameRequiredDescriptionDefault
projectPathNoProject directory path. Can be absolute (recommended) or relative to workspace. Examples: "C:\Dev\my-project", "/Users/username/project", or "." for current workspace.
formatNoOutput format preference - structured for detailed analysis, compact for quick overview, json for raw data, markdown for documentation, html for visual reportscompact
maxFilesNoMaximum number of files to analyze for performance
folderPathNoAnalyze specific folder instead of entire project (optional)
includeContentNoInclude file content analysis for deeper insights (may impact performance)
useAINoEnable AI-powered folder analysis for better purpose detection (requires OpenAI API key)
maxFileSizeForSymbolsNoMaximum file size in bytes for symbol extraction (performance tuning)

Implementation Reference

  • Main execution handler for the 'local_project_hints' tool. Validates inputs, generates project or folder hints using ProjectHintsGenerator, supports multiple formats (compact, structured, json, markdown, html), analyzes file composition, and returns formatted hints with metadata.
    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 name, description, and detailed inputSchema for parameters like projectPath, format, maxFiles, 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)',
          },
        },
      },
    };
  • Module-level registration of the 'local_project_hints' handler in the localHandlers object, which is imported and used by higher-level tool registries.
    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,
    };
  • src/index.ts:135-142 (registration)
    Primary MCP server registration of the 'local_project_hints' handler in the AmbianceMCPServer instance's handlers object, used for tool execution requests.
    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,
    };
  • Helper function used by the handler to analyze file composition by type (extensions), providing metadata on total files, analyzed files, and filtered out files.
    function analyzeFileComposition(
      allFiles: FileInfo[],
      analyzedFiles: FileInfo[]
    ): {
      totalFiles: number;
      byType: Record<string, number>;
      analyzedFiles: number;
      filteredOut: Record<string, number>;
    } {
      const byType: Record<string, number> = {};
      const filteredOut: Record<string, number> = {};
    
      // Count all files by extension
      for (const file of allFiles) {
        const ext = file.ext || path.extname(file.relPath).toLowerCase() || 'no-extension';
        byType[ext] = (byType[ext] || 0) + 1;
      }
    
      // Count filtered out files (not in analyzedFiles)
      const analyzedFileSet = new Set(analyzedFiles.map(f => f.absPath));
      for (const file of allFiles) {
        if (!analyzedFileSet.has(file.absPath)) {
          const ext = file.ext || path.extname(file.relPath).toLowerCase() || 'no-extension';
          filteredOut[ext] = (filteredOut[ext] || 0) + 1;
        }
      }
    
      return {
        totalFiles: allFiles.length,
        byType,
        analyzedFiles: analyzedFiles.length,
        filteredOut,
      };
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions 'AI-powered analysis' and 'configurable performance options,' but lacks critical details: whether this tool is read-only or makes changes, what permissions are required, how errors are handled, whether it accesses external APIs (beyond the OpenAI mention), or what the output structure looks like. For a complex 7-parameter tool with AI capabilities, this is insufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is reasonably concise and front-loaded, starting with the core purpose. Both sentences contribute value: the first defines capabilities, the second adds path and format context. There's no redundant information, though it could be slightly more structured by separating functional description from technical details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (7 parameters, AI capabilities, multiple output formats) and the absence of both annotations and an output schema, the description is incomplete. It doesn't explain what the generated 'hints' actually contain, how word clouds or architecture detection work, what the performance implications are, or what happens when AI analysis is enabled without an API key. For a sophisticated analysis tool, this leaves too many operational questions unanswered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds minimal parameter semantics beyond the schema. It mentions 'absolute paths or relative paths' which aligns with the projectPath parameter, and 'multiple output formats' which aligns with the format parameter. However, with 100% schema description coverage, the schema already documents all 7 parameters thoroughly. The description doesn't provide additional context about parameter interactions or usage patterns beyond what's in the schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Generate intelligent project navigation hints with word clouds, folder analysis, and architecture detection.' It specifies the verb 'generate' and the resource 'project navigation hints' with key capabilities. However, it doesn't explicitly differentiate this from sibling tools like 'local_context' or 'local_file_summary' which might also analyze local projects.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides minimal usage guidance. It mentions 'Supports multiple output formats' and 'Accepts absolute paths or relative paths,' but offers no explicit advice on when to use this tool versus alternatives like 'local_context' or 'frontend_insights.' There's no guidance on prerequisites, performance trade-offs, or typical use cases beyond the basic functionality.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sbarron/AmbianceMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server