read_file
Read file contents from the file system, handling various text encodings and providing error details for unreadable files within 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 for security and reads the file contents using Node.js 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 schema defining the input for read_file tool: requires a 'path' string parameter.export const ReadFileArgsSchema = z.object({ path: z.string(), });
- src/server.ts:126-131 (registration)Tool registration in the server's ListTools response, specifying 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)Server dispatch handler that parses arguments, calls the readFile function, and formats the response for MCP protocol.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 that validates paths are within allowed directories, handles symlinks and home expansion.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}`); } } }