read_file
Retrieve and read the entire contents of a file from the file system, supporting multiple text encodings. Provides detailed error messages for unreadable files and operates within specified allowed directories.
Instructions
Read the complete contents of a file from the file system. Handles various text encodings and provides detailed error messages if the file cannot be read. Only works within allowed directories.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Implementation Reference
- src/tools/filesystem.ts:65-68 (handler)Core handler function that validates the file path security and reads the file content using fs.promises.readFile.export async function readFile(filePath: string): Promise<string> { const validPath = await validatePath(filePath); return fs.readFile(validPath, "utf-8"); }
- src/tools/schemas.ts:32-34 (schema)Zod input schema for the read_file tool, requiring a 'path' string parameter.export const ReadFileArgsSchema = z.object({ path: z.string(), });
- src/server.ts:125-132 (registration)Tool registration in the MCP ListTools handler, defining name, description, and input schema.{ name: "read_file", description: "Read the complete contents of a file from the file system. " + "Handles various text encodings and provides detailed error messages " + "if the file cannot be read. Only works within allowed directories.", inputSchema: zodToJsonSchema(ReadFileArgsSchema), },
- src/server.ts:266-272 (handler)MCP CallTool dispatch handler for read_file, which parses arguments, calls the readFile function, and formats the response.case "read_file": { const parsed = ReadFileArgsSchema.parse(args); const content = await readFile(parsed.path); return { content: [{ type: "text", text: content }], }; }
- src/tools/filesystem.ts:24-62 (helper)Security helper function used by readFile to validate paths are within allowed directories and resolve symlinks.export async function validatePath(requestedPath: string): Promise<string> { const expandedPath = expandHome(requestedPath); const absolute = path.isAbsolute(expandedPath) ? path.resolve(expandedPath) : path.resolve(process.cwd(), expandedPath); const normalizedRequested = normalizePath(absolute); // Check if path is within allowed directories const isAllowed = allowedDirectories.some(dir => normalizedRequested.startsWith(normalizePath(dir))); if (!isAllowed) { throw new Error(`Access denied - path outside allowed directories: ${absolute}`); } // Handle symlinks by checking their real path try { const realPath = await fs.realpath(absolute); const normalizedReal = normalizePath(realPath); const isRealPathAllowed = allowedDirectories.some(dir => normalizedReal.startsWith(normalizePath(dir))); if (!isRealPathAllowed) { throw new Error("Access denied - symlink target outside allowed directories"); } return realPath; } catch (error) { // For new files that don't exist yet, verify parent directory const parentDir = path.dirname(absolute); try { const realParentPath = await fs.realpath(parentDir); const normalizedParent = normalizePath(realParentPath); const isParentAllowed = allowedDirectories.some(dir => normalizedParent.startsWith(normalizePath(dir))); if (!isParentAllowed) { throw new Error("Access denied - parent directory outside allowed directories"); } return absolute; } catch { throw new Error(`Parent directory does not exist: ${parentDir}`); } } }