Skip to main content
Glama
mikeyny

Image Generation MCP Server

by mikeyny

generate-image

Create custom images from text descriptions with configurable settings for size, format, and quality. Save generated images to specified directories for various applications.

Instructions

Generate an image based on a prompt

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
promptYes
output_dirYesFull absolute path to output directory. For Windows, use double backslashes like 'C:\\Users\\name\\path'. For Unix/Mac use '/path/to/dir'. Always use the proper path otherwise you will get an error.
filenameNoBase filename to save the image(s) with
go_fastNo
megapixelsNo
num_outputsNo
aspect_ratioNo
output_formatNo
output_qualityNo
num_inference_stepsNo

Implementation Reference

  • Core handler method of ImageGenerationService that implements the image generation logic: caching, calling Replicate API, downloading images, saving to disk, and error handling.
    async generateImages(params: ImageGenerationParams): Promise<ImageGenerationResponse> {
      const startTime = Date.now();
    
      try {
        // Check cache first
        const cacheKey = this.generateCacheKey(params);
        const cached = this.cache.get(cacheKey);
        
        if (cached) {
          // Verify files still exist
          const allFilesExist = cached.response.image_paths.every(path => fs.existsSync(path));
          if (allFilesExist) {
            return {
              ...cached.response,
              metadata: {
                ...cached.response.metadata,
                cache_hit: true
              }
            };
          }
          // If files don't exist, remove from cache
          this.cache.delete(cacheKey);
        }
    
        // Prepare model input
        const modelInput = {
          prompt: params.prompt,
          go_fast: params.go_fast ?? false,
          megapixels: params.megapixels ?? "1",
          num_outputs: params.num_outputs ?? 1,
          aspect_ratio: params.aspect_ratio ?? "1:1",
          num_inference_steps: params.num_inference_steps ?? 4
        };
    
        // Call Replicate API
        const output = await this.replicate.run(
          this.MODEL,
          { input: modelInput }
        ) as string[];
    
        // Download and save images
        const imagePaths = await this.saveImages(
          output,
          params.output_dir,
          params.output_format ?? 'webp',
          params.output_quality ?? 80,
          params.filename
        );
    
        const endTime = Date.now();
    
        const response: ImageGenerationResponse = {
          image_paths: imagePaths,
          metadata: {
            model: this.MODEL,
            inference_time_ms: endTime - startTime,
            cache_hit: false
          }
        };
    
        // Cache the result
        this.cache.set(cacheKey, {
          response,
          timestamp: Date.now()
        });
    
        return response;
    
      } catch (error: any) {
    
        if (error.response) {
          const apiError = new Error(error.message) as APIError;
          apiError.code = 'API_ERROR';
          apiError.details = {
            message: error.message,
            status: error.response.status
          };
          throw apiError;
        }
    
        const serverError = new Error('Server error occurred') as ServerError;
        serverError.code = 'SERVER_ERROR';
        serverError.details = {
          message: 'Failed to generate or save images',
          system_error: error.message
        };
        throw serverError;
      }
    }
  • src/server.ts:18-52 (registration)
    MCP server tool registration for 'generate-image', including description, Zod input schema, and wrapper handler delegating to ImageGenerationService.
    // Register the image generation tool
    server.tool(
      "generate-image",
      "Generate an image based on a prompt",
      {
        prompt: z.string(),
        output_dir: z.string().describe("Full absolute path to output directory. For Windows, use double backslashes like 'C:\\\\Users\\\\name\\\\path'. For Unix/Mac use '/path/to/dir'. Always use the proper path otherwise you will get an error."),
        filename: z.string().optional().describe("Base filename to save the image(s) with"),
        go_fast: z.boolean().optional(),
        megapixels: z.enum(["1", "2", "4"]).optional(),
        num_outputs: z.number().min(1).max(4).optional(),
        aspect_ratio: z.enum(["1:1", "4:3", "16:9"]).optional(),
        output_format: z.enum(["webp", "png", "jpeg"]).optional(),
        output_quality: z.number().min(1).max(100).optional(),
        num_inference_steps: z.number().min(4).max(20).optional()
      },
      async (params) => {
        try {
          const result = await imageService.generateImages(params);
          return {
            content: [{
              type: "text",
              text: JSON.stringify(result, null, 2)
            }]
          };
        } catch (error: any) {
          return {
            content: [{
              type: "text",
              text: `Error: ${error.message}`
            }]
          };
        }
      }
    );
  • TypeScript interface defining the input parameters for the generate-image tool, used by ImageGenerationService.
    export interface ImageGenerationParams {
      prompt: string;
      output_dir: string;
      filename?: string;
      go_fast?: boolean;
      megapixels?: "1" | "2" | "4";
      num_outputs?: number;
      aspect_ratio?: "1:1" | "4:3" | "16:9";
      output_format?: "webp" | "png" | "jpeg";
      output_quality?: number;
      num_inference_steps?: number;
    }
  • Helper method to download images from URLs (with retries), save them to disk in batches with concurrency limit, and return file paths.
    private async saveImages(
      imageUrls: string[],
      outputDir: string,
      format: 'webp' | 'png' | 'jpeg',
      quality: number,
      baseFilename?: string
    ): Promise<string[]> {
      // Create output directory if it doesn't exist
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true });
      }
    
      // Prepare download tasks
      const downloadTasks = imageUrls.map(async (imageUrl, i) => {
        const filename = baseFilename 
          ? (imageUrls.length > 1 ? `${baseFilename}_${i + 1}.${format}` : `${baseFilename}.${format}`)
          : `output_${i}.${format}`;
        const filePath = path.join(outputDir, filename);
    
        try {
          // Download image with retry mechanism
          const buffer = await this.downloadWithRetry(imageUrl);
          
          // Save image atomically using temporary file
          const tempPath = `${filePath}.tmp`;
          fs.writeFileSync(tempPath, buffer);
          fs.renameSync(tempPath, filePath);
          
          return filePath;
        } catch (error: any) {
          const serverError = new Error('Failed to save image') as ServerError;
          serverError.code = 'SERVER_ERROR';
          serverError.details = {
            message: `Failed to save image ${i}`,
            system_error: error.message
          };
          throw serverError;
        }
      });
    
      // Execute all downloads in parallel with a concurrency limit
      const CONCURRENCY_LIMIT = 3;
      const imagePaths: string[] = [];
      
      for (let i = 0; i < downloadTasks.length; i += CONCURRENCY_LIMIT) {
        const batch = downloadTasks.slice(i, i + CONCURRENCY_LIMIT);
        const results = await Promise.all(batch);
        imagePaths.push(...results);
      }
    
      return imagePaths;
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions the core action (generating images from prompts) but lacks critical behavioral details like whether this is a local or cloud operation, rate limits, authentication requirements, error handling, or what happens when files are saved. The description doesn't contradict annotations since none exist.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise at just 5 words, front-loaded with the core functionality. Every word earns its place, and there's no wasted text or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex tool with 10 parameters, no annotations, no output schema, and low schema description coverage, the description is severely inadequate. It doesn't explain what the tool returns, how outputs are structured, error conditions, or provide enough context for an agent to use it effectively beyond the most basic invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With only 20% schema description coverage, the description must compensate but fails to do so. It mentions 'based on a prompt' which hints at one parameter but doesn't explain the other 9 parameters or their relationships. The description adds minimal value beyond what's already in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with a specific verb ('generate') and resource ('image'), and specifies it's based on a prompt. It's unambiguous about what the tool does, though it doesn't distinguish from siblings since there are none.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives, nor any context about prerequisites or limitations. It simply states what the tool does without indicating appropriate use cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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/mikeyny/ai-image-gen-mcp'

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