Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/handlers/filesystem-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,15 @@ export async function handleCreateDirectory(args: unknown): Promise<ServerResult
*/
export async function handleListDirectory(args: unknown): Promise<ServerResult> {
try {
const startTime = Date.now();
const parsed = ListDirectoryArgsSchema.parse(args);
const entries = await listDirectory(parsed.path);
const entries = await listDirectory(parsed.path, parsed.depth);
const duration = Date.now() - startTime;

const resultText = entries.join('\n');

return {
content: [{ type: "text", text: entries.join('\n') }],
content: [{ type: "text", text: resultText }],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
Expand Down
14 changes: 14 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {

Use this instead of 'execute_command' with ls/dir commands.
Results distinguish between files and directories with [FILE] and [DIR] prefixes.

Supports recursive listing with the 'depth' parameter (default: 2):
- depth=1: Only direct contents of the directory
- depth=2: Contents plus one level of subdirectories
- depth=3+: Multiple levels deep

Results show full relative paths from the root directory being listed.
Example output with depth=2:
[DIR] src
[FILE] src/index.ts
[DIR] src/tools
[FILE] src/tools/filesystem.ts

If a directory cannot be accessed, it will show [DENIED] instead.
Only works within allowed directories.

${PATH_GUIDANCE}
Expand Down
43 changes: 40 additions & 3 deletions src/tools/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -890,10 +890,47 @@ export async function createDirectory(dirPath: string): Promise<void> {
await fs.mkdir(validPath, { recursive: true });
}

export async function listDirectory(dirPath: string): Promise<string[]> {
export async function listDirectory(dirPath: string, depth: number = 2): Promise<string[]> {
const validPath = await validatePath(dirPath);
const entries = await fs.readdir(validPath, { withFileTypes: true });
return entries.map((entry) => `${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${entry.name}`);
const results: string[] = [];

async function listRecursive(currentPath: string, currentDepth: number, relativePath: string = ''): Promise<void> {
if (currentDepth <= 0) return;

let entries;
try {
entries = await fs.readdir(currentPath, { withFileTypes: true });
} catch (error) {
// If we can't read this directory (permission denied), show as denied
const displayPath = relativePath || path.basename(currentPath);
results.push(`[DENIED] ${displayPath}`);
return;
}

for (const entry of entries) {
const fullPath = path.join(currentPath, entry.name);
const displayPath = relativePath ? path.join(relativePath, entry.name) : entry.name;

// Add this entry to results
results.push(`${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${displayPath}`);

// If it's a directory and we have depth remaining, recurse
if (entry.isDirectory() && currentDepth > 1) {
try {
// Validate the path before recursing
await validatePath(fullPath);
await listRecursive(fullPath, currentDepth - 1, displayPath);
} catch (error) {
// If validation fails or we can't access it, it will be marked as denied
// when we try to read it in the recursive call
continue;
}
}
}
}

await listRecursive(validPath, depth);
return results;
}

export async function moveFile(sourcePath: string, destinationPath: string): Promise<void> {
Expand Down
1 change: 1 addition & 0 deletions src/tools/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const CreateDirectoryArgsSchema = z.object({

export const ListDirectoryArgsSchema = z.object({
path: z.string(),
depth: z.number().optional().default(2),
});

export const MoveFileArgsSchema = z.object({
Expand Down