read_image
Extracts image dataURL and dimensions from local or URL-based images, supporting resizing via maxSide parameter for flexible image processing.
Instructions
读取本地/URL图片并返回 dataURL 与尺寸信息
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| maxSide | No | 最大边长,用于缩放 | |
| path | Yes | 图片路径或URL |
Implementation Reference
- src/index.ts:168-227 (handler)Core handler function that implements the read_image tool: loads image from local file, HTTP/HTTPS URL, or data URL, optionally compresses it, generates base64 data URL, and returns structured ImageResult with dimensions.async function readImage(imagePath: string, maxSide?: number): Promise<ImageResult> { try { console.error(`[DEBUG] readImage called with path: ${imagePath.substring(0, 50)}...`); console.error(`[DEBUG] Path starts with data:? ${imagePath.startsWith("data:")}`); let buffer: Buffer; if (imagePath.startsWith("data:")) { // Data URL 格式 console.error(`[DEBUG] Processing data URL in readImage`); const commaIndex = imagePath.indexOf(','); if (commaIndex === -1) { throw new Error("Invalid data URL format: no comma found"); } const base64Data = imagePath.substring(commaIndex + 1); if (!base64Data) { throw new Error("Invalid data URL format: no base64 data"); } console.error(`[DEBUG] Base64 data length: ${base64Data.length}`); buffer = Buffer.from(base64Data, 'base64'); } else if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) { // HTTP/HTTPS URL图片 console.error(`[DEBUG] Fetching HTTP/HTTPS image`); const response = await fetch(imagePath); if (!response.ok) { throw new Error(`Failed to fetch image: ${response.statusText}`); } buffer = Buffer.from(await response.arrayBuffer()); } else { // 本地文件 console.error(`[DEBUG] Reading local file: ${imagePath}`); const resolvedPath = path.resolve(imagePath); buffer = await fs.readFile(resolvedPath); } console.error(`[DEBUG] Original buffer size: ${buffer.length}`); // 压缩图片 const compressedBuffer = await compressImage(buffer, maxSide || 1024); console.error(`[DEBUG] Compressed buffer size: ${compressedBuffer.length}`); const mime = "image/jpeg"; // 压缩后统一为 JPEG 格式 const dataUrl = `data:${mime};base64,${compressedBuffer.toString("base64")}`; return { ok: true, image: { source: imagePath, mime, dataUrl, width: (await sharp(compressedBuffer).metadata()).width, height: (await sharp(compressedBuffer).metadata()).height } }; } catch (error) { return { ok: false, error: error instanceof Error ? error.message : "Unknown error" }; } }
- src/index.ts:51-78 (registration)Registration of the read_image tool with the MCP server, specifying input schema using Zod and a thin wrapper handler that invokes readImage and formats the MCP response.mcpServer.registerTool("read_image", { description: "读取本地/URL图片并返回 dataURL 与尺寸信息", inputSchema: { path: z.string().describe("图片路径或URL"), maxSide: z.number().optional().describe("最大边长,用于缩放"), }, }, async ({ path: imagePath, maxSide }) => { try { const result = await readImage(imagePath, maxSide); return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] }; } catch (error) { return { content: [{ type: "text" as const, text: JSON.stringify({ ok: false, error: error instanceof Error ? error.message : "Unknown error" }, null, 2) }], isError: true }; } });
- src/index.ts:13-23 (schema)TypeScript interface defining the structure of the output returned by the read_image tool.interface ImageResult { ok: boolean; image?: { source: string; mime: string; dataUrl: string; width?: number; height?: number; }; error?: string; }
- src/index.ts:52-56 (schema)Zod input schema for the read_image tool parameters: required path (string) and optional maxSide (number).description: "读取本地/URL图片并返回 dataURL 与尺寸信息", inputSchema: { path: z.string().describe("图片路径或URL"), maxSide: z.number().optional().describe("最大边长,用于缩放"), },
- src/index.ts:143-166 (helper)Supporting helper function used by readImage to compress image buffers to a maximum side length using sharp, outputting JPEG.async function compressImage(buffer: Buffer, maxSide: number = 1024, quality: number = 80): Promise<Buffer> { try { const image = sharp(buffer); const metadata = await image.metadata(); let width = metadata.width || 1024; let height = metadata.height || 1024; // 计算缩放比例 if (width > maxSide || height > maxSide) { const ratio = Math.min(maxSide / width, maxSide / height); width = Math.round(width * ratio); height = Math.round(height * ratio); } return await image .resize(width, height, { fit: 'inside' }) .jpeg({ quality, progressive: true }) .toBuffer(); } catch (error) { console.error("Image compression failed:", error); return buffer; // 失败时返回原始buffer } }