Skip to main content
Glama
modelcontextprotocol

Filesystem MCP Server

Official

Read File (Deprecated)

read_file
Read-only

Read file contents as text, with options to extract specific first or last lines for focused data retrieval.

Instructions

Read the complete contents of a file as text. DEPRECATED: Use read_text_file instead.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYes
tailNoIf provided, returns only the last N lines of the file
headNoIf provided, returns only the first N lines of the file

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
contentYes

Implementation Reference

  • Handler function that implements the core logic for the 'read_file' tool. Validates path, optionally tails/heads the file, otherwise reads full content using readFileContent, and returns as text content.
    const readTextFileHandler = async (args: z.infer<typeof ReadTextFileArgsSchema>) => {
      const validPath = await validatePath(args.path);
    
      if (args.head && args.tail) {
        throw new Error("Cannot specify both head and tail parameters simultaneously");
      }
    
      let content: string;
      if (args.tail) {
        content = await tailFile(validPath, args.tail);
      } else if (args.head) {
        content = await headFile(validPath, args.head);
      } else {
        content = await readFileContent(validPath);
      }
    
      return {
        content: [{ type: "text" as const, text: content }],
        structuredContent: { content }
      };
    };
  • Registration of the 'read_file' tool, marking it as deprecated and pointing to read_text_file, using the shared readTextFileHandler.
    server.registerTool(
      "read_file",
      {
        title: "Read File (Deprecated)",
        description: "Read the complete contents of a file as text. DEPRECATED: Use read_text_file instead.",
        inputSchema: ReadTextFileArgsSchema.shape,
        outputSchema: { content: z.string() },
        annotations: { readOnlyHint: true }
      },
      readTextFileHandler
    );
  • Zod input schema defining parameters for read_file (path, optional tail/head line limits).
    const ReadTextFileArgsSchema = z.object({
      path: z.string(),
      tail: z.number().optional().describe('If provided, returns only the last N lines of the file'),
      head: z.number().optional().describe('If provided, returns only the first N lines of the file')
    });
  • Helper function that performs the actual fs.readFile operation for reading file contents as text, used by the read_file handler.
    export async function readFileContent(filePath: string, encoding: string = 'utf-8'): Promise<string> {
      return await fs.readFile(filePath, encoding as BufferEncoding);
    }
  • Helper for tailing last N lines, used when 'tail' parameter is provided in read_file.
    export async function tailFile(filePath: string, numLines: number): Promise<string> {
      const CHUNK_SIZE = 1024; // Read 1KB at a time
      const stats = await fs.stat(filePath);
      const fileSize = stats.size;
      
      if (fileSize === 0) return '';
      
      // Open file for reading
      const fileHandle = await fs.open(filePath, 'r');
      try {
        const lines: string[] = [];
        let position = fileSize;
        let chunk = Buffer.alloc(CHUNK_SIZE);
        let linesFound = 0;
        let remainingText = '';
        
        // Read chunks from the end of the file until we have enough lines
        while (position > 0 && linesFound < numLines) {
          const size = Math.min(CHUNK_SIZE, position);
          position -= size;
          
          const { bytesRead } = await fileHandle.read(chunk, 0, size, position);
          if (!bytesRead) break;
          
          // Get the chunk as a string and prepend any remaining text from previous iteration
          const readData = chunk.slice(0, bytesRead).toString('utf-8');
          const chunkText = readData + remainingText;
          
          // Split by newlines and count
          const chunkLines = normalizeLineEndings(chunkText).split('\n');
          
          // If this isn't the end of the file, the first line is likely incomplete
          // Save it to prepend to the next chunk
          if (position > 0) {
            remainingText = chunkLines[0];
            chunkLines.shift(); // Remove the first (incomplete) line
          }
          
          // Add lines to our result (up to the number we need)
          for (let i = chunkLines.length - 1; i >= 0 && linesFound < numLines; i--) {
            lines.unshift(chunkLines[i]);
            linesFound++;
          }
        }
        
        return lines.join('\n');
      } finally {
        await fileHandle.close();
      }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotation 'readOnlyHint: true' already indicates this is a read operation, which the description confirms. The description adds the behavioral context that it reads 'complete contents as text' and is deprecated, but doesn't provide additional behavioral details like error conditions, performance characteristics, or file size limitations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly concise with two sentences that each serve distinct purposes: stating the tool's function and providing critical deprecation guidance. No wasted words, front-loaded with the core functionality.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has annotations (readOnlyHint), 67% schema coverage, and an output schema exists, the description provides adequate context. The deprecation warning is crucial missing context that the description correctly includes, though it could mention more about why it's deprecated or migration considerations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 67% schema description coverage (2 of 3 parameters have descriptions in the schema), the baseline is 3. The description doesn't add any parameter-specific information beyond what the schema provides about 'path', 'tail', and 'head' parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Read the complete contents of a file as text') and distinguishes this tool from its sibling 'read_text_file' by explicitly marking it as deprecated. It provides both verb and resource with precision.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states 'DEPRECATED: Use read_text_file instead,' providing clear guidance on when not to use this tool and naming the alternative. This is a complete usage guideline that prevents misuse.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/modelcontextprotocol/filesystem'

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