Skip to main content
Glama

MCPollinations Multimodal MCP Server

imageService.js19.4 kB
/** * Pollinations Image Service * * Functions for interacting with the Pollinations Image API */ /** * Generates an image URL from a text prompt using the Pollinations Image API * * @param {string} prompt - The text description of the image to generate * @param {string} [model='flux'] - Model name to use for generation * @param {number} [seed] - Seed for reproducible results (defaults to random if not specified) * @param {number} [width=1024] - Width of the generated image * @param {number} [height=1024] - Height of the generated image * @param {boolean} [enhance=true] - Whether to enhance the prompt using an LLM before generating * @param {boolean} [safe=false] - Whether to apply content filtering * @param {Object} [authConfig] - Optional authentication configuration {token, referrer} * @returns {Object} - Object containing the image URL and metadata * @note Always includes nologo=true and private=true parameters */ export async function generateImageUrl(prompt, model = 'flux', seed = Math.floor(Math.random() * 1000000), width = 1024, height = 1024, enhance = true, safe = false, authConfig = null) { if (!prompt || typeof prompt !== 'string') { throw new Error('Prompt is required and must be a string'); } // Parameters are now directly passed as function arguments // Build the query parameters const queryParams = new URLSearchParams(); // Always include model (with default 'flux') queryParams.append('model', model); // Add other parameters if (seed !== undefined) queryParams.append('seed', seed); if (width) queryParams.append('width', width); if (height) queryParams.append('height', height); // Add enhance parameter if true if (enhance) queryParams.append('enhance', 'true'); // Add parameters queryParams.append('nologo', 'true'); // Always set nologo to true queryParams.append('private', 'true'); // Always set private to true) queryParams.append('safe', safe.toString()); // Use the customizable safe parameter // Construct the URL const encodedPrompt = encodeURIComponent(prompt); const baseUrl = 'https://image.pollinations.ai'; let url = `${baseUrl}/prompt/${encodedPrompt}`; // Add query parameters const queryString = queryParams.toString(); url += `?${queryString}`; // Return the URL directly, keeping it simple return { imageUrl: url, prompt, width, height, model, seed, enhance, private: true, nologo: true, safe }; } /** * Generates an image from a text prompt and returns the image data as base64 * Saves the image to a file by default * * @param {string} prompt - The text description of the image to generate * @param {string} [model='flux'] - Model name to use for generation * @param {number} [seed] - Seed for reproducible results (defaults to random if not specified) * @param {number} [width=1024] - Width of the generated image * @param {number} [height=1024] - Height of the generated image * @param {boolean} [enhance=true] - Whether to enhance the prompt using an LLM before generating * @param {boolean} [safe=false] - Whether to apply content filtering * @param {string} [outputPath='./mcpollinations-output'] - Directory path where to save the image * @param {string} [fileName] - Name of the file to save (without extension) * @param {string} [format='png'] - Image format to save as (png, jpeg, jpg, webp) * @param {Object} [authConfig] - Optional authentication configuration {token, referrer} * @returns {Promise<Object>} - Object containing the base64 image data, mime type, metadata, and file path if saved * @note Always includes nologo=true and private=true parameters */ export async function generateImage(prompt, model = 'flux', seed = Math.floor(Math.random() * 1000000), width = 1024, height = 1024, enhance = true, safe = false, outputPath = './mcpollinations-output', fileName = '', format = 'png', authConfig = null) { if (!prompt || typeof prompt !== 'string') { throw new Error('Prompt is required and must be a string'); } // First, generate the image URL const urlResult = await generateImageUrl(prompt, model, seed, width, height, enhance, safe, authConfig); try { // Prepare fetch options with optional auth headers const fetchOptions = {}; if (authConfig) { fetchOptions.headers = {}; if (authConfig.token) { fetchOptions.headers['Authorization'] = `Bearer ${authConfig.token}`; } if (authConfig.referrer) { fetchOptions.headers['Referer'] = authConfig.referrer; } } // Fetch the image from the URL const response = await fetch(urlResult.imageUrl, fetchOptions); if (!response.ok) { throw new Error(`Failed to generate image: ${response.statusText}`); } // Get the image data as an ArrayBuffer const imageBuffer = await response.arrayBuffer(); // Convert the ArrayBuffer to a base64 string const base64Data = Buffer.from(imageBuffer).toString('base64'); // Determine the mime type from the response headers or default to image/jpeg const contentType = response.headers.get('content-type') || 'image/jpeg'; // Prepare the result object const result = { data: base64Data, mimeType: contentType, metadata: { prompt: urlResult.prompt, width: urlResult.width, height: urlResult.height, model: urlResult.model, seed: urlResult.seed, enhance: urlResult.enhance, private: urlResult.private, nologo: urlResult.nologo, safe: urlResult.safe } }; // Always save the image to a file // Import required modules const fs = await import('fs'); const path = await import('path'); // Create the output directory if it doesn't exist if (!fs.existsSync(outputPath)) { fs.mkdirSync(outputPath, { recursive: true }); } // Validate the file format const validFormats = ['png', 'jpeg', 'jpg', 'webp']; if (!validFormats.includes(format)) { console.warn(`Invalid format '${format}', defaulting to 'png'`); } const extension = validFormats.includes(format) ? format : 'png'; // Generate a file name if not provided or ensure it's unique let baseFileName = fileName; if (!baseFileName) { // Create a safe filename from the prompt (first 20 chars, alphanumeric only) const safePrompt = prompt.slice(0, 20).replace(/[^a-z0-9]/gi, '_').toLowerCase(); const timestamp = Date.now(); // Add a random component to ensure uniqueness const randomSuffix = Math.floor(Math.random() * 10000).toString().padStart(4, '0'); baseFileName = `${safePrompt}_${timestamp}_${randomSuffix}`; } // Ensure the filename is unique to prevent overwriting let fileNameWithSuffix = baseFileName; let filePath = path.join(outputPath, `${fileNameWithSuffix}.${extension}`); let counter = 1; // If the file already exists, add a numeric suffix while (fs.existsSync(filePath)) { fileNameWithSuffix = `${baseFileName}_${counter}`; filePath = path.join(outputPath, `${fileNameWithSuffix}.${extension}`); counter++; } // Save the image to the file fs.writeFileSync(filePath, Buffer.from(base64Data, 'base64')); // Add the file path to the result result.filePath = filePath; return result; } catch (error) { console.error('Error generating image:', error); throw error; } } /** * Edits or modifies an existing image based on a text prompt * * @param {string} prompt - The text description of how to edit the image * @param {string} imageUrl - URL of the input image to edit * @param {string} [model='kontext'] - Model name to use for editing (kontext recommended for image-to-image) * @param {number} [seed] - Seed for reproducible results (defaults to random if not specified) * @param {number} [width=1024] - Width of the generated image * @param {number} [height=1024] - Height of the generated image * @param {boolean} [enhance=true] - Whether to enhance the prompt using an LLM before generating * @param {boolean} [safe=false] - Whether to apply content filtering * @param {string} [outputPath='./mcpollinations-output'] - Directory path where to save the image * @param {string} [fileName] - Name of the file to save (without extension) * @param {string} [format='png'] - Image format to save as (png, jpeg, jpg, webp) * @param {Object} [authConfig] - Optional authentication configuration {token, referrer} * @returns {Promise<Object>} - Object containing the base64 image data, mime type, metadata, and file path if saved * @note Always includes nologo=true and private=true parameters */ export async function editImage(prompt, imageUrl, model = 'kontext', seed = Math.floor(Math.random() * 1000000), width = 1024, height = 1024, enhance = true, safe = false, outputPath = './mcpollinations-output', fileName = '', format = 'png', authConfig = null) { if (!prompt || typeof prompt !== 'string') { throw new Error('Prompt is required and must be a string'); } if (!imageUrl || typeof imageUrl !== 'string') { throw new Error('Image URL is required and must be a string'); } // Build the query parameters const queryParams = new URLSearchParams(); queryParams.append('model', model); queryParams.append('image', imageUrl); // Add the input image URL if (seed !== undefined) queryParams.append('seed', seed); if (width !== 1024) queryParams.append('width', width); if (height !== 1024) queryParams.append('height', height); // Add enhance parameter if true if (enhance) queryParams.append('enhance', 'true'); // Add parameters queryParams.append('nologo', 'true'); // Always set nologo to true queryParams.append('private', 'true'); // Always set private to true) queryParams.append('safe', safe.toString()); // Use the customizable safe parameter // Construct the URL const encodedPrompt = encodeURIComponent(prompt); const baseUrl = 'https://image.pollinations.ai'; let url = `${baseUrl}/prompt/${encodedPrompt}`; // Add query parameters const queryString = queryParams.toString(); url += `?${queryString}`; try { // Prepare fetch options with optional auth headers const fetchOptions = {}; if (authConfig) { fetchOptions.headers = {}; if (authConfig.token) { fetchOptions.headers['Authorization'] = `Bearer ${authConfig.token}`; } if (authConfig.referrer) { fetchOptions.headers['Referer'] = authConfig.referrer; } } // Fetch the image from the URL const response = await fetch(url, fetchOptions); if (!response.ok) { throw new Error(`Failed to edit image: ${response.statusText}`); } // Get the image data as an ArrayBuffer const imageBuffer = await response.arrayBuffer(); // Convert the ArrayBuffer to a base64 string const base64Data = Buffer.from(imageBuffer).toString('base64'); // Determine the mime type from the response headers or default to image/jpeg const contentType = response.headers.get('content-type') || 'image/jpeg'; // Prepare the result object const result = { data: base64Data, mimeType: contentType, metadata: { prompt, inputImageUrl: imageUrl, width, height, model, seed, enhance, private: true, nologo: true, safe } }; // Always save the image to a file // Import required modules const fs = await import('fs'); const path = await import('path'); // Create the output directory if it doesn't exist if (!fs.existsSync(outputPath)) { fs.mkdirSync(outputPath, { recursive: true }); } // Generate a filename if not provided let finalFileName = fileName; if (!finalFileName) { // Create a filename from the prompt (first 20 characters) and timestamp const sanitizedPrompt = prompt.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 20); const timestamp = Date.now(); const randomSuffix = Math.floor(Math.random() * 1000); finalFileName = `edited_${sanitizedPrompt}_${timestamp}_${randomSuffix}`; } // Ensure the filename has the correct extension const extension = format.toLowerCase(); if (!finalFileName.endsWith(`.${extension}`)) { finalFileName += `.${extension}`; } // Check if file already exists and add a number suffix if needed let finalFilePath = path.join(outputPath, finalFileName); let counter = 1; while (fs.existsSync(finalFilePath)) { const nameWithoutExt = finalFileName.replace(`.${extension}`, ''); const numberedFileName = `${nameWithoutExt}_${counter}.${extension}`; finalFilePath = path.join(outputPath, numberedFileName); counter++; } // Write the image data to the file fs.writeFileSync(finalFilePath, Buffer.from(base64Data, 'base64')); // Add the file path to the result result.filePath = finalFilePath; return result; } catch (error) { console.error('Error editing image:', error); throw error; } } /** * Generates a new image using an existing image as reference * * @param {string} prompt - The text description of what to generate based on the reference image * @param {string} imageUrl - URL of the reference image * @param {string} [model='kontext'] - Model name to use for generation (kontext recommended for image-to-image) * @param {number} [seed] - Seed for reproducible results (defaults to random if not specified) * @param {number} [width=1024] - Width of the generated image * @param {number} [height=1024] - Height of the generated image * @param {boolean} [enhance=true] - Whether to enhance the prompt using an LLM before generating * @param {boolean} [safe=false] - Whether to apply content filtering * @param {string} [outputPath='./mcpollinations-output'] - Directory path where to save the image * @param {string} [fileName] - Name of the file to save (without extension) * @param {string} [format='png'] - Image format to save as (png, jpeg, jpg, webp) * @param {Object} [authConfig] - Optional authentication configuration {token, referrer} * @returns {Promise<Object>} - Object containing the base64 image data, mime type, metadata, and file path if saved * @note Always includes nologo=true and private=true parameters */ export async function generateImageFromReference(prompt, imageUrl, model = 'kontext', seed = Math.floor(Math.random() * 1000000), width = 1024, height = 1024, enhance = true, safe = false, outputPath = './mcpollinations-output', fileName = '', format = 'png', authConfig = null) { if (!prompt || typeof prompt !== 'string') { throw new Error('Prompt is required and must be a string'); } if (!imageUrl || typeof imageUrl !== 'string') { throw new Error('Reference image URL is required and must be a string'); } // Build the query parameters const queryParams = new URLSearchParams(); queryParams.append('model', model); queryParams.append('image', imageUrl); // Add the reference image URL if (seed !== undefined) queryParams.append('seed', seed); if (width !== 1024) queryParams.append('width', width); if (height !== 1024) queryParams.append('height', height); // Add enhance parameter if true if (enhance) queryParams.append('enhance', 'true'); // Add parameters queryParams.append('nologo', 'true'); // Always set nologo to true queryParams.append('private', 'true'); // Always set private to true) queryParams.append('safe', safe.toString()); // Use the customizable safe parameter // Construct the URL const encodedPrompt = encodeURIComponent(prompt); const baseUrl = 'https://image.pollinations.ai'; let url = `${baseUrl}/prompt/${encodedPrompt}`; // Add query parameters const queryString = queryParams.toString(); url += `?${queryString}`; try { // Prepare fetch options with optional auth headers const fetchOptions = {}; if (authConfig) { fetchOptions.headers = {}; if (authConfig.token) { fetchOptions.headers['Authorization'] = `Bearer ${authConfig.token}`; } if (authConfig.referrer) { fetchOptions.headers['Referer'] = authConfig.referrer; } } // Fetch the image from the URL const response = await fetch(url, fetchOptions); if (!response.ok) { throw new Error(`Failed to generate image from reference: ${response.statusText}`); } // Get the image data as an ArrayBuffer const imageBuffer = await response.arrayBuffer(); // Convert the ArrayBuffer to a base64 string const base64Data = Buffer.from(imageBuffer).toString('base64'); // Determine the mime type from the response headers or default to image/jpeg const contentType = response.headers.get('content-type') || 'image/jpeg'; // Prepare the result object const result = { data: base64Data, mimeType: contentType, metadata: { prompt, referenceImageUrl: imageUrl, width, height, model, seed, enhance, private: true, nologo: true, safe } }; // Always save the image to a file // Import required modules const fs = await import('fs'); const path = await import('path'); // Create the output directory if it doesn't exist if (!fs.existsSync(outputPath)) { fs.mkdirSync(outputPath, { recursive: true }); } // Generate a filename if not provided let finalFileName = fileName; if (!finalFileName) { // Create a filename from the prompt (first 20 characters) and timestamp const sanitizedPrompt = prompt.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 20); const timestamp = Date.now(); const randomSuffix = Math.floor(Math.random() * 1000); finalFileName = `reference_${sanitizedPrompt}_${timestamp}_${randomSuffix}`; } // Ensure the filename has the correct extension const extension = format.toLowerCase(); if (!finalFileName.endsWith(`.${extension}`)) { finalFileName += `.${extension}`; } // Check if file already exists and add a number suffix if needed let finalFilePath = path.join(outputPath, finalFileName); let counter = 1; while (fs.existsSync(finalFilePath)) { const nameWithoutExt = finalFileName.replace(`.${extension}`, ''); const numberedFileName = `${nameWithoutExt}_${counter}.${extension}`; finalFilePath = path.join(outputPath, numberedFileName); counter++; } // Write the image data to the file fs.writeFileSync(finalFilePath, Buffer.from(base64Data, 'base64')); // Add the file path to the result result.filePath = finalFilePath; return result; } catch (error) { console.error('Error generating image from reference:', error); throw error; } } /** * List available image generation models from Pollinations API * * @returns {Promise<Object>} - Object containing the list of available image models */ export async function listImageModels() { try { const response = await fetch('https://image.pollinations.ai/models'); if (!response.ok) { throw new Error(`Failed to list models: ${response.statusText}`); } return await response.json(); } catch (error) { console.error('Error listing image models:', error); throw error; } }

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/pinkpixel-dev/MCPollinations'

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