edit_image
Modify images by describing changes in text. Upload an encoded image and specify edits to transform visual content according to your instructions.
Instructions
Edit an image using a text prompt. Send a base64-encoded image and describe the desired changes.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | Description of the edits to apply | |
| image | Yes | Base64-encoded source image | |
| mimeType | No | MIME type of the source image | image/png |
| model | No | Image model to use (Nano Banana Pro by default) | gemini-3-pro-image-preview |
| aspectRatio | No | Aspect ratio of the output image | 1:1 |
| imageSize | No | Output image resolution | 1K |
Implementation Reference
- src/tools/edit-image.ts:8-64 (handler)Main implementation of the edit_image tool. Contains the register function with tool metadata, input schema definition (lines 14-21), and the async handler function (lines 28-63) that processes image editing requests using Google's GenAI API.export function register(server: McpServer, ai: GoogleGenAI): void { server.registerTool( 'edit_image', { title: 'Edit Image', description: 'Edit an image using a text prompt. Send a base64-encoded image and describe the desired changes.', inputSchema: { prompt: z.string().min(1).describe('Description of the edits to apply'), image: z.string().min(1).describe('Base64-encoded source image'), mimeType: z.enum(['image/png', 'image/jpeg', 'image/webp']).default('image/png').describe('MIME type of the source image'), model: ImageModel.default('gemini-3-pro-image-preview').describe('Image model to use (Nano Banana Pro by default)'), aspectRatio: AspectRatio.default('1:1').describe('Aspect ratio of the output image'), imageSize: ImageSize.default('1K').describe('Output image resolution'), }, annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true, }, }, async ({ prompt, image, mimeType, model, aspectRatio, imageSize }) => { try { const response = await ai.models.generateContent({ model, contents: [ { text: prompt }, { inlineData: { mimeType, data: image } }, ], config: { responseModalities: ['TEXT', 'IMAGE'], imageConfig: { aspectRatio, imageSize }, }, }); const result = extractImageFromResponse(response); if (!result) { return { content: [{ type: 'text' as const, text: 'No edited image was produced. Try a different prompt.' }], isError: true, }; } if (!validateImageSize(result.data)) { return { content: [{ type: 'text' as const, text: 'Edited image exceeds size limit. Try a smaller imageSize.' }], isError: true, }; } return { content: [{ type: 'image' as const, data: result.data, mimeType: result.mimeType }], }; } catch (error) { return formatToolError(error); } }, );
- src/tools/edit-image.ts:14-21 (schema)Input schema definition for edit_image tool. Defines prompt, image, mimeType, model, aspectRatio, and imageSize parameters with Zod validation.inputSchema: { prompt: z.string().min(1).describe('Description of the edits to apply'), image: z.string().min(1).describe('Base64-encoded source image'), mimeType: z.enum(['image/png', 'image/jpeg', 'image/webp']).default('image/png').describe('MIME type of the source image'), model: ImageModel.default('gemini-3-pro-image-preview').describe('Image model to use (Nano Banana Pro by default)'), aspectRatio: AspectRatio.default('1:1').describe('Aspect ratio of the output image'), imageSize: ImageSize.default('1K').describe('Output image resolution'), },
- src/index.ts:9-9 (registration)Import statement for the edit_image tool registration functions.import { register as registerEditImage, registerMulti as registerEditImageMulti } from './tools/edit-image.js';
- src/index.ts:30-31 (registration)Registration of both edit_image and edit_image_multi tools with the MCP server.registerEditImage(server, ai); registerEditImageMulti(server, ai);
- src/utils/image.ts:8-20 (helper)Helper function extractImageFromResponse that extracts the base64 image data and MIME type from the GenAI API response.export function extractImageFromResponse(response: any): { data: string; mimeType: string } | null { const parts = response?.candidates?.[0]?.content?.parts; if (!parts) return null; for (const part of parts) { if (part.inlineData) { return { data: part.inlineData.data, mimeType: part.inlineData.mimeType, }; } } return null; }