Skip to main content
Glama
jau123

MeiGen AI Image Generation MCP

generate_image

Destructive

Generate AI images using MeiGen, local ComfyUI, or OpenAI APIs. Accepts prompts, reference images, and custom settings for style and aspect ratio.

Instructions

Generate an image using AI. Supports MeiGen platform, local ComfyUI, or OpenAI-compatible APIs. Tip: get prompts from get_inspiration() or enhance_prompt(), and use gallery image URLs as referenceImages for style guidance. For Midjourney V8.1, an optional style reference can be passed by appending --sref <code> at the end of the prompt — only when the user provides a Midjourney style code (numeric or text). Do NOT pass URLs or local paths via --sref; for any image-based reference, use the referenceImages parameter instead.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
promptYesThe image generation prompt
modelNoModel name. For OpenAI-compatible providers: any model ID your endpoint supports. For MeiGen: use model IDs from list_models.
sizeNoImage size for OpenAI-compatible providers: "1024x1024", "1536x1024", "auto". MeiGen/ComfyUI: use aspectRatio instead.
aspectRatioNoAspect ratio for MeiGen provider. Use "auto" (recommended, default when omitted) to let MeiGen infer the best ratio from the prompt content. Explicit values: "1:1", "3:4", "4:3", "16:9", "9:16", "21:9", "2:3", "3:2", "4:5", "5:4", etc. (model-dependent). ComfyUI: use comfyui_workflow modify to adjust dimensions before generating.
resolutionNoResolution tier. MeiGen: "1K" / "2K" / "3K" / "4K" — each model supports a subset (list_models reports resolutions when applicable). OpenAI: not used (use size instead).
qualityNoImage quality. MeiGen gpt-image-2: "low" / "medium" / "high". OpenAI-compatible providers also accept "high".
referenceImagesNoImage references for style/content guidance. Accepts both public URLs (http/https) and local file paths. Local files are automatically compressed and uploaded when needed. For ComfyUI: local files are passed directly to the workflow (requires LoadImage node). Sources: gallery URLs from search_gallery/get_inspiration, URLs from previous generate_image results, or local file paths.
providerNoWhich provider to use. Auto-detected from configuration if not specified.
workflowNoComfyUI workflow name to use (from comfyui_workflow list). Uses default workflow if not specified.
negativePromptNoNegative prompt for OpenAI-compatible providers. ComfyUI: use comfyui_workflow modify to set negative prompt in the workflow before generating.

