Skip to main content
Glama
MausRundung

Project Explorer MCP Server

by MausRundung

explore_project

Analyze project directories to list files with sizes and import/export details, excluding common build folders for JavaScript/TypeScript codebases.

Instructions

Lists all files in a directory with their sizes and imports/exports. Analyzes JavaScript/TypeScript files for import/export statements and provides detailed file information including size formatting. Excludes common build directories like node_modules, .git, dist, etc.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
directoryYesThe directory path to analyze
subDirectoryNoOptional subdirectory within the main directory to analyze
includeHiddenNoWhether to include hidden files and directories (starting with .)

Implementation Reference

  • Main handler function executing the tool logic: validates args, checks permissions, scans directory recursively, analyzes code files for imports/exports, formats and returns markdown results.
    export async function handleExploreProject(args: any, allowedDirectories: string[]) {
      const directory = args.directory as string;
      const subDirectory = args.subDirectory as string || "";
      const includeHidden = (args.includeHidden as boolean) || false;
      
      if (!directory) {
        throw new McpError(
          ErrorCode.InvalidRequest, 
          "Directory parameter is required"
        );
      }
      
      try {
        // Construct the full directory path
        let fullDirPath = directory;
        if (subDirectory) {
          fullDirPath = path.join(directory, subDirectory);
        }
        
        // Normalize path for comparison
        fullDirPath = path.normalize(fullDirPath);
        
        // Check if the path is allowed
        if (!isPathAllowed(fullDirPath, allowedDirectories)) {
          throw new McpError(
            ErrorCode.InvalidRequest, 
            `Access denied: The path '${fullDirPath}' is not in the list of allowed directories: ${allowedDirectories.join(', ')}`
          );
        }
        
        // Validate that the directory exists
        const dirStats = await getFileStats(fullDirPath);
        if (!dirStats || !dirStats.isDirectory) {
          throw new McpError(
            ErrorCode.InvalidRequest, 
            `The path '${fullDirPath}' does not exist or is not a directory.`
          );
        }
        
        const files = await scanDirectory(fullDirPath, fullDirPath);
        
        // Filter out hidden files if not includeHidden
        const filteredFiles = includeHidden 
          ? files 
          : files.filter(file => !path.basename(file.path).startsWith('.'));
        
        if (filteredFiles.length === 0) {
          const emptyResult = `# Project Analysis Results for: ${fullDirPath}\n\nNo files found in the directory.\n\n**Note:** This could mean:\n- The directory is empty\n- All files are hidden (use includeHidden=true to see hidden files)\n- All files are in excluded directories (${EXCLUDED_DIRS.join(', ')})`;
          return {
            content: [
              {
                type: "text",
                text: emptyResult
              }
            ]
          };
        }
        
        const formattedResults = formatResults(filteredFiles, fullDirPath);
        
        return {
          content: [
            {
              type: "text",
              text: formattedResults
            }
          ]
        };
      } catch (error) {
        if (error instanceof McpError) {
          throw error;
        }
        
        throw new McpError(
          ErrorCode.InternalError, 
          `Error analyzing project: ${error instanceof Error ? error.message : String(error)}`
        );
      }
    }
  • Tool definition object with name, description, and inputSchema defining parameters: directory (required), subDirectory (optional), includeHidden (optional boolean).
    export const exploreProjectTool = {
      name: "explore_project",
      description: "Lists all files in a directory with their sizes and imports/exports. Analyzes JavaScript/TypeScript files for import/export statements and provides detailed file information including size formatting. Excludes common build directories like node_modules, .git, dist, etc.",
      inputSchema: {
        type: "object",
        properties: {
          directory: { 
            type: "string",
            description: "The directory path to analyze"
          },
          subDirectory: {
            type: "string",
            description: "Optional subdirectory within the main directory to analyze",
            default: ""
          },
          includeHidden: { 
            type: "boolean", 
            description: "Whether to include hidden files and directories (starting with .)",
            default: false
          }
        },
        required: ["directory"]
      }
    };
  • src/index.ts:33-44 (registration)
    Registration of the exploreProjectTool in the MCP server's listTools handler, making it discoverable.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          exploreProjectTool,
          listAllowedTool,
          searchTool,
          renameFileTool,
          deleteFileTool,
          checkOutdatedTool
        ]
      };
    });
  • src/index.ts:52-77 (registration)
    Registration of the tool handler in the MCP server's CallToolRequestSchema switch statement, routing 'explore_project' calls to handleExploreProject.
      switch (request.params.name) {
        case "list_allowed_directories":
          return await handleListAllowed(args, ALLOWED_DIRECTORIES);
          
        case "explore_project":
          return await handleExploreProject(args, ALLOWED_DIRECTORIES);
          
        case "search_files":
          return await handleSearch(args, ALLOWED_DIRECTORIES);
          
        case "rename_file":
          return await handleRenameFile(args, ALLOWED_DIRECTORIES);
          
        case "delete_file":
          return await handleDeleteFile(args, ALLOWED_DIRECTORIES);
          
        case "check_outdated":
          return await handleCheckOutdated(args, ALLOWED_DIRECTORIES);
          
        default:
          throw new McpError(
            ErrorCode.InvalidRequest, 
            `Unknown tool: ${request.params.name}`
          );
      }
    });
  • Core recursive directory scanning helper that collects file info, skips excluded dirs, extracts imports/exports from code files.
    async function scanDirectory(dirPath: string, rootPath: string): Promise<FileInfo[]> {
      const results: FileInfo[] = [];
      
      try {
        const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
        
        for (const entry of entries) {
          const entryPath = path.join(dirPath, entry.name);
          
          // Skip excluded directories
          if (entry.isDirectory() && shouldExcludePath(entryPath)) {
            continue;
          }
          
          if (entry.isDirectory()) {
            // Recursively scan subdirectories
            const subdirResults = await scanDirectory(entryPath, rootPath);
            results.push(...subdirResults);
          } else if (entry.isFile()) {
            const stats = await getFileStats(entryPath);
            
            if (!stats) continue;
            
            const fileInfo: FileInfo = {
              path: entryPath,
              size: stats.size,
              sizeFormatted: formatFileSize(stats.size),
              isEmpty: stats.isEmpty
            };
            
            // Check if this is a file type we should analyze for imports/exports
            const ext = path.extname(entryPath).toLowerCase();
            if (ANALYZED_EXTENSIONS.includes(ext)) {
              if (CODE_FILE_EXTENSIONS.includes(ext)) {
                const { imports, exports } = await extractImportsAndExports(entryPath);
                fileInfo.imports = imports;
                fileInfo.exports = exports;
              } else if (CONFIG_FILE_EXTENSIONS.includes(ext)) {
                fileInfo.fileType = 'config';
              }
            }
            
            results.push(fileInfo);
          }
        }
      } catch (error) {
        // Error scanning directory, skip
      }
      
      return results;
    }

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/MausRundung/mcp-explorer'

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