image_compression
Compress images by providing image URLs to reduce file size. Optionally set output format and number of results.
Instructions
Compress an image
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | URL of the image to compress,If it's a local file, do not add any prefix. array join by ',' | |
| quantity | No | Number of transcripts to return | |
| format | No | Image format |
Implementation Reference
- src/index.ts:86-139 (handler)The handleToolCall method that dispatches to 'image_compression' case, parsing URLs, calling compressAndStoreImage, and returning results.
private async handleToolCall(name: string, args: any): Promise<CallToolResult> { const { urls, quality = 80, format = null } = args; const imageSources = (urls as string)?.split(",")?.filter((url) => isImageSource(url)); if (this.downloadDir === '') { throw new McpError( ErrorCode.InvalidParams, `downloadDir is empty, please set the environment variable IMAGE_COMPRESSION_DOWNLOAD_DIR` ); } let outputPaths = [] switch (name) { case "image_compression": { try { const isMutipleUrls = imageSources.length > 1; const downloadDir = isMutipleUrls ? path.join(this.downloadDir, 'thumbs') : this.downloadDir; // 循环处理每个 URL // 压缩并存储图片 for (const key in imageSources) { const imageUrl = imageSources[key]; const outputPath = await compressAndStoreImage(imageUrl, downloadDir, quality, format) outputPaths.push(outputPath) } return { content: [{ type: "text", text: `success image compression ${outputPaths}`, }], metadata: { timestamp: new Date().toISOString(), }, isError: false } } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Failed to process transcript: ${(error as Error).message}` ); } } default: { throw new McpError(ErrorCode.MethodNotFound, `Tool ${name} not found`, { code: ErrorCode.MethodNotFound, message: `Tool ${name} not found` }); } } } - src/index.ts:14-37 (schema)The tool definition (TOOLS array) with inputSchema for 'image_compression', specifying required 'urls' field and optional 'format' and default quality=80.
const TOOLS: Tool[] = [ { name: "image_compression", description: "Compress an image", inputSchema: { type: "object", properties: { urls: { type: "string", description: "URL of the image to compress,If it's a local file, do not add any prefix. array join by ','", }, quantity: { type: "number", description: "Number of transcripts to return", default: 80 }, format: { type: "string", description: "Image format", } }, required: ["urls"] } } - src/index.ts:72-81 (registration)The setupHandlers method that registers the tool list (ListToolsRequestSchema) and tool call handler (CallToolRequestSchema) on the MCP server, linking the TOOLS array to the handler.
private setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => this.handleToolCall(request.params.name, request.params.arguments ?? {}) ); - src/common.ts:14-63 (helper)The compressAndStoreImage helper function that downloads/reads an image, compresses it with sharp (using configurable quality and format), saves it to the output directory, and returns the output path.
export async function compressAndStoreImage( imageUrl: ImageSource, outputDir: string, quality = 80, format = 'jpg', ): Promise<string> { try { // 校验输出目录 if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } let inputBuffer: Buffer; // 判断是否是网络地址 if (/^https?:\/\//.test(imageUrl)) { // 下载网络图片 const response = await axios.get(imageUrl, { responseType: 'arraybuffer', timeout: 10000 }); inputBuffer = Buffer.from(response.data, 'binary'); } else { // 读取本地图片 if (!fs.existsSync(imageUrl)) { throw new Error(`Local file not found: ${imageUrl}`); } inputBuffer = await fs.promises.readFile(imageUrl); } // 读取文件原始名称 const originalFilename = path.basename(imageUrl); const originalExt = path.parse(originalFilename).ext; // 生成唯一文件名 const outputFilename = format ? `${uuidv4()}.${format}` : `${uuidv4()}${originalExt}`; const outputPath = path.join(outputDir, outputFilename); await sharp(inputBuffer) // @ts-ignore .toFormat(format ? format : originalExt?.replace('.', ''), { quality, }) .toFile(outputPath); return outputPath; } catch (error) { throw new Error(`Image processing failed`); } } - src/common.ts:65-83 (helper)The isImageSource helper function that validates whether a string is a valid image source (file extension, base64 data URI, or CDN-style URL with format parameter).
export function isImageSource(str: string): boolean { // 匹配常规图片地址 if (/\.(jpe?g|png|gif|webp|bmp|svg|avif)(\?[^#]*)?(#[^\s]*)?$/i.test(str)) { return true; } // 匹配Base64数据URI if (/^data:image\/(jpe?g|png|gif|webp|bmp|svg\+xml|avif);base64,/i.test(str)) { return true; } // 可选:匹配无扩展名但包含图片路由的情况(如CDN地址) // 示例:/image/12345?format=jpg if (/\/(image|img|photo|pic)s?\/[^/]+(\?.*?(format|type)=(jpe?g|png|gif|webp|bmp|svg|avif))/i.test(str)) { return true; } return false; }