Skip to main content
Glama

generate_image

Generate marketing images with AI-powered templates. Use a text prompt for automatic template selection, or choose a template directly with custom slot values. Supports sizes for social media and more.

Instructions

Generate a marketing image. Two modes: (1) Prompt mode — provide a text prompt and AI picks the template. (2) Direct mode (recommended) — provide templateId + slots for precise control. Use list_templates to see available templates.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
promptNoText prompt describing the image (used in prompt mode)
template_idNoTemplate ID for direct render mode. Use list_templates to see options.
slotsNoTemplate slot values. Keys are slot names, values are strings.
photo_queryNo1-3 word search query for background photo (e.g. 'italian restaurant'). Only used with photo templates when no image_url is provided.
image_urlNoURL of your own image to use as background
sizeNoImage size: '1080x1080' (Instagram, default), '1200x628' (OG/Twitter), '1080x1920' (Stories/Reels), '1200x1200' (Instagram HD), '1280x720' (YouTube)
styleNoVisual style: modern, playful, corporate, dark, minimal, bold
brand_kit_idNoID of a saved brand kit to use for consistent branding
fontNoGoogle Font name to use (e.g. 'Poppins', 'Playfair Display')
logo_urlNoHTTPS URL of a logo to overlay on the image
logo_positionNoPosition of the logo overlay. Default: bottom-right
backgroundNoBackground type: auto (AI decides), photo (force photo search), gradient (no photo)
variantsNoNumber of design variants to generate (1-3). Each variant has different colors/layout.

