Skip to main content
Glama

generate-image

Create images using Orshot templates; auto-detects library or studio templates, maps URLs to image fields, and supports multiple output formats like PNG, JPG, or PDF.

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)
formatNoOutput format for the generated imagepng
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.
responseTypeNoResponse type: base64 data, download URL, or binary dataurl
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.
webhookNoOptional webhook URL to receive notifications (studio templates only)

Implementation Reference

  • src/index.ts:800-1076 (registration)
    Registration of the 'generate-image' MCP tool, including name, description, input schema, and inline asynchronous handler function that implements the core logic.
    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.", { 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)"), }, 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)} \`\`\``, }, ], }; } } );
  • The main execution handler for 'generate-image' tool. Auto-detects library/studio template type, handles input validation, API calls to Orshot endpoints (/v1/generate/images or /v1/studio/render), response formatting with markdown links for URLs or raw JSON.
    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-based input schema defining parameters for the generate-image tool, including optional API key, required templateId, 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)"), },
  • Helper function critical for 'generate-image' auto-detection: determines if a given templateId corresponds to a library or studio template by querying respective API endpoints.
    // 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; } }
  • Helper for studio templates in 'generate-image': automatically maps user-provided modifications to correct template fields, with special logic for detecting and placing image URLs.
    async function autoMapModifications(templateId: string, inputModifications: Record<string, any>, apiKey: string): Promise<Record<string, any>> { if (!config.features.autoMapping) { logger.debug("Auto-mapping is disabled, returning input as-is"); return inputModifications; } try { logger.debug(`Starting auto-mapping for template ${templateId}`); // Get template modifications to understand the expected fields const response = await fetch(`${ORSHOT_API_BASE}/v1/studio/template/modifications?templateId=${templateId}`, { method: "GET", headers: { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json", }, }); if (!response.ok) { logger.warn("Failed to fetch template modifications for auto-mapping", { templateId, status: response.status }); return inputModifications; } const modifications = await response.json(); const modArray = Array.isArray(modifications) ? modifications : []; if (modArray.length === 0) { logger.warn("No modifications found for template, using input as-is", { templateId }); return inputModifications; } logger.debug(`Found ${modArray.length} template modifications`, { templateId, modifications: modArray.map((m: any) => ({ key: m.key || m.id, description: m.description })) }); // Create a mapping object const mappedModifications = { ...inputModifications }; // Helper function to check if a string is a URL const isUrl = (str: string) => { try { const url = new URL(str); return url.protocol === 'https:' || url.protocol === 'http:'; } catch { return false; } }; // Look for URL patterns in input and map to appropriate fields for (const [key, value] of Object.entries(inputModifications)) { if (typeof value === 'string' && isUrl(value)) { // This is a URL - find the best matching modification field const urlMod = modArray.find((mod: any) => { const modKey = (mod.key || mod.id || '').toLowerCase(); const modDesc = (mod.description || '').toLowerCase(); return ( modKey.includes('image') || modKey.includes('url') || modKey.includes('photo') || modKey.includes('picture') || modKey.includes('media') || modKey.includes('src') || modDesc.includes('image') || modDesc.includes('url') || modDesc.includes('photo') || modDesc.includes('picture') || modDesc.includes('media') ); }); if (urlMod) { const urlKey = urlMod.key || urlMod.id; if (urlKey) { // Remove the original key if it was a generic name and add the proper field if (key !== urlKey) { delete mappedModifications[key]; } mappedModifications[urlKey] = value; logger.debug(`Auto-mapped URL to field`, { url: value, field: urlKey, templateId }); } } } } // Special handling: if we have a single URL value but no clear field mapping, // and there's only one image-like field, use that const urlValues = Object.values(inputModifications).filter(v => typeof v === 'string' && isUrl(v)); const imageFields = modArray.filter((mod: any) => { const modKey = (mod.key || mod.id || '').toLowerCase(); const modDesc = (mod.description || '').toLowerCase(); return modKey.includes('image') || modKey.includes('photo') || modKey.includes('picture') || modKey.includes('media') || modKey.includes('url') || modKey.includes('src') || modDesc.includes('image') || modDesc.includes('photo') || modDesc.includes('picture'); }); if (urlValues.length === 1 && imageFields.length === 1) { const urlValue = urlValues[0]; const imageField = imageFields[0]; const fieldKey = imageField.key || imageField.id; if (fieldKey && !mappedModifications[fieldKey]) { mappedModifications[fieldKey] = urlValue; logger.debug(`Auto-mapped single URL to single image field`, { url: urlValue, field: fieldKey, templateId }); } } const mappedFields = Object.keys(mappedModifications).filter(key => key !== Object.keys(inputModifications).find(k => mappedModifications[key] === inputModifications[k])); if (mappedFields.length > 0) { logger.autoMapping(templateId, mappedFields); } logger.debug("Auto-mapping completed", { templateId, mappedModifications }); return mappedModifications; } catch (error) { logger.error("Error in auto-mapping modifications", { templateId, error: error instanceof Error ? error.message : String(error) }); return inputModifications; } }

Other Tools

Related 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