Skip to main content
Glama

edit_image

Modify existing images using text prompts and optional reference images. Change specific elements, apply styles, or adjust composition while maintaining the original file structure.

Instructions

Edit a SPECIFIC existing image file, optionally using additional reference images. Use this when you have the exact file path of an image to modify.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
aspectRatioNoOptional aspect ratio for the edited image. Default is 1:1 (1024×1024).
imagePathYesFull file path to the main image file to edit
promptYesText describing the modifications to make to the existing image
referenceImagesNoOptional array of file paths to additional reference images to use during editing (e.g., for style transfer, adding elements, etc.)

Implementation Reference

  • The primary handler function that implements the 'edit_image' tool logic. It reads the input image, optionally reference images, constructs a prompt for the OpenRouter Gemini model, generates the edited image, saves it to disk, and returns the result with embedded image data.
    private async editImage(request: CallToolRequest): Promise<CallToolResult> { if (!this.ensureConfigured()) { throw new McpError(ErrorCode.InvalidRequest, "OpenRouter API token not configured. Use configure_openrouter_token first."); } const { imagePath, prompt, referenceImages, aspectRatio } = request.params.arguments as { imagePath: string; prompt: string; referenceImages?: string[]; aspectRatio?: AspectRatio; }; try { // Prepare the main image const imageBuffer = await fs.readFile(imagePath); const mimeType = this.getMimeType(imagePath); const imageBase64 = imageBuffer.toString('base64'); // Build content array for the message const contentParts: any[] = []; // Add the main image contentParts.push({ type: "image_url", image_url: { url: `data:${mimeType};base64,${imageBase64}`, } }); // Add reference images if provided if (referenceImages && referenceImages.length > 0) { for (const refPath of referenceImages) { try { const refBuffer = await fs.readFile(refPath); const refMimeType = this.getMimeType(refPath); const refBase64 = refBuffer.toString('base64'); contentParts.push({ type: "image_url", image_url: { url: `data:${refMimeType};base64,${refBase64}`, } }); } catch (error) { // Continue with other images, don't fail the entire operation continue; } } } // Add the text prompt contentParts.push({ type: "text", text: prompt, }); // Prepare the request payload const requestPayload: any = { model: "google/gemini-2.5-flash-image", messages: [ { role: "user", content: contentParts, } ], modalities: ["image", "text"], }; // Add aspect ratio if provided if (aspectRatio) { requestPayload.image_config = { aspect_ratio: aspectRatio, }; } const response = await this.openai!.chat.completions.create(requestPayload); // Process response const content: any[] = []; const savedFiles: string[] = []; let textContent = ""; // Get appropriate save directory const imagesDir = this.getImagesDirectory(); await fs.mkdir(imagesDir, { recursive: true, mode: 0o755 }); const message = response.choices[0]?.message; if (message) { // Process text content if (message.content && typeof message.content === 'string') { textContent = message.content; } // Process images if ((message as any).images && Array.isArray((message as any).images)) { for (const imageData of (message as any).images) { const imageUrl = imageData.image_url?.url; if (imageUrl && imageUrl.startsWith('data:image/')) { // Extract base64 data from data URL const matches = imageUrl.match(/^data:image\/(\w+);base64,(.+)$/); if (matches && matches[2]) { const base64Data = matches[2]; const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const randomId = Math.random().toString(36).substring(2, 8); const fileName = `edited-${timestamp}-${randomId}.png`; const filePath = path.join(imagesDir, fileName); const imageBuffer = Buffer.from(base64Data, 'base64'); await fs.writeFile(filePath, imageBuffer); savedFiles.push(filePath); this.lastImagePath = filePath; // Add image to MCP response content.push({ type: "image", data: base64Data, mimeType: "image/png", }); } } } } } // Build response let statusText = `🎨 Image edited with OpenRouter!\n\nOriginal: ${imagePath}\nEdit prompt: "${prompt}"`; if (aspectRatio) { statusText += `\nAspect Ratio: ${aspectRatio}`; } if (referenceImages && referenceImages.length > 0) { statusText += `\n\nReference images used:\n${referenceImages.map(f => `- ${f}`).join('\n')}`; } if (textContent) { statusText += `\n\nDescription: ${textContent}`; } if (savedFiles.length > 0) { statusText += `\n\n📁 Edited image saved to:\n${savedFiles.map(f => `- ${f}`).join('\n')}`; statusText += `\n\n💡 View the edited image by:`; statusText += `\n1. Opening the file at the path above`; statusText += `\n2. Clicking on "Called edit_image" in Cursor to expand the MCP call details`; statusText += `\n\n🔄 To continue editing, use: continue_editing`; statusText += `\n📋 To check current image info, use: get_last_image_info`; } else { statusText += `\n\nNote: No edited image was generated.`; statusText += `\n\n💡 Tip: Try running the command again - sometimes the first call needs to warm up the model.`; } content.unshift({ type: "text", text: statusText, }); return { content }; } catch (error) { throw new McpError( ErrorCode.InternalError, `Failed to edit image: ${error instanceof Error ? error.message : String(error)}` ); } }
  • JSON schema defining the input parameters for the 'edit_image' tool, including required imagePath and prompt, optional referenceImages and aspectRatio.
    inputSchema: { type: "object", properties: { imagePath: { type: "string", description: "Full file path to the main image file to edit", }, prompt: { type: "string", description: "Text describing the modifications to make to the existing image", }, referenceImages: { type: "array", items: { type: "string" }, description: "Optional array of file paths to additional reference images to use during editing (e.g., for style transfer, adding elements, etc.)", }, aspectRatio: { type: "string", enum: ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"], description: "Optional aspect ratio for the edited image. Default is 1:1 (1024×1024).", }, }, required: ["imagePath", "prompt"],
  • src/index.ts:97-126 (registration)
    Registration of the 'edit_image' tool in the ListToolsRequestSchema handler, providing name, description, and input schema.
    { name: "edit_image", description: "Edit a SPECIFIC existing image file, optionally using additional reference images. Use this when you have the exact file path of an image to modify.", inputSchema: { type: "object", properties: { imagePath: { type: "string", description: "Full file path to the main image file to edit", }, prompt: { type: "string", description: "Text describing the modifications to make to the existing image", }, referenceImages: { type: "array", items: { type: "string" }, description: "Optional array of file paths to additional reference images to use during editing (e.g., for style transfer, adding elements, etc.)", }, aspectRatio: { type: "string", enum: ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"], description: "Optional aspect ratio for the edited image. Default is 1:1 (1024×1024).", }, }, required: ["imagePath", "prompt"], }, },
  • src/index.ts:184-185 (registration)
    Dispatch registration in the CallToolRequestSchema switch statement that routes calls to the editImage handler method.
    case "edit_image": return await this.editImage(request);
  • Helper usage of the editImage handler within the continue_editing tool to reuse the editing logic with the last image path.
    return await this.editImage({ method: "tools/call", params: { name: "edit_image", arguments: { imagePath: this.lastImagePath, prompt: prompt, referenceImages: referenceImages, aspectRatio: aspectRatio } } } as CallToolRequest);

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/WeiYu021/openrouter-image-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server