read_many
Read multiple text files simultaneously to retrieve contents and metadata, supporting partial reads by line ranges or head/tail sections.
Instructions
Read multiple text files in one request with contents and metadata. For a single file, use read.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| paths | Yes | Files to read. e.g. ["src/index.ts"] | |
| head | No | Read first N lines of each file | |
| tail | No | Read last N lines of each file | |
| startLine | No | Start line (1-based, inclusive) per file. Defaults to 1 when endLine is set. | |
| endLine | No | End line (1-based, inclusive) per file. Defaults to last line when startLine is set. |
Implementation Reference
- src/tools/read-multiple.ts:224-241 (handler)The core handler function `handleReadMultipleFiles` that processes multiple files for the `read_many` tool.
async function handleReadMultipleFiles( args: ReadManyInput, signal?: AbortSignal, resourceStore?: ToolRegistrationOptions['resourceStore'], onReadComplete?: () => void ): Promise<ToolResponse<ReadManyOutput>> { const options = buildReadMultipleOptions(args, signal, onReadComplete); const results = await readMultipleFiles(args.paths, options); const payload = buildReadManyResponsePayload(results, resourceStore); const structured: ReadManyOutput = { ok: true, results: payload.structuredResults, summary: payload.summary, }; return buildToolResponse(payload.text, structured, payload.resourceLinks); } - src/tools/read-multiple.ts:243-327 (registration)The `registerReadMultipleFilesTool` function that registers the `read_many` tool with the MCP server.
export function registerReadMultipleFilesTool( server: McpServer, options: ToolRegistrationOptions = {} ): void { const handler = ( args: ReadManyInput, extra: ToolExtra ): Promise<ToolResult<ReadManyOutput>> => { const primaryPath = args.paths[0] ?? ''; return executeToolWithDiagnostics({ toolName: READ_MANY_TOOL_NAME, extra, outputSchema: ReadMultipleFilesOutputSchema, timedSignal: { timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS }, context: { path: primaryPath }, run: async (signal) => { const context = buildBatchPathContext(args.paths, 'files'); const { progress, onItemComplete } = createBatchProgressCallbacks( extra, { toolLabel: READ_MANY_TOOL_LABEL, context, totalItems: args.paths.length, itemVerb: 'read', } ); try { const result = await handleReadMultipleFiles( args, signal, options.resourceStore, onItemComplete ); const sc = result.structuredContent; const suffix = buildBatchCompletionSuffix( sc.summary, 'files read', 'file read' ); const total = sc.summary?.total ?? 0; const finalCurrent = resolveFinalProgressCurrent(progress, total); progress.complete( `${READ_MANY_TOOL_LABEL}: ${context} • ${suffix}`, finalCurrent ); return result; } catch (error) { progress.fail(`${READ_MANY_TOOL_LABEL}: ${context} • failed`); throw error; } }, onError: (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_FILE, primaryPath), }); }; const wrappedHandler = wrapToolHandler(handler, { guard: options.isInitialized, }); const validatedHandler = withValidatedArgs( ReadMultipleFilesInputSchema, wrappedHandler ); if ( registerToolTaskIfAvailable( server, READ_MANY_TOOL_NAME, READ_MANY_TOOL, validatedHandler, options.iconInfo, options.isInitialized ) ) return; server.registerTool( READ_MANY_TOOL_NAME, withDefaultIcons({ ...READ_MANY_TOOL }, options.iconInfo), validatedHandler ); } - src/tools/read-multiple.ts:41-51 (schema)The `READ_MANY_TOOL` contract definition, which includes name, title, description, and input/output schemas for the `read_many` tool.
export const READ_MANY_TOOL: ToolContract = { name: READ_MANY_TOOL_NAME, title: 'Read Multiple Files', description: 'Read multiple text files in one request with contents and metadata. ' + 'For a single file, use `read`.', inputSchema: ReadMultipleFilesInputSchema, outputSchema: ReadMultipleFilesOutputSchema, annotations: READ_ONLY_TOOL_ANNOTATIONS, taskSupport: 'optional', } as const;