Stream media file reads

This commit is contained in:
Cliff Hall
2025-07-18 14:18:32 -04:00
parent 11a064c359
commit d532a5846d
2 changed files with 18 additions and 2 deletions

View File

@@ -81,7 +81,7 @@ The server's directory access control follows this flow:
- **read_media_file**
- Read an image or audio file
- Input: `path` (string)
- Returns base64 data and MIME type based on the file extension
- Streams the file and returns base64 data with the corresponding MIME type
- **read_multiple_files**
- Read multiple files simultaneously

View File

@@ -10,6 +10,7 @@ import {
type Root,
} from "@modelcontextprotocol/sdk/types.js";
import fs from "fs/promises";
import { createReadStream } from "fs";
import path from "path";
import os from 'os';
import { randomBytes } from 'crypto';
@@ -475,6 +476,21 @@ async function headFile(filePath: string, numLines: number): Promise<string> {
}
}
// Stream a file and return its Base64 representation without loading the
// entire file into memory at once. Chunks are encoded individually and
// concatenated into the final string.
async function readFileAsBase64Stream(filePath: string): Promise<string> {
return new Promise((resolve, reject) => {
const stream = createReadStream(filePath, { encoding: 'base64' });
let data = '';
stream.on('data', (chunk) => {
data += chunk;
});
stream.on('end', () => resolve(data));
stream.on('error', (err) => reject(err));
});
}
// Tool handlers
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
@@ -663,7 +679,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
".flac": "audio/flac",
};
const mimeType = mimeTypes[extension] || "application/octet-stream";
const data = (await fs.readFile(validPath)).toString("base64");
const data = await readFileAsBase64Stream(validPath);
const type = mimeType.startsWith("image/")
? "image"
: mimeType.startsWith("audio/")