Skip to main content
Glama

generate-image

Generate images from Orshot templates by applying custom modifications to library or studio templates with automatic URL mapping and format options.

Instructions

Generate an image from an Orshot template (automatically detects library vs studio template). For studio templates, automatically maps URLs to appropriate image fields and supports template names.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
apiKeyNoOrshot API key for authentication (optional if set in environment)
templateIdYesThe ID or name of the template to use (will auto-detect if it's library or studio). Numeric IDs are likely studio templates. Studio templates can also be referenced by name.
modificationsNoObject containing modifications/data to apply to the template (works for both library and studio templates). URLs will be auto-mapped to image fields for studio templates.
formatNoOutput format for the generated imagepng
responseTypeNoResponse type: base64 data, download URL, or binary dataurl
webhookNoOptional webhook URL to receive notifications (studio templates only)

Implementation Reference

  • Primary handler function for 'generate-image' tool. Auto-detects library/studio template, auto-maps modifications for studio, calls Orshot API, handles responses with links or raw data.
      async (args) => {
        const { apiKey, templateId, modifications, format, responseType, webhook } = args;
        const actualApiKey = apiKey || DEFAULT_API_KEY;
        
        if (!actualApiKey) {
          return {
            content: [
              {
                type: "text",
                text: "No API key provided. Please provide an API key parameter or set ORSHOT_API_KEY environment variable.",
              },
            ],
          };
        }
    
        // Determine template type
        const templateType = await getTemplateType(templateId, actualApiKey);
        
        if (!templateType) {
          return {
            content: [
              {
                type: "text",
                text: `Template "${templateId}" not found in either library or studio templates. Please check the template ID.`,
              },
            ],
          };
        }
    
        if (templateType === 'library') {
          // Use library template endpoint
          const requestBody = {
            templateId: templateId,
            modifications,
            response: {
              type: responseType,
              format: format
            },
            source: "orshot-mcp-server"
          };
    
          const response = await makeOrShotRequest<OrShotLibraryResponse>(
            `${ORSHOT_API_BASE}/v1/generate/images`,
            {
              method: "POST",
              headers: {
                Authorization: `Bearer ${actualApiKey}`,
              },
              body: JSON.stringify(requestBody),
            }
          );
    
          if (!response) {
            return {
              content: [
                {
                  type: "text",
                  text: "Failed to generate image from library template. Please check your API key and template ID.",
                },
              ],
            };
          }
    
          const { data } = response;
          
          // Create raw response display (truncate data for readability)
          const responseForDisplay = {
            ...response,
            data: response.data ? 
              (response.data.length > 100 ? 
                `${response.data.substring(0, 100)}... (truncated, total length: ${response.data.length})` : 
                response.data) : 
              response.data
          };
          
          // Handle different response types for library templates
          if (responseType === "url" && response.url) {
            return {
              content: [
                {
                  type: "text",
                  text: `Image generated successfully from library template!
    
    šŸ–¼ļø **[View Generated Image](${response.url})**
    
    Template Type: Library
    Task ID: ${response.task_id || 'Not available'}
    Status: ${response.status || 'Unknown'}`,
                },
              ],
            };
          } else if (responseType === "base64" && response.data && typeof response.data === 'string' && response.data.startsWith('data:image/')) {
            return {
              content: [
                {
                  type: "text",
                  text: `Image generated successfully from library template!
    
    **Raw API Response:**
    \`\`\`json
    ${JSON.stringify(responseForDisplay, null, 2)}
    \`\`\``,
                },
              ],
            };
          } else if (responseType === "binary") {
            return {
              content: [
                {
                  type: "text",
                  text: `Image generated successfully from library template!
    
    **Raw API Response:**
    \`\`\`json
    ${JSON.stringify(responseForDisplay, null, 2)}
    \`\`\``,
                },
              ],
            };
          }
          
          // Fallback to text response
          return {
            content: [
              {
                type: "text",
                text: `Image generated successfully from library template!
    
    **Raw API Response:**
    \`\`\`json
    ${JSON.stringify(responseForDisplay, null, 2)}
    \`\`\``,
              },
            ],
          };
        } else {
          // Use studio template endpoint
          
          // Resolve template ID from name if needed
          const resolvedTemplateId = await resolveStudioTemplateId(templateId, actualApiKey);
          if (!resolvedTemplateId) {
            return {
              content: [
                {
                  type: "text",
                  text: `āŒ Studio template "${templateId}" not found. Please check the template ID or name.`,
                },
              ],
            };
          }
          
          // Auto-map modifications based on template structure
          const mappedModifications = await autoMapModifications(resolvedTemplateId, modifications, actualApiKey);
          
          const requestBody: any = {
            templateId: resolvedTemplateId,
            modifications: mappedModifications, // Use auto-mapped modifications
            response: {
              type: responseType,
              format: format
            },
            source: "orshot-mcp-server"
          };
    
          if (webhook) {
            requestBody.webhook = webhook;
          }
    
          const response = await makeOrShotRequest<OrShotStudioResponse>(
            `${ORSHOT_API_BASE}/v1/studio/render`,
            {
              method: "POST",
              headers: {
                Authorization: `Bearer ${actualApiKey}`,
              },
              body: JSON.stringify(requestBody),
            }
          );
    
          if (!response) {
            return {
              content: [
                {
                  type: "text",
                  text: "Failed to generate image from studio template. Please check your API key and template ID.",
                },
              ],
            };
          }
    
          const { data: responseData } = response;
          
          // Create raw response display (truncate data for readability)
          const responseForDisplay = {
            ...response,
            data: response.data ? 
              (response.data.length > 100 ? 
                `${response.data.substring(0, 100)}... (truncated, total length: ${response.data.length})` : 
                response.data) : 
              response.data
          };
          
          // Handle different response types for studio templates
          if (responseType === "url" && response.url) {
            return {
              content: [
                {
                  type: "text",
                  text: `Image generated successfully from studio template!
    
    šŸ–¼ļø **[View Generated Image](${response.url})**
    
    Template Type: Studio
    Task ID: ${response.task_id || 'Not available'}
    Status: ${response.status || 'Unknown'}
    ${webhook ? `Webhook notifications will be sent to: ${webhook}` : ""}`,
                },
              ],
            };
          } else if (responseType === "base64" && response.data && typeof response.data === 'string' && response.data.startsWith('data:image/')) {
            return {
              content: [
                {
                  type: "text",
                  text: `Image generated successfully from studio template!
    
    **Raw API Response:**
    \`\`\`json
    ${JSON.stringify(responseForDisplay, null, 2)}
    \`\`\``,
                },
              ],
            };
          } else if (responseType === "binary") {
            return {
              content: [
                {
                  type: "text",
                  text: `Image generated successfully from studio template!
    
    **Raw API Response:**
    \`\`\`json
    ${JSON.stringify(responseForDisplay, null, 2)}
    \`\`\``,
                },
              ],
            };
          }
          
          // Fallback to text response
          return {
            content: [
              {
                type: "text",
                text: `Image generated successfully from studio template!
    
    **Raw API Response:**
    \`\`\`json
    ${JSON.stringify(responseForDisplay, null, 2)}
    \`\`\``,
              },
            ],
          };
        }
      }
    );
  • Zod input schema defining parameters for the generate-image tool including optional API key, template ID/name, modifications object, output format, response type, and optional webhook.
    {
      apiKey: z.string().optional().describe("Orshot API key for authentication (optional if set in environment)"),
      templateId: z.string().describe("The ID or name of the template to use (will auto-detect if it's library or studio). Numeric IDs are likely studio templates. Studio templates can also be referenced by name."),
      modifications: z.record(z.any()).default({}).describe("Object containing modifications/data to apply to the template (works for both library and studio templates). URLs will be auto-mapped to image fields for studio templates."),
      format: z.enum(["png", "jpg", "pdf"]).default("png").describe("Output format for the generated image"),
      responseType: z.enum(["base64", "url", "binary"]).default("url").describe("Response type: base64 data, download URL, or binary data"),
      webhook: z.string().url().optional().describe("Optional webhook URL to receive notifications (studio templates only)"),
    },
  • src/index.ts:800-802 (registration)
    Registration of the 'generate-image' tool on the MCP server using server.tool() with name, description, schema, and inline handler function.
    server.tool(
      "generate-image",
      "Generate an image from an Orshot template (automatically detects library vs studio template). For studio templates, automatically maps URLs to appropriate image fields and supports template names.",
  • Helper to auto-detect template type (library or studio) by API queries, crucial for generate-image routing.
    // Helper function to determine template type (library vs studio)
    async function getTemplateType(templateId: string, apiKey: string): Promise<'library' | 'studio' | null> {
      try {
        // If it's a numeric ID, it's likely a studio template - check studio first
        if (isLikelyStudioTemplate(templateId)) {
          // Check studio templates first for numeric IDs
          const studioResponse = await fetch(`${ORSHOT_API_BASE}/v1/studio/templates`, {
            headers: {
              "Authorization": `Bearer ${apiKey}`,
              "Content-Type": "application/json",
            },
          });
    
          if (studioResponse.ok) {
            const studioTemplates = await studioResponse.json();
            const templatesArray = Array.isArray(studioTemplates) ? studioTemplates : [];
            
            // Check if templateId exists in studio templates (supports both numeric ID and name matching)
            const isStudioTemplate = templatesArray.some((template: any) => 
              template.id === templateId || 
              template.id === parseInt(templateId) ||
              template.name?.toLowerCase() === templateId.toLowerCase()
            );
            
            if (isStudioTemplate) {
              return 'studio';
            }
          }
        }
    
        // First check if it's a library template
        const libraryResponse = await fetch(`${ORSHOT_API_BASE}/v1/templates`, {
          headers: {
            "Authorization": `Bearer ${apiKey}`,
            "Content-Type": "application/json",
          },
        });
    
        if (libraryResponse.ok) {
          const libraryData = await libraryResponse.json();
          const libraryTemplates = Array.isArray(libraryData) ? libraryData : [];
          
          // Check if templateId exists in library templates
          const isLibraryTemplate = libraryTemplates.some((template: any) => 
            template.id === templateId || template.template_id === templateId
          );
          
          if (isLibraryTemplate) {
            return 'library';
          }
        }
    
        // If not found in library and not numeric, check studio templates (including name matching)
        if (!isLikelyStudioTemplate(templateId)) {
          const studioResponse = await fetch(`${ORSHOT_API_BASE}/v1/studio/templates`, {
            headers: {
              "Authorization": `Bearer ${apiKey}`,
              "Content-Type": "application/json",
            },
          });
    
          if (studioResponse.ok) {
            const studioTemplates = await studioResponse.json();
            const templatesArray = Array.isArray(studioTemplates) ? studioTemplates : [];
            
            // Check if templateId exists in studio templates (supports name matching for non-numeric IDs)
            const isStudioTemplate = templatesArray.some((template: any) => 
              template.id === templateId || 
              template.name?.toLowerCase() === templateId.toLowerCase()
            );
            
            if (isStudioTemplate) {
              return 'studio';
            }
          }
        }
    
        return null; // Template not found in either
      } catch (error) {
        console.error("Error determining template type:", error);
        return null;
      }
    }
  • Core HTTP client helper for all Orshot API calls, used by generate-image handler with retries and logging.
    async function makeOrShotRequest<T>(
      url: string,
      options: RequestInit = {},
      retries: number = config.api.retries
    ): Promise<T | null> {
      let lastError: Error | null = null;
      
      logger.time(`API Request: ${url}`);
      
      for (let attempt = 1; attempt <= retries; attempt++) {
        try {
          const controller = new AbortController();
          const timeoutId = setTimeout(() => controller.abort(), config.api.timeout);
          
          const response = await fetch(url, {
            ...options,
            headers: {
              "Content-Type": "application/json",
              "User-Agent": `${config.server.name}/${config.server.version}`,
              ...options.headers,
            },
            signal: controller.signal,
          });
    
          clearTimeout(timeoutId);
    
          if (!response.ok) {
            const errorText = await response.text();
            let errorMessage = `HTTP ${response.status} ${response.statusText}`;
            
            try {
              const errorData = JSON.parse(errorText);
              errorMessage = errorData.message || errorData.error || errorMessage;
            } catch {
              // Use the raw error text if JSON parsing fails
              errorMessage = errorText || errorMessage;
            }
            
            logger.apiRequest(options.method || 'GET', url, response.status);
            throw new Error(errorMessage);
          }
    
          const result = await response.json();
          logger.apiRequest(options.method || 'GET', url, response.status);
          logger.timeEnd(`API Request: ${url}`);
          return result as T;
        } catch (error) {
          lastError = error instanceof Error ? error : new Error(String(error));
          
          if (error instanceof Error && error.name === 'AbortError') {
            logger.error(`Request timeout on attempt ${attempt}/${retries}`, { url, timeout: config.api.timeout });
          } else {
            logger.error(`Request failed on attempt ${attempt}/${retries}`, { url, error: lastError.message });
          }
          
          // Don't retry for certain error types
          if (error instanceof Error && 
              (error.message.includes('401') || error.message.includes('403') || error.message.includes('404'))) {
            break;
          }
          
          if (attempt < retries) {
            // Exponential backoff with configurable delay
            const delay = Math.pow(2, attempt - 1) * config.api.retryDelay;
            await new Promise(resolve => setTimeout(resolve, delay));
            logger.debug(`Retrying request after ${delay}ms delay`, { url, attempt: attempt + 1, retries });
          }
        }
      }
      
      logger.error("All retry attempts failed", { url, error: lastError?.message });
      logger.timeEnd(`API Request: ${url}`);
      return null;
    }
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions automatic detection and URL mapping for studio templates, which adds some context, but fails to cover critical aspects like authentication requirements (implied by apiKey parameter), rate limits, error handling, or what the tool returns (only hints at responseType). For a tool with 6 parameters and no annotations, this is insufficient.

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

Conciseness4/5

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

The description is appropriately concise with two sentences that are front-loaded with the core functionality. Each sentence adds value: the first states the purpose and auto-detection, the second details studio-specific features. There's no redundant information, though it could be slightly more structured.

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?

Given the tool's complexity (6 parameters, nested objects, no output schema, and no annotations), the description is incomplete. It doesn't explain the output (e.g., what a 'url' response contains), error conditions, or how modifications interact with template types. For a generative tool with multiple parameters and siblings, more context is needed to guide effective use.

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 description coverage is 100%, providing detailed documentation for all parameters. The description adds minimal value beyond the schema, only reiterating that templateId auto-detects library/studio and that modifications work for both types. It doesn't explain parameter interactions or provide usage examples, so it meets the baseline for high schema coverage.

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: 'Generate an image from an Orshot template' with the specific action of automatic detection between library and studio templates. It distinguishes itself from siblings like 'generate-image-from-library' and 'generate-image-from-studio' by handling both types automatically, though it doesn't explicitly contrast with all siblings.

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

Usage Guidelines3/5

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

The description implies when to use this tool by mentioning it 'automatically detects library vs studio template', suggesting it's a general-purpose alternative to the more specific sibling tools. However, it lacks explicit guidance on when to choose this over 'generate-image-from-library' or 'generate-image-from-studio', or any prerequisites like authentication needs.

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/rishimohan/orshot-mcp-server'

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