explore_project
List all files in a directory with sizes and JavaScript/TypeScript import/export analysis. Excludes build directories. Use to understand project structure and dependencies.
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
| Name | Required | Description | Default |
|---|---|---|---|
| directory | Yes | The directory path to analyze | |
| subDirectory | No | Optional subdirectory within the main directory to analyze | |
| includeHidden | No | Whether to include hidden files and directories (starting with .) |
Implementation Reference
- src/explore-project.ts:205-283 (handler)The main handler function that executes the 'explore_project' tool logic. Takes args (directory, subDirectory, includeHidden) and allowedDirectories, validates path permissions, scans the directory, and returns formatted results with file sizes, imports, and exports.
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)The tool definition including name, description, and input schema. Defines 'explore_project' with parameters: directory (required string), subDirectory (optional string), 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:12-57 (registration)Import of exploreProjectTool and handleExploreProject from explore-project.ts module, and their usage: the tool definition is registered in ListToolsRequestSchema handler (line 36) and the handler is invoked in the CallToolRequestSchema switch case (lines 56-57).
import { exploreProjectTool, handleExploreProject } from './explore-project.js'; import { listAllowedTool, handleListAllowed } from './list-allowed.js'; import { searchTool, handleSearch } from './search.js'; import { renameFileTool, handleRenameFile } from './rename-file.js'; import { deleteFileTool, handleDeleteFile } from './delete-file.js'; import { checkOutdatedTool, handleCheckOutdated } from './check-outdated.js'; // Get allowed directories from command line arguments (all args after the script path) const ALLOWED_DIRECTORIES = process.argv.slice(2).map(dir => dir.replace(/\\/g, '/')); // Initialize the MCP server const server = new Server({ name: "project-explorer", version: "1.0.0", }, { capabilities: { tools: {} } }); // Define available tools using imported tool definitions server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ exploreProjectTool, listAllowedTool, searchTool, renameFileTool, deleteFileTool, checkOutdatedTool ] }; }); // Handle tool execution using imported handlers server.setRequestHandler(CallToolRequestSchema, async (request) => { // Safely access arguments with null checking const args = request.params.arguments || {}; // Route to appropriate handler based on tool name switch (request.params.name) { case "list_allowed_directories": return await handleListAllowed(args, ALLOWED_DIRECTORIES); case "explore_project": return await handleExploreProject(args, ALLOWED_DIRECTORIES); - src/explore-project.ts:14-17 (helper)Helper function to check if a path should be excluded based on EXCLUDED_DIRS (node_modules, .git, dist, etc.)
function shouldExcludePath(pathToCheck: string): boolean { const basename = path.basename(pathToCheck); return EXCLUDED_DIRS.includes(basename); } - src/explore-project.ts:74-124 (helper)Recursive directory scanner that collects FileInfo for each file, including size, imports/exports for JS/TS files, and config detection for JSON 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; }