Skip to main content
Glama
falahgs
by falahgs

generate_storybook_image

Generate 3D cartoon storybook illustrations with matching stories from text prompts. Supports multiple art styles including watercolor, pixel art, hand drawn, and claymation.

Instructions

Generates a 3D style cartoon image with a children's story based on the given prompt

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
promptYesThe prompt describing the storybook scene to generate
fileNameYesBase name for the output files (without extension)
artStyleNoThe art style for the image (default: '3d cartoon')

Implementation Reference

  • Core execution logic for the generate_storybook_image tool: parses args, generates story using Gemini, creates enhanced image prompt, generates and processes image stream, saves image/PNG, story/TXT, HTML preview, opens in browser, returns paths and success message.
    if (toolName === "generate_storybook_image") { const { prompt, fileName, artStyle = "3d cartoon" } = args; // Generate the story first const story = await generateStory(prompt); // Create story filename const storyFileName = `${fileName.replace(/\.[^/.]+$/, '')}_story.txt`; const { savedPath: storyPath } = await saveStoryWithProperPath(story, storyFileName); // Add art style to the prompt const imagePrompt = `Generate a ${artStyle} style image for a children's storybook with this scene: ${prompt}. The image should be colorful, playful, and child-friendly. Use bright colors, appealing characters, and a fun, engaging style that appeals to children.`; const contents = [ { role: 'user', parts: [ { text: imagePrompt, }, ], }, ]; try { const response = await genAI.models.generateContentStream({ model: imageModel, config: imageGenConfig, contents, }); for await (const chunk of response) { if (!chunk.candidates || !chunk.candidates[0].content || !chunk.candidates[0].content.parts) { continue; } if (chunk.candidates[0].content.parts[0].inlineData) { const inlineData = chunk.candidates[0].content.parts[0].inlineData; const buffer = Buffer.from(inlineData.data || '', 'base64'); // Create an output filename with timestamp for uniqueness const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const outputFileName = fileName.endsWith('.png') ? fileName : `${fileName}_${timestamp}.png`; // Find appropriate save location const { savedPath } = await saveImageWithProperPath(buffer, outputFileName); // Create HTML preview that includes the story const htmlContent = ` <!DOCTYPE html> <html> <head> <title>Storybook Preview</title> <style> body { font-family: Arial, sans-serif; margin: 20px; background-color: #f9f9f9; } .container { max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .image-container { text-align: center; margin: 20px 0; } img { max-width: 100%; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .prompt { margin: 10px 0; color: #666; font-style: italic; } .story { margin: 20px 0; line-height: 1.6; white-space: pre-line; } .path { font-family: monospace; margin: 10px 0; font-size: 12px; color: #888; } h1 { color: #4a4a4a; text-align: center; } h2 { color: #5a5a5a; } </style> </head> <body> <div class="container"> <h1>Storybook Image</h1> <div class="prompt">Prompt: ${prompt}</div> <div class="image-container"> <img src="file://${savedPath}" alt="Generated storybook image"> </div> <h2>The Story</h2> <div class="story">${story}</div> <div class="path">Image saved to: ${savedPath}</div> <div class="path">Story saved to: ${storyPath}</div> </div> </body> </html> `; // Create and save HTML file const htmlFileName = `${outputFileName.replace('.png', '')}_preview.html`; const htmlPath = path.join(path.dirname(savedPath), htmlFileName); // Ensure directory exists before writing ensureDirectoryExists(path.dirname(htmlPath)); fs.writeFileSync(htmlPath, htmlContent, 'utf8'); // Try to open in browser try { await openInBrowser(htmlPath); } catch (error) { console.warn('Could not open browser automatically:', error); } return { toolResult: { success: true, imagePath: savedPath, storyPath: storyPath, htmlPath: htmlPath, content: [ { type: "text", text: `Storybook generated successfully!\nImage saved to: ${savedPath}\nStory saved to: ${storyPath}\nPreview HTML: ${htmlPath}` } ], message: "Storybook image and story generated and saved" } }; } } throw new McpError(ErrorCode.InternalError, "No image data received from the API"); } catch (error) { console.error('Error generating image:', error); if (error instanceof Error) { throw new McpError(ErrorCode.InternalError, `Failed to generate image: ${error.message}`); } throw new McpError(ErrorCode.InternalError, 'An unknown error occurred'); }
  • Input schema defining parameters for generate_storybook_image: required prompt and fileName, optional artStyle enum.
    inputSchema: { type: "object", properties: { prompt: { type: "string", description: "The prompt describing the storybook scene to generate" }, fileName: { type: "string", description: "Base name for the output files (without extension)" }, artStyle: { type: "string", description: "The art style for the image (default: '3d cartoon')", enum: ["3d cartoon", "watercolor", "pixel art", "hand drawn", "claymation"] } }, required: ["prompt", "fileName"] }
  • src/index.ts:316-338 (registration)
    Tool specification registered in ListToolsRequestSchema handler, including name, description, and input schema.
    { name: "generate_storybook_image", description: "Generates a 3D style cartoon image with a children's story based on the given prompt", inputSchema: { type: "object", properties: { prompt: { type: "string", description: "The prompt describing the storybook scene to generate" }, fileName: { type: "string", description: "Base name for the output files (without extension)" }, artStyle: { type: "string", description: "The art style for the image (default: '3d cartoon')", enum: ["3d cartoon", "watercolor", "pixel art", "hand drawn", "claymation"] } }, required: ["prompt", "fileName"] } }
  • Helper function generates children's story text using Gemini 'gemini-1.5-pro' model from input prompt.
    async function generateStory(prompt: string): Promise<string> { try { const storyPrompt = `Write a short children's story based on the following prompt: "${prompt}". The story should be engaging, appropriate for young children, have a clear beginning, middle, and end, and convey a positive message or lesson. Keep it under 500 words.`; const contents = [ { role: 'user', parts: [ { text: storyPrompt, }, ], }, ]; // Using the same model, but for text content const response = await genAI.models.generateContentStream({ model: storyModel, contents }); // Collect all text chunks let storyText = ''; for await (const chunk of response) { if (chunk.candidates && chunk.candidates[0].content && chunk.candidates[0].content.parts) { const part = chunk.candidates[0].content.parts[0]; if (typeof part.text === 'string') { storyText += part.text; } } } return storyText || "Once upon a time... (Story generation failed, but the image has been created)"; } catch (error) { console.error('Error generating story:', error); return `Once upon a time... (Story generation failed: ${error instanceof Error ? error.message : String(error)})`; } }
  • Cross-platform helper to save image buffer to 'storybook-images' dir on desktop (if SAVE_TO_DESKTOP=true) or locally, with fallback.
    async function saveImageWithProperPath(buffer: Buffer, fileName: string): Promise<{savedPath: string}> { try { // Check if SAVE_TO_DESKTOP is true if (process.env.SAVE_TO_DESKTOP === "true") { // Desktop saving logic const desktopSaveDir = path.join(getDesktopPath(), 'storybook-images'); debugLog(`Saving to desktop directory: ${desktopSaveDir}`); debugLog(`Platform: ${os.platform()}`); // Ensure save directory exists ensureDirectoryExists(desktopSaveDir); // Create full path and normalize for OS const outputPath = path.normalize(path.join(desktopSaveDir, fileName)); // Save the file fs.writeFileSync(outputPath, buffer); debugLog(`Image saved successfully to: ${outputPath}`); return { savedPath: outputPath }; } else { // Save locally in the server directory const serverDir = process.cwd(); const localSaveDir = path.join(serverDir, 'storybook-images'); debugLog(`Saving to server directory: ${localSaveDir}`); // Ensure output directory exists ensureDirectoryExists(localSaveDir); // Create full path and normalize for OS const outputPath = path.normalize(path.join(localSaveDir, fileName)); // Save the file fs.writeFileSync(outputPath, buffer); debugLog(`Image saved successfully to server path: ${outputPath}`); return { savedPath: outputPath }; } } catch (error) { console.error('Error saving image:', error); // Fallback to output directory const fallbackDir = path.join(process.cwd(), 'output'); ensureDirectoryExists(fallbackDir); const fallbackPath = path.join(fallbackDir, fileName); fs.writeFileSync(fallbackPath, buffer); debugLog(`Fallback save to: ${fallbackPath}`); return { savedPath: fallbackPath }; } }

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/falahgs/MCP-Storybook-Image-Generator'

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