Implementation Reference

  • Main implementation of the generate_image tool. Contains the core handler logic with three provider modes (MeiGen, OpenAI-compatible, ComfyUI), the registerGenerateImage registration function, provider-specific generation functions (generateWithOpenAI, generateWithMeiGen, generateWithComfyUI), helper functions (notify, isLocalPath, resolveLocalPath, resolveReferenceImages), the generateImageSchema, and all supporting logic.
    /**
     * generate_image Tool — requires authentication, three provider modes:
     * Mode A: MeiGen account -> calls MeiGen platform API
     * Mode B: ComfyUI local -> submits workflow to local ComfyUI
     * Mode C: User's own API key -> calls OpenAI-compatible API
     */
    
    import { z } from 'zod'
    import { existsSync } from 'fs'
    import { homedir } from 'os'
    import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
    import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js'
    import type { ServerRequest, ServerNotification } from '@modelcontextprotocol/sdk/types.js'
    import type { MeiGenConfig, ProviderType } from '../config.js'
    import { getDefaultProvider, getAvailableProviders } from '../config.js'
    import type { MeiGenApiClient } from '../lib/meigen-api.js'
    import { OpenAIProvider } from '../lib/providers/openai.js'
    import {
      ComfyUIProvider,
      loadWorkflow,
      listWorkflows,
    } from '../lib/providers/comfyui.js'
    import { sharedApiSemaphore, classifyError } from '../lib/generation-shared.js'
    import { Semaphore } from '../lib/semaphore.js'
    import { saveImageLocally } from '../lib/save-image.js'
    import { addRecentGeneration } from '../lib/preferences.js'
    import { processAndUploadImage } from '../lib/upload.js'
    import { unsafeReferenceUrlReason } from '../lib/url-safety.js'
    
    // MCP 不再硬编码 MeiGen 默认模型。
    // 用户不传 model 时,MeiGen 后端会按 DB is_default=true 的行决定,
    // 响应里回传实际使用的 modelId,MCP 据此展示给用户。
    // 好处: 后端切默认(比如 gpt-image-2 维护/恢复)不需要发 npm 版本。
    
    // API semaphore: shared with generate_video (same backend endpoint, same 12/min rate limit).
    // ComfyUI: serial (local GPU constraint).
    const comfyuiSemaphore = new Semaphore(1)
    
    /** Safe notification — silently ignores if client doesn't support logging */
    async function notify(extra: RequestHandlerExtra<ServerRequest, ServerNotification>, message: string) {
      try {
        await extra.sendNotification({
          method: 'notifications/message',
          params: { level: 'info', logger: 'generate_image', data: message },
        })
      } catch {
        // Client doesn't support logging — ignore
      }
    }
    
    /** Check if a string looks like a local file path (not a URL) */
    function isLocalPath(ref: string): boolean {
      if (ref.startsWith('http://') || ref.startsWith('https://')) return false
      if (ref.startsWith('file://')) return true
      return ref.startsWith('/') || ref.startsWith('~') || /^[A-Z]:[/\\]/i.test(ref)
    }
    
    /** Resolve file:// URIs and ~ prefix to absolute paths */
    function resolveLocalPath(ref: string): string {
      if (ref.startsWith('file://')) return ref.slice(7)
      if (ref.startsWith('~')) return homedir() + ref.slice(1)
      return ref
    }
    
    /**
     * Resolve local file paths in referenceImages to public URLs by uploading them.
     * URLs are passed through unchanged. ComfyUI is skipped (handles local files natively).
     */
    async function resolveReferenceImages(
      refs: string[] | undefined,
      config: MeiGenConfig,
      notifyFn: (msg: string) => Promise<void>,
    ): Promise<string[] | undefined> {
      if (!refs || refs.length === 0) return refs
    
      return Promise.all(refs.map(async (ref) => {
        if (!isLocalPath(ref)) {
          // Defense-in-depth: reject obviously-unsafe URLs (file://, data:, private IPs,
          // cloud metadata) before relaying to the backend. Backend SHOULD also filter
          // but this saves a network round-trip and gives users a clearer error.
          const unsafe = unsafeReferenceUrlReason(ref)
          if (unsafe) {
            throw new Error(`Reference image URL rejected: ${unsafe}. URL: ${ref}`)
          }
          return ref
        }
    
        const filePath = resolveLocalPath(ref)
        if (!existsSync(filePath)) {
          throw new Error(`Reference image not found: ${filePath}`)
        }
    
        await notifyFn(`Uploading reference image: ${filePath}...`)
        const result = await processAndUploadImage(filePath, config)
        return result.publicUrl
      }))
    }
    
    export const generateImageSchema = {
      prompt: z.string().trim().min(1, 'Prompt cannot be empty').describe('The image generation prompt'),
      model: z.string().optional()
        .describe('Model name. For OpenAI-compatible providers: any model ID your endpoint supports. For MeiGen: use model IDs from list_models.'),
      size: z.string().optional()
        .describe('Image size for OpenAI-compatible providers: "1024x1024", "1536x1024", "auto". MeiGen/ComfyUI: use aspectRatio instead.'),
      aspectRatio: z.string().optional()
        .describe('Aspect ratio for MeiGen provider. Use "auto" (recommended, default when omitted) to let MeiGen infer the best ratio from the prompt content. Explicit values: "1:1", "3:4", "4:3", "16:9", "9:16", "21:9", "2:3", "3:2", "4:5", "5:4", etc. (model-dependent). ComfyUI: use comfyui_workflow modify to adjust dimensions before generating.'),
      resolution: z.string().optional()
        .describe('Resolution tier. MeiGen: "1K" / "2K" / "3K" / "4K" — each model supports a subset (list_models reports resolutions when applicable). OpenAI: not used (use size instead).'),
      quality: z.string().optional()
        .describe('Image quality. MeiGen gpt-image-2: "low" / "medium" / "high". OpenAI-compatible providers also accept "high".'),
      referenceImages: z.array(z.string()).optional()
        .describe('Image references for style/content guidance. Accepts both public URLs (http/https) and local file paths. Local files are automatically compressed and uploaded when needed. For ComfyUI: local files are passed directly to the workflow (requires LoadImage node). Sources: gallery URLs from search_gallery/get_inspiration, URLs from previous generate_image results, or local file paths.'),
      provider: z.enum(['openai', 'meigen', 'comfyui']).optional()
        .describe('Which provider to use. Auto-detected from configuration if not specified.'),
      workflow: z.string().optional()
        .describe('ComfyUI workflow name to use (from comfyui_workflow list). Uses default workflow if not specified.'),
      negativePrompt: z.string().optional()
        .describe('Negative prompt for OpenAI-compatible providers. ComfyUI: use comfyui_workflow modify to set negative prompt in the workflow before generating.'),
    }
    
    export function registerGenerateImage(server: McpServer, apiClient: MeiGenApiClient, config: MeiGenConfig) {
      server.tool(
        'generate_image',
        'Generate an image using AI. Supports MeiGen platform, local ComfyUI, or OpenAI-compatible APIs. Tip: get prompts from get_inspiration() or enhance_prompt(), and use gallery image URLs as referenceImages for style guidance. For Midjourney V8.1, an optional style reference can be passed by appending `--sref <code>` at the end of the prompt — only when the user provides a Midjourney style code (numeric or text). Do NOT pass URLs or local paths via --sref; for any image-based reference, use the referenceImages parameter instead.',
        generateImageSchema,
        { readOnlyHint: false, destructiveHint: true },
        async ({ prompt, model, size, aspectRatio, resolution, quality, referenceImages, provider: requestedProvider, workflow, negativePrompt }, extra) => {
          const availableProviders = getAvailableProviders(config)
    
          if (availableProviders.length === 0) {
            return {
              content: [{
                type: 'text' as const,
                text: 'No image generation providers configured. Get a MeiGen API token at https://www.meigen.ai (sign in → Settings → API Keys), then set MEIGEN_API_TOKEN in your environment or MCP config and restart the host. Claude Code users can run /meigen:setup for guided configuration. Alternative providers: OPENAI_API_KEY (any OpenAI-compatible API) or ComfyUI workflow import.',
              }],
              isError: true,
            }
          }
    
          // Determine which provider to use
          let providerType: ProviderType
          if (requestedProvider) {
            if (!availableProviders.includes(requestedProvider)) {
              return {
                content: [{
                  type: 'text' as const,
                  text: `Provider "${requestedProvider}" is not configured. Available: ${availableProviders.join(', ')}`,
                }],
                isError: true,
              }
            }
            providerType = requestedProvider
          } else {
            providerType = getDefaultProvider(config)!
          }
    
          try {
            // Auto-upload local reference images for API providers (ComfyUI handles local files natively)
            const resolvedRefs = providerType !== 'comfyui'
              ? await resolveReferenceImages(referenceImages, config, (msg) => notify(extra, msg))
              : referenceImages
    
            switch (providerType) {
              case 'openai': {
                await sharedApiSemaphore.acquire()
                try {
                  return await generateWithOpenAI(config, prompt, model, size, quality, resolvedRefs)
                } finally {
                  sharedApiSemaphore.release()
                }
              }
              case 'meigen': {
                await sharedApiSemaphore.acquire()
                try {
                  return await generateWithMeiGen(apiClient, prompt, model, aspectRatio, resolution, quality, resolvedRefs, extra)
                } finally {
                  sharedApiSemaphore.release()
                }
              }
              case 'comfyui': {
                await comfyuiSemaphore.acquire()
                try {
                  return await generateWithComfyUI(config, prompt, workflow, referenceImages, extra)
                } finally {
                  comfyuiSemaphore.release()
                }
              }
              default:
                return {
                  content: [{ type: 'text' as const, text: `Unknown provider: ${providerType}` }],
                  isError: true,
                }
            }
          } catch (error) {
            const message = error instanceof Error ? error.message : String(error)
            const guidance = classifyError(message)
            return {
              content: [{
                type: 'text' as const,
                text: `Image generation failed: ${message}\n\n${guidance}`,
              }],
              isError: true,
            }
          }
        }
      )
    }
    
    // ============================================================
    // Provider-specific generation functions
    // ============================================================
    
    async function generateWithOpenAI(
      config: MeiGenConfig,
      prompt: string,
      model?: string,
      size?: string,
      quality?: string,
      referenceImages?: string[],
    ) {
      const provider = new OpenAIProvider(config.openaiApiKey!, config.openaiBaseUrl, config.openaiModel)
      const result = await provider.generate({ prompt, model, size, quality, referenceImages })
    
      const savedPath = saveImageLocally(result.imageBase64, result.mimeType)
    
      addRecentGeneration({ prompt, provider: 'openai', model: model || config.openaiModel })
    
      const lines = [`Image generated successfully.`]
      lines.push(`- Provider: OpenAI-compatible (${model || config.openaiModel})`)
      if (referenceImages?.length) lines.push(`- Reference images: ${referenceImages.length} used`)
      if (savedPath) lines.push(`- Saved to: ${savedPath}`)
    
      return {
        content: [{ type: 'text' as const, text: lines.join('\n') }],
      }
    }
    
    async function generateWithMeiGen(
      apiClient: MeiGenApiClient,
      prompt: string,
      model: string | undefined,
      aspectRatio: string | undefined,
      resolution: string | undefined,
      quality: string | undefined,
      referenceImages: string[] | undefined,
      extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
    ) {
      // 1. Submit generation request
      // model / resolution / quality 不强制填充默认值;缺省时由 MeiGen 后端按 DB 决定
      const genResponse = await apiClient.generateImage({
        prompt,
        modelId: model,
        aspectRatio: aspectRatio || 'auto',
        resolution,
        quality,
        referenceImages,
      })
    
      if (!genResponse.generationId) {
        throw new Error('No generation ID returned')
      }
    
      // Notify: generation submitted
      await notify(extra, 'Image generation submitted, waiting for result...')
    
      // 2. Poll until completed (with progress notifications)
      const status = await apiClient.waitForGeneration(
        genResponse.generationId,
        300_000,
        async (elapsedMs) => {
          await notify(extra, `Still generating... (${Math.round(elapsedMs / 1000)}s elapsed)`)
        },
      )
    
      if (status.status === 'failed') {
        throw new Error(status.error || 'Generation failed')
      }
    
      // Detect video model misuse early — give a clear redirect instead of cryptic "no image URL"
      if (status.mediaType === 'video') {
        throw new Error('This model produces video. Use the generate_video tool with the same model id.')
      }
    
      // Use imageUrls array if available (e.g., V8.1 returns 4 candidates), fall back to imageUrl
      const allImageUrls = status.imageUrls?.length ? status.imageUrls : (status.imageUrl ? [status.imageUrl] : [])
    
      if (allImageUrls.length === 0) {
        throw new Error('No image URL in completed generation')
      }
    
      // Download first image for local save
      const imageRes = await fetch(allImageUrls[0])
      if (!imageRes.ok) {
        throw new Error(`Failed to download generated image: ${imageRes.status}`)
      }
      const buffer = await imageRes.arrayBuffer()
      const base64 = Buffer.from(buffer).toString('base64')
      const mimeType = imageRes.headers.get('content-type') || 'image/jpeg'
    
      const savedPath = saveImageLocally(base64, mimeType)
    
      // 优先用后端返回的 modelId(反映真实使用的模型,包含 is_default 解析结果);
      // 若后端未回传(旧版 backend),用用户显式传入的 model,再 fallback 到占位
      const actualModel = genResponse.modelId || model || 'meigen-default'
    
      addRecentGeneration({ prompt, provider: 'meigen', model: actualModel, aspectRatio })
    
      const lines = [`Image generated successfully.`]
      lines.push(`- Provider: MeiGen (model: ${actualModel})`)
    
      if (allImageUrls.length > 1) {
        lines.push(`- ${allImageUrls.length} candidate images returned:`)
        allImageUrls.forEach((url, i) => lines.push(`  ${i + 1}. ${url}`))
      } else {
        lines.push(`- Image URL: ${allImageUrls[0]}`)
      }
    
      if (savedPath) lines.push(`- Saved to: ${savedPath}`)
      lines.push(`\nYou can use any Image URL as referenceImages for follow-up generation.`)
    
      return {
        content: [{ type: 'text' as const, text: lines.join('\n') }],
      }
    }
    
    async function generateWithComfyUI(
      config: MeiGenConfig,
      prompt: string,
      workflow: string | undefined,
      referenceImages: string[] | undefined,
      extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
    ) {
      // Determine workflow
      const workflows = listWorkflows()
      if (workflows.length === 0) {
        throw new Error('No ComfyUI workflows configured. Use comfyui_workflow import to add one (or on Claude Code, run /meigen:setup for guided configuration).')
      }
    
      const workflowName = workflow || config.comfyuiDefaultWorkflow || workflows[0]
      const workflowData = loadWorkflow(workflowName)
    
      const comfyuiUrl = config.comfyuiUrl || 'http://localhost:8188'
      const provider = new ComfyUIProvider(comfyuiUrl)
    
      // Pre-flight: check if ComfyUI is reachable
      const health = await provider.checkConnection()
      if (!health.ok) {
        throw new Error(`ComfyUI is not reachable at ${comfyuiUrl}. Make sure ComfyUI is running.\nDetails: ${health.error}`)
      }
    
      // Notify: generation submitted
      await notify(extra, `Submitting workflow "${workflowName}" to ComfyUI...`)
      const result = await provider.generate(
        workflowData,
        prompt,
        { referenceImages },
        async (elapsedMs) => {
          await notify(extra, `Still generating... (${Math.round(elapsedMs / 1000)}s elapsed)`)
        },
      )
    
      const savedPath = saveImageLocally(result.imageBase64, result.mimeType)
    
      addRecentGeneration({ prompt, provider: 'comfyui', model: workflowName })
    
      const lines = [`Image generated successfully.`]
      lines.push(`- Provider: ComfyUI (workflow: ${workflowName})`)
      if (savedPath) lines.push(`- Saved to: ${savedPath}`)
      if (result.referenceImageWarning) lines.push(`\nWarning: ${result.referenceImageWarning}`)
    
      return {
        content: [{ type: 'text' as const, text: lines.join('\n') }],
      }
    }
  • generateImageSchema — Zod validation schema defining all input parameters: prompt (required string), model, size, aspectRatio, resolution, quality, referenceImages (array of URLs or local paths), provider (enum: openai/meigen/comfyui), workflow, and negativePrompt.
    export const generateImageSchema = {
      prompt: z.string().trim().min(1, 'Prompt cannot be empty').describe('The image generation prompt'),
      model: z.string().optional()
        .describe('Model name. For OpenAI-compatible providers: any model ID your endpoint supports. For MeiGen: use model IDs from list_models.'),
      size: z.string().optional()
        .describe('Image size for OpenAI-compatible providers: "1024x1024", "1536x1024", "auto". MeiGen/ComfyUI: use aspectRatio instead.'),
      aspectRatio: z.string().optional()
        .describe('Aspect ratio for MeiGen provider. Use "auto" (recommended, default when omitted) to let MeiGen infer the best ratio from the prompt content. Explicit values: "1:1", "3:4", "4:3", "16:9", "9:16", "21:9", "2:3", "3:2", "4:5", "5:4", etc. (model-dependent). ComfyUI: use comfyui_workflow modify to adjust dimensions before generating.'),
      resolution: z.string().optional()
        .describe('Resolution tier. MeiGen: "1K" / "2K" / "3K" / "4K" — each model supports a subset (list_models reports resolutions when applicable). OpenAI: not used (use size instead).'),
      quality: z.string().optional()
        .describe('Image quality. MeiGen gpt-image-2: "low" / "medium" / "high". OpenAI-compatible providers also accept "high".'),
      referenceImages: z.array(z.string()).optional()
        .describe('Image references for style/content guidance. Accepts both public URLs (http/https) and local file paths. Local files are automatically compressed and uploaded when needed. For ComfyUI: local files are passed directly to the workflow (requires LoadImage node). Sources: gallery URLs from search_gallery/get_inspiration, URLs from previous generate_image results, or local file paths.'),
      provider: z.enum(['openai', 'meigen', 'comfyui']).optional()
        .describe('Which provider to use. Auto-detected from configuration if not specified.'),
      workflow: z.string().optional()
        .describe('ComfyUI workflow name to use (from comfyui_workflow list). Uses default workflow if not specified.'),
      negativePrompt: z.string().optional()
        .describe('Negative prompt for OpenAI-compatible providers. ComfyUI: use comfyui_workflow modify to set negative prompt in the workflow before generating.'),
    }
  • registerGenerateImage function that registers the 'generate_image' tool on the MCP server via server.tool(). Maps the schema and handler, dispatches to provider-specific logic based on user selection or auto-detection.
    export function registerGenerateImage(server: McpServer, apiClient: MeiGenApiClient, config: MeiGenConfig) {
      server.tool(
        'generate_image',
        'Generate an image using AI. Supports MeiGen platform, local ComfyUI, or OpenAI-compatible APIs. Tip: get prompts from get_inspiration() or enhance_prompt(), and use gallery image URLs as referenceImages for style guidance. For Midjourney V8.1, an optional style reference can be passed by appending `--sref <code>` at the end of the prompt — only when the user provides a Midjourney style code (numeric or text). Do NOT pass URLs or local paths via --sref; for any image-based reference, use the referenceImages parameter instead.',
        generateImageSchema,
        { readOnlyHint: false, destructiveHint: true },
        async ({ prompt, model, size, aspectRatio, resolution, quality, referenceImages, provider: requestedProvider, workflow, negativePrompt }, extra) => {
          const availableProviders = getAvailableProviders(config)
    
          if (availableProviders.length === 0) {
            return {
              content: [{
                type: 'text' as const,
                text: 'No image generation providers configured. Get a MeiGen API token at https://www.meigen.ai (sign in → Settings → API Keys), then set MEIGEN_API_TOKEN in your environment or MCP config and restart the host. Claude Code users can run /meigen:setup for guided configuration. Alternative providers: OPENAI_API_KEY (any OpenAI-compatible API) or ComfyUI workflow import.',
              }],
              isError: true,
            }
          }
    
          // Determine which provider to use
          let providerType: ProviderType
          if (requestedProvider) {
            if (!availableProviders.includes(requestedProvider)) {
              return {
                content: [{
                  type: 'text' as const,
                  text: `Provider "${requestedProvider}" is not configured. Available: ${availableProviders.join(', ')}`,
                }],
                isError: true,
              }
            }
            providerType = requestedProvider
          } else {
            providerType = getDefaultProvider(config)!
          }
    
          try {
            // Auto-upload local reference images for API providers (ComfyUI handles local files natively)
            const resolvedRefs = providerType !== 'comfyui'
              ? await resolveReferenceImages(referenceImages, config, (msg) => notify(extra, msg))
              : referenceImages
    
            switch (providerType) {
              case 'openai': {
                await sharedApiSemaphore.acquire()
                try {
                  return await generateWithOpenAI(config, prompt, model, size, quality, resolvedRefs)
                } finally {
                  sharedApiSemaphore.release()
                }
              }
              case 'meigen': {
                await sharedApiSemaphore.acquire()
                try {
                  return await generateWithMeiGen(apiClient, prompt, model, aspectRatio, resolution, quality, resolvedRefs, extra)
                } finally {
                  sharedApiSemaphore.release()
                }
              }
              case 'comfyui': {
                await comfyuiSemaphore.acquire()
                try {
                  return await generateWithComfyUI(config, prompt, workflow, referenceImages, extra)
                } finally {
                  comfyuiSemaphore.release()
                }
              }
              default:
                return {
                  content: [{ type: 'text' as const, text: `Unknown provider: ${providerType}` }],
                  isError: true,
                }
            }
          } catch (error) {
            const message = error instanceof Error ? error.message : String(error)
            const guidance = classifyError(message)
            return {
              content: [{
                type: 'text' as const,
                text: `Image generation failed: ${message}\n\n${guidance}`,
              }],
              isError: true,
            }
          }
        }
      )
    }
  • src/server.ts:13-13 (registration)
    Import of registerGenerateImage from the generate-image module in the server.
    import { registerGenerateImage } from './tools/generate-image.js'
  • src/server.ts:275-275 (registration)
    Call to registerGenerateImage(server, apiClient, config) which registers the generate_image tool on the MCP server.
    registerGenerateImage(server, apiClient, config)
