Skip to main content
Glama

ls

List directory contents including files and folders with details like name, type, size, and modification date. Configure visibility of hidden or ignored items and apply filters for specific file patterns.

Instructions

List immediate directory contents (non-recursive): name, path, type, size, modified date. Omit path for workspace root. includeIgnored=true for node_modules etc. For recursive search, use find.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathNoBase directory (default: root). Absolute path required if multiple roots.
includeHiddenNoInclude hidden items (starting with .)
includeIgnoredNoInclude ignored items (node_modules, .git, etc).
maxDepthNoMax recursion depth when pattern is provided
maxEntriesNoMaximum entries to return before truncation. Default: 20000
sortByNoSort field (name, size, modified, type)name
patternNoOptional glob pattern filter (e.g. "**/*.ts")
includeSymlinkTargetsNoResolve and include symlink targets in results
cursorNoPagination cursor from a previous response

Implementation Reference

  • The main handler function for the 'ls' tool.
    async function handleListDirectory(
      args: z.infer<typeof ListDirectoryInputSchema>,
      signal?: AbortSignal
    ): Promise<ToolResponse<z.infer<typeof ListDirectoryOutputSchema>>> {
      const dirPath = resolvePathOrRoot(args.path);
      const pageSize = args.maxEntries;
      const options: Parameters<typeof listDirectory>[1] = {
        includeHidden: args.includeHidden,
        excludePatterns: args.includeIgnored ? [] : DEFAULT_EXCLUDE_PATTERNS,
        sortBy: args.sortBy,
        includeSymlinkTargets: args.includeSymlinkTargets,
        ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),
        maxEntries: MAX_LIST_ENTRIES,
        ...(args.pattern !== undefined ? { pattern: args.pattern } : {}),
        ...(signal ? { signal } : {}),
      };
      const fingerprint = buildListFingerprint(args);
    
      let result: Awaited<ReturnType<typeof listDirectory>>;
      let cursorOffset = 0;
      let snapshotId: string | undefined;
    
      if (args.cursor) {
        const cursor = decodeListCursor(args.cursor);
        const snapshot = listSnapshots.get(cursor.snapshotId);
        if (snapshot?.fingerprint !== fingerprint) {
          throw new McpError(
            ErrorCode.E_INVALID_INPUT,
            'Invalid cursor: the cursor value is malformed or expired.'
          );
        }
    
        const { offset, snapshotId: storedSnapshotId } = cursor;
        cursorOffset = offset;
        snapshotId = storedSnapshotId;
        result = {
          path: snapshot.path,
          entries: snapshot.entries,
          summary: snapshot.summary,
        };
      } else {
        result = await listDirectory(dirPath, options);
      }
    
      const displayEntries = result.entries.slice(
        cursorOffset,
        cursorOffset + pageSize
      );
      if (!args.cursor && displayEntries.length < result.entries.length) {
        snapshotId = storeListSnapshot({
          path: result.path,
          entries: result.entries,
          summary: result.summary,
          fingerprint,
        });
      }
    
      const nextCursor = resolveNextListCursor(
        snapshotId,
        cursorOffset,
        displayEntries.length,
        result.entries.length
      );
      const displayResult = { ...result, entries: displayEntries };
      return buildToolResponse(
        buildListTextResult(displayResult, nextCursor),
        buildStructuredListResult(displayResult, nextCursor)
      );
    }
  • Registration function for the 'ls' tool.
    export function registerListDirectoryTool(
      server: McpServer,
      options: ToolRegistrationOptions = {}
    ): void {
      const handler = (
        args: z.infer<typeof ListDirectoryInputSchema>,
        extra: ToolExtra
      ): Promise<ToolResult<z.infer<typeof ListDirectoryOutputSchema>>> =>
        executeToolWithDiagnostics({
          toolName: 'ls',
          extra,
          outputSchema: ListDirectoryOutputSchema,
          context: { path: args.path ?? '.' },
          run: (signal) => handleListDirectory(args, signal),
          onError: (error) =>
            buildToolErrorResponse(
              error,
              ErrorCode.E_NOT_DIRECTORY,
              args.path ?? '.'
            ),
        });
    
      const wrappedHandler = wrapToolHandler(handler, {
        guard: options.isInitialized,
        progressMessage: (args) =>
          `≣ ls: ${args.path ? path.basename(args.path) : '.'}`,
        completionMessage: (args, result) => {
          const base = args.path ? path.basename(args.path) : '.';
          if (result.isError) return `≣ ls: ${base} • failed`;
          const sc = result.structuredContent;
          const count = sc.totalEntries ?? 0;
          return `≣ ls: ${base} • ${count} ${count === 1 ? 'entry' : 'entries'}`;
        },
      });
    
      const validatedHandler = withValidatedArgs(
        ListDirectoryInputSchema,
        wrappedHandler
      );
    
      if (
        registerToolTaskIfAvailable(
          server,
          'ls',
          LIST_DIRECTORY_TOOL,
          validatedHandler,
          options.iconInfo,
          options.isInitialized
        )
      )
        return;
      server.registerTool(
        'ls',
        withDefaultIcons({ ...LIST_DIRECTORY_TOOL }, options.iconInfo),
        validatedHandler
      );
    }
  • The tool contract definition for 'ls'.
    export const LIST_DIRECTORY_TOOL: ToolContract = {
      name: 'ls',
      title: 'List Directory',
      description:
        'List immediate directory contents (non-recursive): name, path, type, size, modified date. ' +
        'Omit path for workspace root. `includeIgnored=true` for node_modules etc. ' +
        'For recursive search, use `find`.',
      inputSchema: ListDirectoryInputSchema,
      outputSchema: ListDirectoryOutputSchema,
      annotations: READ_ONLY_TOOL_ANNOTATIONS,
      taskSupport: 'optional',
      nuances: ['`pattern` enables filtered recursive traversal up to `maxDepth`.'],
    } as const;

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/j0hanz/filesystem-mcp'

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