UNPKG

docfs

Version:

MCP server for accessing local file system content with intelligent search and listing tools

110 lines 4.23 kB
/** * List Files Tool - Returns a structured list of files and directories */ import { isAbsolute, resolve, normalize } from 'node:path'; import { listFiles as listDirectoryFiles, validatePathAccess, pathExists, } from '../utils/filesystem.js'; /** * Validates and parses input parameters */ function parseInput(input) { const params = input; return { pattern: typeof params.pattern === 'string' ? params.pattern : undefined, recursive: typeof params.recursive === 'boolean' ? params.recursive : true, maxDepth: typeof params.maxDepth === 'number' ? Math.max(1, params.maxDepth) : 10, includeHidden: typeof params.includeHidden === 'boolean' ? params.includeHidden : false, path: typeof params.path === 'string' ? params.path : undefined, }; } export const listFiles = { name: 'list_files', description: 'Lists files and directories in the configured root directories and returns JSON data', inputSchema: { type: 'object', properties: { pattern: { type: 'string', description: 'Optional glob pattern to filter files (e.g., "*.js", "*.md")', }, recursive: { type: 'boolean', description: 'Whether to list files recursively (default: true)', default: true, }, maxDepth: { type: 'number', description: 'Maximum directory depth to traverse (default: 10)', default: 10, minimum: 1, }, includeHidden: { type: 'boolean', description: 'Whether to include hidden files and directories (default: false)', default: false, }, path: { type: 'string', description: 'Optional specific path within the root directories to list', }, }, }, async handler(input, context) { const params = parseInput(input); const results = []; // Determine which paths to list let pathsToList; if (params.path) { if (isAbsolute(params.path)) { pathsToList = [validatePathAccess(params.path, context.roots)]; } else { // Resolve relative path against each root and include those that exist const candidates = []; for (const root of context.roots) { const candidate = normalize(resolve(root, params.path)); try { const withinRoot = validatePathAccess(candidate, [root]); if (await pathExists(withinRoot)) { candidates.push(withinRoot); } } catch { // skip; not within this root } } if (candidates.length === 0) { throw new Error(`Path '${params.path}' not found within allowed roots. ` + `Provide an absolute path or a path relative to one of: ${context.roots.join(', ')}`); } pathsToList = candidates; } } else { pathsToList = context.roots; } for (const rootPath of pathsToList) { try { const files = await listDirectoryFiles(rootPath, { pattern: params.pattern, recursive: params.recursive, maxDepth: params.maxDepth, includeHidden: params.includeHidden, }); results.push({ root: rootPath, files }); } catch (error) { const message = error instanceof Error ? error.message : String(error); results.push({ root: rootPath, error: message }); } } return { content: [ { type: 'text', text: JSON.stringify(results), }, ], }; }, }; //# sourceMappingURL=listFiles.js.map