Implementation Reference

  • Main tool registration and handler function for 'generate_image'. Calls client.generateImage() with parameters from the schema, handles both single image and multi-variant responses, and formats text output.
    import { z } from "zod/v4";
    import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import type { RendrKitClient } from "../api-client.js";
    import type { GeneratedImage } from "../types.js";
    
    export function registerGenerateImageTool(
      server: McpServer,
      client: RendrKitClient,
    ): void {
      server.registerTool(
        "generate_image",
        {
          description:
            "Generate a marketing image. Two modes: (1) Prompt mode — provide a text prompt and AI picks the template. (2) Direct mode (recommended) — provide templateId + slots for precise control. Use list_templates to see available templates.",
          inputSchema: {
            prompt: z
              .string()
              .optional()
              .describe("Text prompt describing the image (used in prompt mode)"),
            template_id: z
              .string()
              .optional()
              .describe(
                "Template ID for direct render mode. Use list_templates to see options.",
              ),
            slots: z
              .record(z.string(), z.string())
              .optional()
              .describe(
                "Template slot values. Keys are slot names, values are strings.",
              ),
            photo_query: z
              .string()
              .optional()
              .describe(
                "1-3 word search query for background photo (e.g. 'italian restaurant'). Only used with photo templates when no image_url is provided.",
              ),
            image_url: z
              .string()
              .optional()
              .describe("URL of your own image to use as background"),
            size: z
              .enum(["1080x1080", "1200x628", "1080x1920", "1200x1200", "1280x720"])
              .optional()
              .describe(
                "Image size: '1080x1080' (Instagram, default), '1200x628' (OG/Twitter), '1080x1920' (Stories/Reels), '1200x1200' (Instagram HD), '1280x720' (YouTube)",
              ),
            style: z
              .enum(["modern", "playful", "corporate", "dark", "minimal", "bold"])
              .optional()
              .describe(
                "Visual style: modern, playful, corporate, dark, minimal, bold",
              ),
            brand_kit_id: z
              .string()
              .optional()
              .describe(
                "ID of a saved brand kit to use for consistent branding",
              ),
            font: z
              .string()
              .optional()
              .describe("Google Font name to use (e.g. 'Poppins', 'Playfair Display')"),
            logo_url: z
              .string()
              .optional()
              .describe("HTTPS URL of a logo to overlay on the image"),
            logo_position: z
              .enum(["top-left", "top-right", "bottom-left", "bottom-right"])
              .optional()
              .describe("Position of the logo overlay. Default: bottom-right"),
            background: z
              .enum(["auto", "photo", "gradient"])
              .optional()
              .describe("Background type: auto (AI decides), photo (force photo search), gradient (no photo)"),
            variants: z
              .number()
              .optional()
              .describe("Number of design variants to generate (1-3). Each variant has different colors/layout."),
          },
        },
        async ({ prompt, template_id, slots, photo_query, image_url, size, style, brand_kit_id, font, logo_url, logo_position, background, variants }) => {
          try {
            const result = await client.generateImage({
              prompt,
              templateId: template_id,
              slots,
              photoQuery: photo_query,
              imageUrl: image_url,
              size,
              style,
              brandKitId: brand_kit_id,
              font,
              logoUrl: logo_url,
              logoPosition: logo_position,
              background,
              variants,
            });
    
            // Variants > 1 returns { images: [...] } instead of a single image
            if (variants && variants > 1) {
              const multi = result as unknown as { images: GeneratedImage[] };
              const lines = multi.images.map(
                (img: GeneratedImage, i: number) =>
                  `Variant ${i + 1}: ${img.url} (template: ${img.templateId})`,
              );
              return {
                content: [
                  {
                    type: "text" as const,
                    text: `Generated ${multi.images.length} variants!\n\n${lines.join("\n")}`,
                  },
                ],
              };
            }
    
            return {
              content: [
                {
                  type: "text" as const,
                  text: [
                    `Image generated successfully!`,
                    ``,
                    `URL: ${result.url}`,
                    `ID: ${result.id}`,
                    `Size: ${result.width}x${result.height}`,
                    result.templateId ? `Template: ${result.templateId}` : null,
                    `Style: ${result.style}`,
                    `Prompt: ${result.prompt}`,
                    `Created: ${result.createdAt}`,
                  ].filter(Boolean).join("\n"),
                },
              ],
            };
          } catch (error) {
            const message =
              error instanceof Error ? error.message : String(error);
            return {
              content: [
                {
                  type: "text" as const,
                  text: `Failed to generate image: ${message}`,
                },
              ],
              isError: true,
            };
          }
        },
      );
    }
  • Input schema using Zod validation. Defines all parameters: prompt, template_id, slots, photo_query, image_url, size, style, brand_kit_id, font, logo_url, logo_position, background, variants.
    server.registerTool(
      "generate_image",
      {
        description:
          "Generate a marketing image. Two modes: (1) Prompt mode — provide a text prompt and AI picks the template. (2) Direct mode (recommended) — provide templateId + slots for precise control. Use list_templates to see available templates.",
        inputSchema: {
          prompt: z
            .string()
            .optional()
            .describe("Text prompt describing the image (used in prompt mode)"),
          template_id: z
            .string()
            .optional()
            .describe(
              "Template ID for direct render mode. Use list_templates to see options.",
            ),
          slots: z
            .record(z.string(), z.string())
            .optional()
            .describe(
              "Template slot values. Keys are slot names, values are strings.",
            ),
          photo_query: z
            .string()
            .optional()
            .describe(
              "1-3 word search query for background photo (e.g. 'italian restaurant'). Only used with photo templates when no image_url is provided.",
            ),
          image_url: z
            .string()
            .optional()
            .describe("URL of your own image to use as background"),
          size: z
            .enum(["1080x1080", "1200x628", "1080x1920", "1200x1200", "1280x720"])
            .optional()
            .describe(
              "Image size: '1080x1080' (Instagram, default), '1200x628' (OG/Twitter), '1080x1920' (Stories/Reels), '1200x1200' (Instagram HD), '1280x720' (YouTube)",
            ),
          style: z
            .enum(["modern", "playful", "corporate", "dark", "minimal", "bold"])
            .optional()
            .describe(
              "Visual style: modern, playful, corporate, dark, minimal, bold",
            ),
          brand_kit_id: z
            .string()
            .optional()
            .describe(
              "ID of a saved brand kit to use for consistent branding",
            ),
          font: z
            .string()
            .optional()
            .describe("Google Font name to use (e.g. 'Poppins', 'Playfair Display')"),
          logo_url: z
            .string()
            .optional()
            .describe("HTTPS URL of a logo to overlay on the image"),
          logo_position: z
            .enum(["top-left", "top-right", "bottom-left", "bottom-right"])
            .optional()
            .describe("Position of the logo overlay. Default: bottom-right"),
          background: z
            .enum(["auto", "photo", "gradient"])
            .optional()
            .describe("Background type: auto (AI decides), photo (force photo search), gradient (no photo)"),
          variants: z
            .number()
            .optional()
            .describe("Number of design variants to generate (1-3). Each variant has different colors/layout."),
        },
  • src/server.ts:3-3 (registration)
    Import of registerGenerateImageTool from the generate-image module.
    import { registerGenerateImageTool } from "./tools/generate-image.js";
  • src/server.ts:18-18 (registration)
    Registration call: registerGenerateImageTool(server, client) wires the tool into the MCP server.
    registerGenerateImageTool(server, client);
  • API client helper that sends a POST request to /api/v1/generate with all image generation parameters.
    async generateImage(params: GenerateImageParams): Promise<GeneratedImage> {
      const body: Record<string, unknown> = {};
      if (params.prompt) body.prompt = params.prompt;
      if (params.templateId) body.templateId = params.templateId;
      if (params.slots) body.slots = params.slots;
      if (params.photoQuery) body.photoQuery = params.photoQuery;
      if (params.imageUrl) body.imageUrl = params.imageUrl;
      if (params.size) body.size = params.size;
      if (params.style) body.style = params.style;
      if (params.brandKitId) body.brandKitId = params.brandKitId;
      if (params.font) body.font = params.font;
      if (params.logoUrl) body.logoUrl = params.logoUrl;
      if (params.logoPosition) body.logoPosition = params.logoPosition;
      if (params.background) body.background = params.background;
      if (params.variants) body.variants = params.variants;
      return this.request<GeneratedImage>("POST", "/api/v1/generate", body);
    }
  • TypeScript interface GenerateImageParams defining the typed parameters for the API call.
    export interface GenerateImageParams {
      prompt?: string;
      size?: string;
      style?: string;
      brandKitId?: string;
      templateId?: string;
      slots?: Record<string, string>;
      photoQuery?: string;
      imageUrl?: string;
      font?: string;
      logoUrl?: string;
      logoPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
      background?: "auto" | "photo" | "gradient";
      variants?: number;
    }
  • GeneratedImage interface defining the response shape (id, url, width, height, prompt, style, templateId, createdAt).
    /** Response from the generate image endpoint */
    export interface GeneratedImage {
      id: string;
      url: string;
      width: number;
      height: number;
      prompt: string;
      style: string;
      mode?: "direct" | "prompt";
      templateId?: string;
      createdAt: string;
    }
Behavior2/5

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

No annotations provided; description lacks information on side effects, authentication needs, rate limits, or error handling. Does not disclose what happens to existing data or safety implications.

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?

Extremely concise: two sentences plus a referral to another tool. Front-loaded with purpose, every sentence adds value.

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

Completeness4/5

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

For a tool with 13 parameters and no output schema, the description effectively covers usage modes and cross-tool dependencies. However, lacks return value details and error scenarios.

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

Parameters3/5

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

Schema has 100% description coverage, so baseline is 3. Description adds value by explaining modes and linking to list_templates but does not elaborate beyond schema descriptions.

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?

Clearly states 'Generate a marketing image' and explains two modes (Prompt and Direct), distinguishing from siblings by referencing list_templates.

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

Usage Guidelines5/5

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

Explicitly describes when to use each mode, recommends direct mode for precise control, and directs users to list_templates for options.

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/vbiff/rendr-kit'

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