read_file
Retrieve file contents efficiently, either in full or by specific line ranges, using a file path. Option to display line numbers for enhanced readability and precise file navigation.
Instructions
Read the contents of a file. You can read the entire file or specific line ranges.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| end_line | No | Ending line number (1-based). Cannot be used with full=true | |
| file_path | Yes | Absolute path to the file to read | |
| full | No | Read the entire file. Cannot be used with start_line or end_line | |
| show_line_numbers | No | Whether to prefix each line with its line number | |
| start_line | No | Starting line number (1-based). Cannot be used with full=true |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"end_line": {
"description": "Ending line number (1-based). Cannot be used with full=true",
"exclusiveMinimum": 0,
"type": "integer"
},
"file_path": {
"description": "Absolute path to the file to read",
"type": "string"
},
"full": {
"description": "Read the entire file. Cannot be used with start_line or end_line",
"type": "boolean"
},
"show_line_numbers": {
"default": false,
"description": "Whether to prefix each line with its line number",
"type": "boolean"
},
"start_line": {
"description": "Starting line number (1-based). Cannot be used with full=true",
"exclusiveMinimum": 0,
"type": "integer"
}
},
"required": [
"file_path"
],
"type": "object"
}
Implementation Reference
- src/index.ts:24-80 (registration)Registers the read_file tool using server.addTool, including name, description, parameters schema, and execute handler.server.addTool({ name: 'read_file', description: 'Read the contents of a file. You can read the entire file or specific line ranges.', parameters: z.object({ file_path: z.string().describe('Absolute path to the file to read'), show_line_numbers: z.boolean().optional().default(false).describe('Whether to prefix each line with its line number'), start_line: z.number().int().positive().optional().describe('Starting line number (1-based). Cannot be used with full=true'), end_line: z.number().int().positive().optional().describe('Ending line number (1-based). Cannot be used with full=true'), full: z.boolean().optional().describe('Read the entire file. Cannot be used with start_line or end_line') }), execute: async ({ file_path, show_line_numbers, start_line, end_line, full }) => { // Validate parameters if (full && (start_line || end_line)) { throw new UserError('Cannot use "full" parameter together with "start_line" or "end_line". Choose either full=true or specify line ranges.'); } if ((start_line && !end_line) || (!start_line && end_line)) { throw new UserError('Both "start_line" and "end_line" must be provided together.'); } if (start_line && end_line && start_line > end_line) { throw new UserError('"start_line" must be less than or equal to "end_line".'); } const absolutePath = validateAbsolutePath(file_path, 'file_path'); validateFileExists(absolutePath); try { const content = fs.readFileSync(absolutePath, 'utf-8'); const lines = content.split('\n'); let resultLines: string[]; if (full) { resultLines = lines; } else if (start_line && end_line) { if (start_line > lines.length) { throw new UserError(`Start line ${start_line} is beyond the file length (${lines.length} lines).`); } if (end_line > lines.length) { throw new UserError(`End line ${end_line} is beyond the file length (${lines.length} lines).`); } resultLines = lines.slice(start_line - 1, end_line); // Convert to 0-based } else { resultLines = lines; } if (show_line_numbers) { const startLineNum = start_line || 1; return resultLines.map((line, index) => `${startLineNum + index} | ${line}`).join('\n'); } else { return resultLines.join('\n'); } } catch (error: any) { if (error instanceof UserError) throw error; throw new UserError(`Error reading file "${absolutePath}": ${error.message}`); } } });
- src/index.ts:34-79 (handler)The core handler function for the read_file tool. It validates input parameters, reads the file using fs.readFileSync, processes line ranges if specified, optionally adds line numbers, and returns the content.execute: async ({ file_path, show_line_numbers, start_line, end_line, full }) => { // Validate parameters if (full && (start_line || end_line)) { throw new UserError('Cannot use "full" parameter together with "start_line" or "end_line". Choose either full=true or specify line ranges.'); } if ((start_line && !end_line) || (!start_line && end_line)) { throw new UserError('Both "start_line" and "end_line" must be provided together.'); } if (start_line && end_line && start_line > end_line) { throw new UserError('"start_line" must be less than or equal to "end_line".'); } const absolutePath = validateAbsolutePath(file_path, 'file_path'); validateFileExists(absolutePath); try { const content = fs.readFileSync(absolutePath, 'utf-8'); const lines = content.split('\n'); let resultLines: string[]; if (full) { resultLines = lines; } else if (start_line && end_line) { if (start_line > lines.length) { throw new UserError(`Start line ${start_line} is beyond the file length (${lines.length} lines).`); } if (end_line > lines.length) { throw new UserError(`End line ${end_line} is beyond the file length (${lines.length} lines).`); } resultLines = lines.slice(start_line - 1, end_line); // Convert to 0-based } else { resultLines = lines; } if (show_line_numbers) { const startLineNum = start_line || 1; return resultLines.map((line, index) => `${startLineNum + index} | ${line}`).join('\n'); } else { return resultLines.join('\n'); } } catch (error: any) { if (error instanceof UserError) throw error; throw new UserError(`Error reading file "${absolutePath}": ${error.message}`); } }
- src/index.ts:27-32 (schema)Zod schema defining the input parameters for the read_file tool, including file_path, optional line ranges, full read flag, and line number display option.parameters: z.object({ file_path: z.string().describe('Absolute path to the file to read'), show_line_numbers: z.boolean().optional().default(false).describe('Whether to prefix each line with its line number'), start_line: z.number().int().positive().optional().describe('Starting line number (1-based). Cannot be used with full=true'), end_line: z.number().int().positive().optional().describe('Ending line number (1-based). Cannot be used with full=true'), full: z.boolean().optional().describe('Read the entire file. Cannot be used with start_line or end_line')
- src/utils.ts:12-20 (helper)Helper function validateAbsolutePath used in read_file handler to ensure the file_path is absolute (called at line 46).export function validateAbsolutePath(filePath: string, parameterName: string = 'path'): string { if (!path.isAbsolute(filePath)) { throw new UserError( `The ${parameterName} must be an absolute path. You provided a relative path: "${filePath}". ` + `Please provide the full absolute path (e.g., "/home/user/file.txt" on Linux/Mac or "C:\\Users\\user\\file.txt" on Windows).` ); } return filePath; }
- src/utils.ts:27-50 (helper)Helper function validateFileExists used in read_file handler to check if the file exists and is readable (called at line 47).export function validateFileExists(filePath: string): void { try { const stats = fs.statSync(filePath); if (!stats.isFile()) { throw new UserError( `The path "${filePath}" exists but is not a file. Please ensure you're providing the path to a file, not a directory.` ); } } catch (error: any) { if (error.code === 'ENOENT') { throw new UserError( `File not found: "${filePath}". Please verify that the file exists and the path is correct.` ); } else if (error.code === 'EACCES') { throw new UserError( `Permission denied: Cannot access "${filePath}". Please check file permissions.` ); } else { throw new UserError( `Error accessing file "${filePath}": ${error.message}` ); } } }