Skip to main content
Glama

create_image_edit

Edit and generate images using text prompts with OpenAI's GPT Image 1 model. Define inputs like image source, prompt, and settings such as size, quality, and background for precise image customization.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
backgroundNo
imageYes
maskNo
nNo
promptYes
qualityNo
sizeNo
userNo

Implementation Reference

  • The main execution logic for the 'create_image_edit' tool. Converts base64 or file path inputs to temp files, invokes OpenAI's image edit API via curl, processes the base64 response images, saves them to disk, and returns a rich formatted response with images and metadata.
    async (args: CreateImageEditArgs, extra: any) => { try { // The OpenAI SDK expects 'image' and 'mask' to be Node.js ReadStream or Blob. // Since we are receiving base64 strings from the client, we need to convert them. // This is a simplified approach. A robust solution might involve handling file uploads // or different data formats depending on the client's capabilities. // For this implementation, we'll assume base64 and convert to Buffer, which the SDK might accept // or require further processing depending on its exact requirements for file-like objects. // NOTE: The OpenAI SDK's `images.edit` method specifically expects `File` or `Blob` in browser // environments and `ReadableStream` or `Buffer` in Node.js. Converting base64 to Buffer is // the most straightforward approach for a Node.js server receiving base64. // Process image input which can be file paths or base64 strings const imageFiles = []; // Handle different image input formats if (Array.isArray(args.image)) { // Handle array of strings or objects for (const img of args.image) { if (typeof img === 'string') { // Base64 string - create a temporary file const tempFile = path.join(os.tmpdir(), `image-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`); const base64Data = img.replace(/^data:image\/\w+;base64,/, ''); fs.writeFileSync(tempFile, Buffer.from(base64Data, 'base64')); imageFiles.push(tempFile); } else { // Object with filePath - use the file directly imageFiles.push(img.filePath); } } } else if (typeof args.image === 'string') { // Single base64 string - create a temporary file const tempFile = path.join(os.tmpdir(), `image-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`); const base64Data = args.image.replace(/^data:image\/\w+;base64,/, ''); fs.writeFileSync(tempFile, Buffer.from(base64Data, 'base64')); imageFiles.push(tempFile); } else { // Single object with filePath - use the file directly imageFiles.push(args.image.filePath); } // Process mask input which can be a file path or base64 string let maskFile = undefined; if (args.mask) { if (typeof args.mask === 'string') { // Mask is a base64 string - create a temporary file const tempFile = path.join(os.tmpdir(), `mask-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`); const base64Data = args.mask.replace(/^data:image\/\w+;base64,/, ''); fs.writeFileSync(tempFile, Buffer.from(base64Data, 'base64')); maskFile = tempFile; } else { // Mask is an object with filePath - use the file directly maskFile = args.mask.filePath; } } // Use a direct curl command to call the OpenAI API // This is more reliable than using the SDK for file uploads // Create a temporary file to store the response const tempResponseFile = path.join(os.tmpdir(), `response-${Date.now()}.json`); // Build the curl command let curlCommand = `curl -s -X POST "https://api.openai.com/v1/images/edits" -H "Authorization: Bearer ${process.env.OPENAI_API_KEY}"`; // Add the model curlCommand += ` -F "model=gpt-image-1"`; // Add the prompt curlCommand += ` -F "prompt=${args.prompt}"`; // Add the images for (const imageFile of imageFiles) { curlCommand += ` -F "image[]=@${imageFile}"`; } // Add the mask if it exists if (maskFile) { curlCommand += ` -F "mask=@${maskFile}"`; } // Add other parameters if (args.n) curlCommand += ` -F "n=${args.n}"`; if (args.size) curlCommand += ` -F "size=${args.size}"`; if (args.quality) curlCommand += ` -F "quality=${args.quality}"`; if (args.background) curlCommand += ` -F "background=${args.background}"`; if (args.user) curlCommand += ` -F "user=${args.user}"`; // Add output redirection curlCommand += ` > "${tempResponseFile}"`; // Execute the curl command // Use execSync to run the curl command try { console.error(`Executing curl command to edit image...`); execSync(curlCommand, { stdio: ['pipe', 'pipe', 'inherit'] }); console.error(`Curl command executed successfully.`); } catch (error: any) { console.error(`Error executing curl command: ${error.message}`); throw new Error(`Failed to edit image: ${error.message}`); } // Read the response from the temporary file let responseJson; try { responseJson = fs.readFileSync(tempResponseFile, 'utf8'); console.error(`Response file read successfully.`); } catch (error: any) { console.error(`Error reading response file: ${error.message}`); throw new Error(`Failed to read response file: ${error.message}`); } // Parse the response let responseData; try { responseData = JSON.parse(responseJson); console.error(`Response parsed successfully.`); // Check if the response contains an error if (responseData.error) { console.error(`OpenAI API returned an error:`, responseData.error); const errorMessage = responseData.error.message || 'Unknown API error'; const errorType = responseData.error.type || 'api_error'; const errorCode = responseData.error.code || responseData.error.status || 'unknown'; throw { message: errorMessage, type: errorType, code: errorCode, response: { data: responseData } }; } } catch (error: any) { // If the error is from our API error check, rethrow it if (error.response && error.response.data) { throw error; } console.error(`Error parsing response: ${error.message}`); throw new Error(`Failed to parse response: ${error.message}`); } // Delete the temporary response file try { fs.unlinkSync(tempResponseFile); console.error(`Temporary response file deleted.`); } catch (error: any) { console.error(`Error deleting temporary file: ${error.message}`); // Don't throw an error here, just log it } // Clean up temporary files try { // Delete temporary image files for (const imageFile of imageFiles) { // Only delete files we created (temporary files in the os.tmpdir directory) if (imageFile.startsWith(os.tmpdir())) { try { fs.unlinkSync(imageFile); } catch (e) { /* ignore errors */ } } } // Delete temporary mask file if (maskFile && maskFile.startsWith(os.tmpdir())) { try { fs.unlinkSync(maskFile); } catch (e) { /* ignore errors */ } } } catch (cleanupError) { console.error("Error cleaning up temporary files:", cleanupError); } // No need for a Response-like object anymore since we're using fetch directly // Save images to disk and create response with file paths const savedImages = []; const imageContents = []; const format = "png"; // Assuming png for edits based on common practice if (responseData.data && responseData.data.length > 0) { for (const item of responseData.data) { if (item.b64_json) { // Save the image to disk const imagePath = saveImageToDisk(item.b64_json, format); // Add the saved image info to our response savedImages.push({ path: imagePath, format: format }); // Also include the image content for compatibility imageContents.push({ type: "image" as const, data: item.b64_json, mimeType: `image/${format}` }); } else if (item.url) { console.error(`Image URL: ${item.url}`); console.error("The gpt-image-1 model returned a URL instead of base64 data."); console.error("To view the image, open the URL in your browser."); // Add the URL info to our response savedImages.push({ url: item.url, format: format }); // Include a text message about the URL in the content imageContents.push({ type: "text" as const, text: `Image available at URL: ${item.url}` }); } } } // Create a beautifully formatted response with emojis and details const formatSize = (size: string | undefined) => size || "1024x1024"; const formatQuality = (quality: string | undefined) => quality || "high"; // Get source image information let sourceImageInfo = ""; if (Array.isArray(args.image)) { // Handle array of strings or objects sourceImageInfo = args.image.map((img, index) => { if (typeof img === 'string') { return ` ${index + 1}. Base64 encoded image`; } else { return ` ${index + 1}. ${img.filePath}`; } }).join('\n'); } else if (typeof args.image === 'string') { sourceImageInfo = " Base64 encoded image"; } else { sourceImageInfo = ` ${args.image.filePath}`; } // Get mask information let maskInfo = ""; if (args.mask) { if (typeof args.mask === 'string') { maskInfo = "🎭 **Mask**: Base64 encoded mask applied"; } else { maskInfo = `🎭 **Mask**: Mask from ${args.mask.filePath} applied`; } } // Create a beautiful formatted message const formattedMessage = ` ✏️ **Image Edit Complete!** πŸ–ŒοΈ ✨ **Edit Prompt**: "${args.prompt}" πŸ–ΌοΈ **Source Image${imageFiles.length > 1 ? 's' : ''}**: ${sourceImageInfo} ${maskInfo} πŸ“Š **Edit Parameters**: β€’ Size: ${formatSize(args.size)} β€’ Quality: ${formatQuality(args.quality)} β€’ Number of Results: ${args.n || 1} ${args.background ? `β€’ Background: ${args.background}` : ''} πŸ“ **Edited ${savedImages.length} Image${savedImages.length > 1 ? 's' : ''}**: ${savedImages.map((img, index) => ` ${index + 1}. ${img.path || img.url}`).join('\n')} ${responseData.usage ? `⚑ **Token Usage**: β€’ Total Tokens: ${responseData.usage.total_tokens} β€’ Input Tokens: ${responseData.usage.input_tokens} β€’ Output Tokens: ${responseData.usage.output_tokens}` : ''} πŸ” You can find your edited image${savedImages.length > 1 ? 's' : ''} at the path${savedImages.length > 1 ? 's' : ''} above! `; // Return both the image content and the saved file paths with the beautiful message return { content: [ { type: "text" as const, text: formattedMessage }, ...imageContents ], ...(responseData.usage && { _meta: { usage: { totalTokens: responseData.usage.total_tokens, inputTokens: responseData.usage.input_tokens, outputTokens: responseData.usage.output_tokens, }, savedImages: savedImages } }) }; } catch (error: any) { // Log the full error for debugging console.error("Error creating image edit:", error); // Extract detailed error information const errorCode = error.status || error.code || 'Unknown'; const errorType = error.type || 'Error'; const errorMessage = error.message || 'An unknown error occurred'; // Check for specific error types and provide more helpful messages let detailedError = ''; let suggestedFix = ''; // Handle file-related errors if (errorMessage.includes('ENOENT') || errorMessage.includes('no such file')) { detailedError = '\nπŸ“‹ **Details**: The specified image or mask file could not be found'; suggestedFix = '\nπŸ’‘ **Suggestion**: Verify that the file path is correct and the file exists'; } // Handle permission errors else if (errorMessage.includes('EACCES') || errorMessage.includes('permission denied')) { detailedError = '\nπŸ“‹ **Details**: Permission denied when trying to access the file'; suggestedFix = '\nπŸ’‘ **Suggestion**: Check file permissions or try running with elevated privileges'; } // Handle curl errors else if (errorMessage.includes('curl')) { detailedError = '\nπŸ“‹ **Details**: Error occurred while sending the request to OpenAI API'; suggestedFix = '\nπŸ’‘ **Suggestion**: Check your internet connection and API key'; } // Handle OpenAI API errors else if (error.response) { try { const responseData = error.response.data || {}; if (responseData.error) { detailedError = `\nπŸ“‹ **Details**: ${responseData.error.message || 'No additional details available'}`; // Add parameter errors if available if (responseData.error.param) { detailedError += `\nπŸ” **Parameter**: ${responseData.error.param}`; } // Add code if available if (responseData.error.code) { detailedError += `\nπŸ”’ **Error Code**: ${responseData.error.code}`; } // Add type if available if (responseData.error.type) { detailedError += `\nπŸ“ **Error Type**: ${responseData.error.type}`; } // Provide suggestions based on error type if (responseData.error.type === 'invalid_request_error') { suggestedFix = '\nπŸ’‘ **Suggestion**: Check that your image format is supported (PNG, JPEG) and the prompt is valid'; } else if (responseData.error.type === 'authentication_error') { suggestedFix = '\nπŸ’‘ **Suggestion**: Verify your OpenAI API key is correct and has access to the gpt-image-1 model'; } } } catch (parseError) { detailedError = '\nπŸ“‹ **Details**: Could not parse error details from API response'; } } // If we have a JSON response with an error, try to extract it if (errorMessage.includes('{') && errorMessage.includes('}')) { try { const jsonStartIndex = errorMessage.indexOf('{'); const jsonEndIndex = errorMessage.lastIndexOf('}') + 1; const jsonStr = errorMessage.substring(jsonStartIndex, jsonEndIndex); const jsonError = JSON.parse(jsonStr); if (jsonError.error) { detailedError = `\nπŸ“‹ **Details**: ${jsonError.error.message || 'No additional details available'}`; if (jsonError.error.code) { detailedError += `\nπŸ”’ **Error Code**: ${jsonError.error.code}`; } if (jsonError.error.type) { detailedError += `\nπŸ“ **Error Type**: ${jsonError.error.type}`; } } } catch (e) { // If we can't parse JSON from the error message, just continue } } // Construct a comprehensive error message const fullErrorMessage = `❌ **Image Edit Failed**\n\n⚠️ **Error ${errorCode}**: ${errorType} - ${errorMessage}${detailedError}${suggestedFix}\n\nπŸ”„ Please try again with a different prompt, image, or parameters.`; // Return the detailed error to the client return { content: [{ type: "text", text: fullErrorMessage }], isError: true, _meta: { error: { code: errorCode, type: errorType, message: errorMessage, details: detailedError.replace(/\nπŸ“‹ \*\*Details\*\*: /, ''), suggestion: suggestedFix.replace(/\nπŸ’‘ \*\*Suggestion\*\*: /, ''), raw: JSON.stringify(error, Object.getOwnPropertyNames(error)) } } }; } }
  • Zod schema defining the input parameters for the create_image_edit tool, including flexible image and mask inputs (base64 string, array, or file path objects), prompt, and optional parameters like n, size, quality.
    const createImageEditSchema = z.object({ image: z.union([ z.string(), // Can be base64 encoded image string z.array(z.string()), // Can be array of base64 encoded image strings z.object({ // Can be an object with a file path filePath: z.string(), isBase64: z.boolean().optional().default(false) }), z.array(z.object({ // Can be an array of objects with file paths filePath: z.string(), isBase64: z.boolean().optional().default(false) })) ]), prompt: z.string().max(32000, "Prompt exceeds maximum length for gpt-image-1."), background: z.enum(["transparent", "opaque", "auto"]).optional(), mask: z.union([ z.string(), // Can be base64 encoded mask string z.object({ // Can be an object with a file path filePath: z.string(), isBase64: z.boolean().optional().default(false) }) ]).optional(), n: z.number().int().min(1).max(10).optional(), quality: z.enum(["high", "medium", "low", "auto"]).optional(), size: z.enum(["1024x1024", "1536x1024", "1024x1536", "auto"]).optional(), user: z.string().optional() });
  • src/index.ts:394-803 (registration)
    Registration of the 'create_image_edit' tool with the MCP server using server.tool(), providing name, input schema, title metadata, and the handler function.
    server.tool( "create_image_edit", createImageEditSchema.shape, { title: "Edit existing images using OpenAI's gpt-image-1 model" }, async (args: CreateImageEditArgs, extra: any) => { try { // The OpenAI SDK expects 'image' and 'mask' to be Node.js ReadStream or Blob. // Since we are receiving base64 strings from the client, we need to convert them. // This is a simplified approach. A robust solution might involve handling file uploads // or different data formats depending on the client's capabilities. // For this implementation, we'll assume base64 and convert to Buffer, which the SDK might accept // or require further processing depending on its exact requirements for file-like objects. // NOTE: The OpenAI SDK's `images.edit` method specifically expects `File` or `Blob` in browser // environments and `ReadableStream` or `Buffer` in Node.js. Converting base64 to Buffer is // the most straightforward approach for a Node.js server receiving base64. // Process image input which can be file paths or base64 strings const imageFiles = []; // Handle different image input formats if (Array.isArray(args.image)) { // Handle array of strings or objects for (const img of args.image) { if (typeof img === 'string') { // Base64 string - create a temporary file const tempFile = path.join(os.tmpdir(), `image-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`); const base64Data = img.replace(/^data:image\/\w+;base64,/, ''); fs.writeFileSync(tempFile, Buffer.from(base64Data, 'base64')); imageFiles.push(tempFile); } else { // Object with filePath - use the file directly imageFiles.push(img.filePath); } } } else if (typeof args.image === 'string') { // Single base64 string - create a temporary file const tempFile = path.join(os.tmpdir(), `image-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`); const base64Data = args.image.replace(/^data:image\/\w+;base64,/, ''); fs.writeFileSync(tempFile, Buffer.from(base64Data, 'base64')); imageFiles.push(tempFile); } else { // Single object with filePath - use the file directly imageFiles.push(args.image.filePath); } // Process mask input which can be a file path or base64 string let maskFile = undefined; if (args.mask) { if (typeof args.mask === 'string') { // Mask is a base64 string - create a temporary file const tempFile = path.join(os.tmpdir(), `mask-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`); const base64Data = args.mask.replace(/^data:image\/\w+;base64,/, ''); fs.writeFileSync(tempFile, Buffer.from(base64Data, 'base64')); maskFile = tempFile; } else { // Mask is an object with filePath - use the file directly maskFile = args.mask.filePath; } } // Use a direct curl command to call the OpenAI API // This is more reliable than using the SDK for file uploads // Create a temporary file to store the response const tempResponseFile = path.join(os.tmpdir(), `response-${Date.now()}.json`); // Build the curl command let curlCommand = `curl -s -X POST "https://api.openai.com/v1/images/edits" -H "Authorization: Bearer ${process.env.OPENAI_API_KEY}"`; // Add the model curlCommand += ` -F "model=gpt-image-1"`; // Add the prompt curlCommand += ` -F "prompt=${args.prompt}"`; // Add the images for (const imageFile of imageFiles) { curlCommand += ` -F "image[]=@${imageFile}"`; } // Add the mask if it exists if (maskFile) { curlCommand += ` -F "mask=@${maskFile}"`; } // Add other parameters if (args.n) curlCommand += ` -F "n=${args.n}"`; if (args.size) curlCommand += ` -F "size=${args.size}"`; if (args.quality) curlCommand += ` -F "quality=${args.quality}"`; if (args.background) curlCommand += ` -F "background=${args.background}"`; if (args.user) curlCommand += ` -F "user=${args.user}"`; // Add output redirection curlCommand += ` > "${tempResponseFile}"`; // Execute the curl command // Use execSync to run the curl command try { console.error(`Executing curl command to edit image...`); execSync(curlCommand, { stdio: ['pipe', 'pipe', 'inherit'] }); console.error(`Curl command executed successfully.`); } catch (error: any) { console.error(`Error executing curl command: ${error.message}`); throw new Error(`Failed to edit image: ${error.message}`); } // Read the response from the temporary file let responseJson; try { responseJson = fs.readFileSync(tempResponseFile, 'utf8'); console.error(`Response file read successfully.`); } catch (error: any) { console.error(`Error reading response file: ${error.message}`); throw new Error(`Failed to read response file: ${error.message}`); } // Parse the response let responseData; try { responseData = JSON.parse(responseJson); console.error(`Response parsed successfully.`); // Check if the response contains an error if (responseData.error) { console.error(`OpenAI API returned an error:`, responseData.error); const errorMessage = responseData.error.message || 'Unknown API error'; const errorType = responseData.error.type || 'api_error'; const errorCode = responseData.error.code || responseData.error.status || 'unknown'; throw { message: errorMessage, type: errorType, code: errorCode, response: { data: responseData } }; } } catch (error: any) { // If the error is from our API error check, rethrow it if (error.response && error.response.data) { throw error; } console.error(`Error parsing response: ${error.message}`); throw new Error(`Failed to parse response: ${error.message}`); } // Delete the temporary response file try { fs.unlinkSync(tempResponseFile); console.error(`Temporary response file deleted.`); } catch (error: any) { console.error(`Error deleting temporary file: ${error.message}`); // Don't throw an error here, just log it } // Clean up temporary files try { // Delete temporary image files for (const imageFile of imageFiles) { // Only delete files we created (temporary files in the os.tmpdir directory) if (imageFile.startsWith(os.tmpdir())) { try { fs.unlinkSync(imageFile); } catch (e) { /* ignore errors */ } } } // Delete temporary mask file if (maskFile && maskFile.startsWith(os.tmpdir())) { try { fs.unlinkSync(maskFile); } catch (e) { /* ignore errors */ } } } catch (cleanupError) { console.error("Error cleaning up temporary files:", cleanupError); } // No need for a Response-like object anymore since we're using fetch directly // Save images to disk and create response with file paths const savedImages = []; const imageContents = []; const format = "png"; // Assuming png for edits based on common practice if (responseData.data && responseData.data.length > 0) { for (const item of responseData.data) { if (item.b64_json) { // Save the image to disk const imagePath = saveImageToDisk(item.b64_json, format); // Add the saved image info to our response savedImages.push({ path: imagePath, format: format }); // Also include the image content for compatibility imageContents.push({ type: "image" as const, data: item.b64_json, mimeType: `image/${format}` }); } else if (item.url) { console.error(`Image URL: ${item.url}`); console.error("The gpt-image-1 model returned a URL instead of base64 data."); console.error("To view the image, open the URL in your browser."); // Add the URL info to our response savedImages.push({ url: item.url, format: format }); // Include a text message about the URL in the content imageContents.push({ type: "text" as const, text: `Image available at URL: ${item.url}` }); } } } // Create a beautifully formatted response with emojis and details const formatSize = (size: string | undefined) => size || "1024x1024"; const formatQuality = (quality: string | undefined) => quality || "high"; // Get source image information let sourceImageInfo = ""; if (Array.isArray(args.image)) { // Handle array of strings or objects sourceImageInfo = args.image.map((img, index) => { if (typeof img === 'string') { return ` ${index + 1}. Base64 encoded image`; } else { return ` ${index + 1}. ${img.filePath}`; } }).join('\n'); } else if (typeof args.image === 'string') { sourceImageInfo = " Base64 encoded image"; } else { sourceImageInfo = ` ${args.image.filePath}`; } // Get mask information let maskInfo = ""; if (args.mask) { if (typeof args.mask === 'string') { maskInfo = "🎭 **Mask**: Base64 encoded mask applied"; } else { maskInfo = `🎭 **Mask**: Mask from ${args.mask.filePath} applied`; } } // Create a beautiful formatted message const formattedMessage = ` ✏️ **Image Edit Complete!** πŸ–ŒοΈ ✨ **Edit Prompt**: "${args.prompt}" πŸ–ΌοΈ **Source Image${imageFiles.length > 1 ? 's' : ''}**: ${sourceImageInfo} ${maskInfo} πŸ“Š **Edit Parameters**: β€’ Size: ${formatSize(args.size)} β€’ Quality: ${formatQuality(args.quality)} β€’ Number of Results: ${args.n || 1} ${args.background ? `β€’ Background: ${args.background}` : ''} πŸ“ **Edited ${savedImages.length} Image${savedImages.length > 1 ? 's' : ''}**: ${savedImages.map((img, index) => ` ${index + 1}. ${img.path || img.url}`).join('\n')} ${responseData.usage ? `⚑ **Token Usage**: β€’ Total Tokens: ${responseData.usage.total_tokens} β€’ Input Tokens: ${responseData.usage.input_tokens} β€’ Output Tokens: ${responseData.usage.output_tokens}` : ''} πŸ” You can find your edited image${savedImages.length > 1 ? 's' : ''} at the path${savedImages.length > 1 ? 's' : ''} above! `; // Return both the image content and the saved file paths with the beautiful message return { content: [ { type: "text" as const, text: formattedMessage }, ...imageContents ], ...(responseData.usage && { _meta: { usage: { totalTokens: responseData.usage.total_tokens, inputTokens: responseData.usage.input_tokens, outputTokens: responseData.usage.output_tokens, }, savedImages: savedImages } }) }; } catch (error: any) { // Log the full error for debugging console.error("Error creating image edit:", error); // Extract detailed error information const errorCode = error.status || error.code || 'Unknown'; const errorType = error.type || 'Error'; const errorMessage = error.message || 'An unknown error occurred'; // Check for specific error types and provide more helpful messages let detailedError = ''; let suggestedFix = ''; // Handle file-related errors if (errorMessage.includes('ENOENT') || errorMessage.includes('no such file')) { detailedError = '\nπŸ“‹ **Details**: The specified image or mask file could not be found'; suggestedFix = '\nπŸ’‘ **Suggestion**: Verify that the file path is correct and the file exists'; } // Handle permission errors else if (errorMessage.includes('EACCES') || errorMessage.includes('permission denied')) { detailedError = '\nπŸ“‹ **Details**: Permission denied when trying to access the file'; suggestedFix = '\nπŸ’‘ **Suggestion**: Check file permissions or try running with elevated privileges'; } // Handle curl errors else if (errorMessage.includes('curl')) { detailedError = '\nπŸ“‹ **Details**: Error occurred while sending the request to OpenAI API'; suggestedFix = '\nπŸ’‘ **Suggestion**: Check your internet connection and API key'; } // Handle OpenAI API errors else if (error.response) { try { const responseData = error.response.data || {}; if (responseData.error) { detailedError = `\nπŸ“‹ **Details**: ${responseData.error.message || 'No additional details available'}`; // Add parameter errors if available if (responseData.error.param) { detailedError += `\nπŸ” **Parameter**: ${responseData.error.param}`; } // Add code if available if (responseData.error.code) { detailedError += `\nπŸ”’ **Error Code**: ${responseData.error.code}`; } // Add type if available if (responseData.error.type) { detailedError += `\nπŸ“ **Error Type**: ${responseData.error.type}`; } // Provide suggestions based on error type if (responseData.error.type === 'invalid_request_error') { suggestedFix = '\nπŸ’‘ **Suggestion**: Check that your image format is supported (PNG, JPEG) and the prompt is valid'; } else if (responseData.error.type === 'authentication_error') { suggestedFix = '\nπŸ’‘ **Suggestion**: Verify your OpenAI API key is correct and has access to the gpt-image-1 model'; } } } catch (parseError) { detailedError = '\nπŸ“‹ **Details**: Could not parse error details from API response'; } } // If we have a JSON response with an error, try to extract it if (errorMessage.includes('{') && errorMessage.includes('}')) { try { const jsonStartIndex = errorMessage.indexOf('{'); const jsonEndIndex = errorMessage.lastIndexOf('}') + 1; const jsonStr = errorMessage.substring(jsonStartIndex, jsonEndIndex); const jsonError = JSON.parse(jsonStr); if (jsonError.error) { detailedError = `\nπŸ“‹ **Details**: ${jsonError.error.message || 'No additional details available'}`; if (jsonError.error.code) { detailedError += `\nπŸ”’ **Error Code**: ${jsonError.error.code}`; } if (jsonError.error.type) { detailedError += `\nπŸ“ **Error Type**: ${jsonError.error.type}`; } } } catch (e) { // If we can't parse JSON from the error message, just continue } } // Construct a comprehensive error message const fullErrorMessage = `❌ **Image Edit Failed**\n\n⚠️ **Error ${errorCode}**: ${errorType} - ${errorMessage}${detailedError}${suggestedFix}\n\nπŸ”„ Please try again with a different prompt, image, or parameters.`; // Return the detailed error to the client return { content: [{ type: "text", text: fullErrorMessage }], isError: true, _meta: { error: { code: errorCode, type: errorType, message: errorMessage, details: detailedError.replace(/\nπŸ“‹ \*\*Details\*\*: /, ''), suggestion: suggestedFix.replace(/\nπŸ’‘ \*\*Suggestion\*\*: /, ''), raw: JSON.stringify(error, Object.getOwnPropertyNames(error)) } } }; } } );

Other Tools

Related Tools

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/CLOUDWERX-DEV/gpt-image-1-mcp'

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