Behavior4/5

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

Annotations already indicate destructive nature; description adds behavior like auto-uploading local files for referenceImages, auto-detecting provider, and provider-specific parameter handling. No contradictions with annotations.

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?

Six sentences with clear structure: purpose, tips, specific rule. Every sentence adds value; no redundant information. Highly efficient.

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

Completeness3/5

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

Complex tool with 10 parameters and no output schema. Description covers provider differences, reference image handling, and related tools, but omits expected return value (e.g., image URL). This gap reduces completeness.

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

Parameters4/5

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

Schema covers all 10 parameters with descriptions. Description adds context for Midjourney style code usage, reference image sources, and provider-specific parameter behavior (e.g., size vs aspectRatio).

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

Purpose5/5

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

Description clearly states the tool generates images using AI, listing supported providers (MeiGen, ComfyUI, OpenAI). It distinguishes from sibling tools like generate_video, get_inspiration, and enhance_prompt by providing specific guidance on when to use those instead.

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

Usage Guidelines4/5

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

Provides actionable tips: get prompts from get_inspiration() or enhance_prompt(), use gallery URLs as referenceImages, and a specific rule for Midjourney style codes via --sref. Clearly differentiates from siblings but lacks explicit exclusion scenarios, hence not a 5.

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/jau123/mei-gen-ai-design-mcp'

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