read_file_lines
Retrieve a specific line range from a file using 1-indexed inclusive bounds. Ideal for inspecting stack-trace regions or large file chunks without loading the entire content.
Instructions
Return a 1-indexed inclusive line slice of a file. Out-of-range bounds clamp silently to the file's actual length; to < from throws. Read-only; no side effects, auth, or rate limits. Returns the snippet plus its size_bytes and est_tokens. Use to inspect a stack-trace region or a chunk of a large file without pulling the whole body. Prefer read_section if you know the heading, grep_in_file if you know a pattern but not the line number.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | File ID | |
| from | Yes | First line (1-indexed, inclusive) | |
| to | Yes | Last line (1-indexed, inclusive) |
Implementation Reference
- apps/mcp/src/index.ts:348-384 (handler)The handler function for the read_file_lines tool. Reads a file by ID, extracts a 1-indexed line slice from 'from' to 'to', and returns the snippet with metadata (file_id, path, line range, total_lines, content, size_bytes, est_tokens). Bounds are clamped silently; throws if to < from.
async ({ id, from, to }) => { try { if (to < from) throw new Error("`to` must be >= `from`"); const file = readFile(id); const lines = file.content.split("\n"); const start = Math.max(0, from - 1); const end = Math.min(lines.length, to); const slice = lines.slice(start, end).join("\n"); return { content: [ { type: "text", text: JSON.stringify( { file_id: id, path: file.path, from: start + 1, to: end, total_lines: lines.length, content: slice, size_bytes: Buffer.byteLength(slice, "utf8"), est_tokens: estimateTokensFromBuffer(Buffer.from(slice, "utf8")), }, null, 2 ), }, ], }; } catch (e: any) { return { isError: true, content: [{ type: "text", text: JSON.stringify({ error: e?.message ?? String(e) }, null, 2) }], }; } } ); - apps/mcp/src/index.ts:344-347 (schema)Zod schema for read_file_lines input parameters: id (number), from (positive int), to (positive int).
id: z.number().describe("File ID"), from: z.number().int().positive().describe("First line (1-indexed, inclusive)"), to: z.number().int().positive().describe("Last line (1-indexed, inclusive)"), }, - apps/mcp/src/index.ts:340-384 (registration)Registration of the read_file_lines tool via server.tool() with name 'read_file_lines', description, schema, and handler.
server.tool( "read_file_lines", "Return a 1-indexed inclusive line slice of a file. Out-of-range bounds clamp silently to the file's actual length; `to < from` throws. Read-only; no side effects, auth, or rate limits. Returns the snippet plus its size_bytes and est_tokens. Use to inspect a stack-trace region or a chunk of a large file without pulling the whole body. Prefer `read_section` if you know the heading, `grep_in_file` if you know a pattern but not the line number.", { id: z.number().describe("File ID"), from: z.number().int().positive().describe("First line (1-indexed, inclusive)"), to: z.number().int().positive().describe("Last line (1-indexed, inclusive)"), }, async ({ id, from, to }) => { try { if (to < from) throw new Error("`to` must be >= `from`"); const file = readFile(id); const lines = file.content.split("\n"); const start = Math.max(0, from - 1); const end = Math.min(lines.length, to); const slice = lines.slice(start, end).join("\n"); return { content: [ { type: "text", text: JSON.stringify( { file_id: id, path: file.path, from: start + 1, to: end, total_lines: lines.length, content: slice, size_bytes: Buffer.byteLength(slice, "utf8"), est_tokens: estimateTokensFromBuffer(Buffer.from(slice, "utf8")), }, null, 2 ), }, ], }; } catch (e: any) { return { isError: true, content: [{ type: "text", text: JSON.stringify({ error: e?.message ?? String(e) }, null, 2) }], }; } } ); - apps/mcp/src/index.ts:69-84 (helper)The estimateTokensFromBuffer helper (imported from ctxnest-core) is used by the handler to compute estimated tokens from the line slice. Also estimateTokensFromFile helper defined locally.
function estimateTokensFromFile(filePath: string, sizeBytes: number): number { if (sizeBytes <= 0) return 1; const sampleSize = Math.min(4096, sizeBytes); if (sampleSize < 256) return Math.max(1, Math.ceil(sizeBytes / 4)); let mostlyAscii = true; let fd: number | null = null; try { fd = openSync(filePath, "r"); const buf = Buffer.alloc(sampleSize); readSync(fd, buf, 0, sampleSize, 0); mostlyAscii = buf.toString("utf-8").length > sampleSize * 0.7; } catch {} finally { if (fd !== null) try { closeSync(fd); } catch {} } return Math.max(1, Math.ceil(sizeBytes / (mostlyAscii ? 4 : 3))); } - apps/web/src/lib/mcp-tool-categories.ts:26-26 (registration)Categorizes read_file_lines under the 'Read' category for the web UI.
read_file_lines: "Read",