edit_image
Modify existing images using text prompts and optional reference images. Upload an image file and describe changes to apply visual edits.
Instructions
Edit an existing image file with a text prompt, optionally using additional reference images. Use this when you have the exact file path of an image to modify.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| imagePath | Yes | Full file path to the image to edit | |
| prompt | Yes | Text describing the modifications to make (max 10,000 chars) | |
| referenceImages | No | Optional array of file paths to reference images (for style transfer, adding elements, etc.) |
Implementation Reference
- src/index.ts:202-215 (handler)The handleEditImage method is the primary handler for the edit_image tool. It parses and validates the input arguments using EditImageArgsSchema, then delegates to editImageInternal for the actual image processing logic.
private async handleEditImage( request: CallToolRequest ): Promise<CallToolResult> { const parsed = EditImageArgsSchema.safeParse(request.params.arguments); if (!parsed.success) { throw new McpError( ErrorCode.InvalidParams, parsed.error.errors.map((e) => e.message).join("; ") ); } const { imagePath, prompt, referenceImages } = parsed.data; return await this.editImageInternal(imagePath, prompt, referenceImages); } - src/gemini-client.ts:123-180 (handler)The editImage method in GeminiClient handles the core image editing logic. It constructs the API request parts (main image, optional reference images, and prompt text), calls the Gemini API with generateContent, extracts the edited image from the response, saves it to disk, and returns the result.
async editImage( imageBase64: string, imageMimeType: string, prompt: string, referenceImagesData?: Array<{ base64: string; mimeType: string }> ): Promise<ImageResult> { // Build parts: main image + reference images + prompt text const parts: Array<Record<string, unknown>> = [ { inlineData: { data: imageBase64, mimeType: imageMimeType, }, }, ]; if (referenceImagesData) { for (const ref of referenceImagesData) { parts.push({ inlineData: { data: ref.base64, mimeType: ref.mimeType, }, }); } } parts.push({ text: prompt }); const response = (await this.client.models.generateContent({ model: this.model, contents: [{ parts }], config: { responseModalities: ["Text", "Image"], }, })) as GeminiResponse; const { images, text } = extractImagesFromResponse(response); if (images.length === 0) { return { filePath: "", base64Data: "", mimeType: "", textContent: text || "No edited image was generated.", }; } const firstImage = images[0]; const filePath = await saveImage(firstImage.base64, "edited"); return { filePath, base64Data: firstImage.base64, mimeType: firstImage.mimeType, textContent: text, }; } - src/types.ts:9-13 (schema)EditImageArgsSchema defines the input validation schema for the edit_image tool using Zod. It validates: imagePath (required string), prompt (required string, max 10,000 chars), and referenceImages (optional array of strings).
export const EditImageArgsSchema = z.object({ imagePath: z.string().min(1, "Image path is required"), prompt: z.string().min(1, "Prompt is required").max(10_000, "Prompt too long (max 10,000 chars)"), referenceImages: z.array(z.string()).optional(), }); - src/index.ts:47-71 (registration)The edit_image tool is registered with its name, description, and JSON Schema inputSchema defining the expected parameters (imagePath, prompt, referenceImages). This is part of the TOOLS array exposed via the ListToolsRequestSchema handler.
{ name: "edit_image", description: "Edit an existing image file with a text prompt, 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 image to edit", }, prompt: { type: "string", description: "Text describing the modifications to make (max 10,000 chars)", }, referenceImages: { type: "array", items: { type: "string" }, description: "Optional array of file paths to reference images (for style transfer, adding elements, etc.)", }, }, required: ["imagePath", "prompt"], }, }, - src/index.ts:258-324 (helper)The editImageInternal method is a shared helper used by both edit_image and continue_editing tools. It validates file paths against allowed directories, reads and encodes images to base64, processes reference images, calls the Gemini client, and formats the response with the edited image.
private async editImageInternal( imagePath: string, prompt: string, referenceImages?: string[] ): Promise<CallToolResult> { const allowedDirs = getAllowedDirs(); // Validate main image path const validatedPath = validatePath(imagePath, allowedDirs); const imageBuffer = await readImageFile(validatedPath); const mimeType = getMimeType(validatedPath); const imageBase64 = imageBuffer.toString("base64"); // Validate and read reference images const refData: Array<{ base64: string; mimeType: string }> = []; if (referenceImages && referenceImages.length > 0) { for (const refPath of referenceImages) { const validatedRef = validatePath(refPath, allowedDirs); const refBuffer = await readImageFile(validatedRef); const refMime = getMimeType(validatedRef); refData.push({ base64: refBuffer.toString("base64"), mimeType: refMime, }); } } const result = await this.gemini.editImage( imageBase64, mimeType, prompt, refData.length > 0 ? refData : undefined ); if (!result.filePath) { return { content: [{ type: "text", text: result.textContent }], }; } this.lastImagePath = result.filePath; const statusText = [ `Image edited with nanobanana (${this.gemini.getModelName()})`, `Original: ${imagePath}`, `Edit: "${prompt.length > 100 ? prompt.slice(0, 100) + "..." : prompt}"`, referenceImages?.length ? `Reference images: ${referenceImages.length}` : null, result.textContent ? `Description: ${result.textContent}` : null, `Saved to: ${result.filePath}`, `Use continue_editing to make further changes.`, ] .filter(Boolean) .join("\n\n"); return { content: [ { type: "text", text: statusText }, { type: "image", data: result.base64Data, mimeType: result.mimeType, }, ], }; }