explore_project
Analyzes and lists files in a directory, detailing sizes and import/export statements in JavaScript/TypeScript. Filters out common build directories like node_modules for streamlined project structure review.
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
| Name | Required | Description | Default |
|---|---|---|---|
| directory | Yes | The directory path to analyze | |
| includeHidden | No | Whether to include hidden files and directories (starting with .) | |
| subDirectory | No | Optional subdirectory within the main directory to analyze |
Implementation Reference
- src/explore-project.ts:205-283 (handler)The main handler function that executes the explore_project tool logic, including path validation, directory scanning, file analysis for imports/exports, and result formatting.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)}` ); } }
- src/explore-project.ts:179-202 (schema)Tool definition object containing the name, description, and input schema for validation.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 explore_project tool in the ListToolsRequestSchema handler, where it is included in the list of available tools.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ exploreProjectTool, listAllowedTool, searchTool, renameFileTool, deleteFileTool, checkOutdatedTool ] }; });
- src/index.ts:56-57 (registration)Dispatch to the explore_project handler in the CallToolRequestSchema switch statement.case "explore_project": return await handleExploreProject(args, ALLOWED_DIRECTORIES);
- src/explore-project.ts:74-124 (helper)Core helper function that recursively scans directories, gathers file info, 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; }