edit_image
Modify images using text prompts to adjust content, style, or composition while preserving original lighting and visual characteristics.
Instructions
Edit an image using a prompt. Provide one input image via base64 or file path.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| image | Yes | One input image | |
| prompt | Yes | Describe the edit; the model matches original style and lighting. | |
| saveToFilePath | No | Optional path to save the edited image |
Implementation Reference
- src/index.ts:166-179 (handler)The handler function for the 'edit_image' tool. It takes the prompt, image input, and optional save path, calls the shared Gemini API helper, processes the generated image, optionally saves it to file, and returns a content array with text description, image data, and data URL.async (args) => { const { prompt, image, saveToFilePath } = args as { prompt: string; image: InlineImageInput; saveToFilePath?: string }; const results = await callGeminiGenerate({ prompt, images: [image] }); const first = results[0]; const savedPath = await maybeSaveImage(first.imageBase64, first.mimeType, saveToFilePath); const dataUrl = `data:${first.mimeType};base64,${first.imageBase64}`; return { content: [ { type: 'text', text: `Edited image${savedPath ? ` saved to ${savedPath}` : ''}` }, { type: 'image', mimeType: first.mimeType, data: first.imageBase64 }, { type: 'text', text: dataUrl }, ], }; }
- src/index.ts:156-165 (schema)Zod input schema for the 'edit_image' tool defining parameters: prompt (string), image (object with dataBase64/path/mimeType), and optional saveToFilePath.prompt: z.string().describe('Describe the edit; the model matches original style and lighting.'), image: z .object({ dataBase64: z.string().optional().describe('Base64 without data URL prefix'), path: z.string().optional().describe('Path to the input image file'), mimeType: z.string().optional().describe('image/png or image/jpeg'), }) .describe('One input image'), saveToFilePath: z.string().optional().describe('Optional path to save the edited image'), },
- src/index.ts:152-180 (registration)The mcp.tool call that registers the 'edit_image' tool with its name, description, input schema, and handler function.mcp.tool( 'edit_image', 'Edit an image using a prompt. Provide one input image via base64 or file path.', { prompt: z.string().describe('Describe the edit; the model matches original style and lighting.'), image: z .object({ dataBase64: z.string().optional().describe('Base64 without data URL prefix'), path: z.string().optional().describe('Path to the input image file'), mimeType: z.string().optional().describe('image/png or image/jpeg'), }) .describe('One input image'), saveToFilePath: z.string().optional().describe('Optional path to save the edited image'), }, async (args) => { const { prompt, image, saveToFilePath } = args as { prompt: string; image: InlineImageInput; saveToFilePath?: string }; const results = await callGeminiGenerate({ prompt, images: [image] }); const first = results[0]; const savedPath = await maybeSaveImage(first.imageBase64, first.mimeType, saveToFilePath); const dataUrl = `data:${first.mimeType};base64,${first.imageBase64}`; return { content: [ { type: 'text', text: `Edited image${savedPath ? ` saved to ${savedPath}` : ''}` }, { type: 'image', mimeType: first.mimeType, data: first.imageBase64 }, { type: 'text', text: dataUrl }, ], }; } );
- src/index.ts:73-112 (helper)Core helper function that handles the API call to Gemini for image editing/generation. Converts inputs to API format, sends POST request, parses response, extracts image data. Used by edit_image and other image tools.async function callGeminiGenerate(request: GenerateRequest): Promise<{ imageBase64: string; mimeType: string }[]> { const textPart = { text: request.prompt }; const imageParts = await toInlineDataParts(request.images); const parts = [textPart as any, ...imageParts]; const fetchResponse = await fetch(`${GEMINI_ENDPOINT}?key=${encodeURIComponent(GEMINI_API_KEY)}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ contents: [ { parts, }, ], }), }); if (!fetchResponse.ok) { const text = await fetchResponse.text(); throw new Error(`Gemini API error ${fetchResponse.status}: ${text}`); } const json = (await fetchResponse.json()) as GeminiGenerateResponse; const images: { imageBase64: string; mimeType: string }[] = []; const first = json.candidates?.[0]?.content?.parts ?? []; for (const part of first) { if (part.inlineData?.data) { images.push({ imageBase64: part.inlineData.data, mimeType: part.inlineData.mimeType ?? 'image/png' }); } } if (images.length === 0) { // Fallback: if API returns interleaved text etc. throw new Error('No image data returned by Gemini API'); } return images; }
- src/index.ts:114-123 (helper)Helper function to optionally save the generated/edited image to a file path, determining extension from mimeType if needed.async function maybeSaveImage(base64: string, mimeType: string, targetPath?: string): Promise<string | undefined> { if (!targetPath) return undefined; const { writeFile } = await import('node:fs/promises'); const { extname } = await import('node:path'); const extension = extname(targetPath) || (mimeType === 'image/jpeg' ? '.jpg' : '.png'); const resolved = resolve(targetPath.endsWith(extension) ? targetPath : `${targetPath}${extension}`); const buffer = Buffer.from(base64, 'base64'); await writeFile(resolved, buffer); return resolved; }