Skip to main content
Glama
t0ster
by t0ster

generate_meme

Create custom memes with text overlays using pre-configured templates. Fill specific text placeholders for each meme type to generate shareable content.

Instructions

Generate a meme with custom text overlays.

Each meme type has specific named text placeholders that must be filled. Use the 'get_meme_info' tool to see available memes and their placeholder requirements.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
meme_nameYesThe type of meme to generate
textsYesDictionary like {"placeholder_name": "Your text here"}. To skip a placeholder, use an empty string explicitly.

Implementation Reference

  • Primary handler function for the 'generate_meme' MCP tool. Includes registration via @mcp.tool(), input schema via Annotated/Field, validation logic, delegation to image generation helper, and response formatting.
    @mcp.tool()
    async def generate_meme(
        meme_name: Annotated[str, Field(description="The type of meme to generate")],
        texts: Annotated[
            dict[str, str],
            Field(
                description=(
                    'Dictionary like {"placeholder_name": "Your text here"}. '
                    "To skip a placeholder, use an empty string explicitly."
                )
            ),
        ],
    ) -> dict:
        """
        Generate a meme with custom text overlays.
    
        Each meme type has specific named text placeholders that must be filled.
        Use the 'get_meme_info' tool to see available memes and their placeholder requirements.
        """
        try:
            meme_configs = get_meme_configs()
            if meme_name not in meme_configs:
                return {
                    "status": "error",
                    "message": f"Unknown meme type: {meme_name}",
                    "available_memes": list(meme_configs.keys()),
                }
    
            config = meme_configs[meme_name]
            expected_keys = set(config.placeholders.keys())
            provided_keys = set(texts.keys())
    
            if provided_keys != expected_keys:
                missing = expected_keys - provided_keys
                extra = provided_keys - expected_keys
                error_parts = []
                if missing:
                    error_parts.append(f"missing: {', '.join(missing)}")
                if extra:
                    error_parts.append(f"unexpected: {', '.join(extra)}")
                msg = f"Meme '{meme_name}' placeholder mismatch. {'; '.join(error_parts)}."
                if missing:
                    msg += " To skip a placeholder, use an empty string explicitly."
                raise ValueError(msg)
    
            saved_path = generate_meme_image(meme_name, texts, get_output_dir())
    
            return {
                "status": "success",
                "message": "Meme generated successfully",
                "output_path": str(saved_path.resolve()),
                "meme_type": meme_name,
                "texts_used": texts,
            }
    
        except Exception as e:
            return {
                "status": "error",
                "message": f"Error generating meme: {str(e)}",
                "meme_type": meme_name,
            }
  • Pydantic-based input schema definition for the generate_meme tool parameters: meme_name (str) and texts (dict[str,str]) with descriptions.
    meme_name: Annotated[str, Field(description="The type of meme to generate")],
    texts: Annotated[
        dict[str, str],
        Field(
            description=(
                'Dictionary like {"placeholder_name": "Your text here"}. '
                "To skip a placeholder, use an empty string explicitly."
            )
        ),
    ],
  • app/server.py:96-96 (registration)
    FastMCP tool registration decorator applied to the generate_meme handler.
    @mcp.tool()
  • Core helper function that performs the actual meme image generation using PIL: loads template, handles fonts, text wrapping, drawing with strokes, and saves to file.
    def generate_meme_image(
        meme_type: str, texts: dict[str, str], output_dir: Path
    ) -> Path:
        """Generate a meme image with the given texts."""
        config = get_meme_configs()[meme_type]
        template_path = get_templates_dir() / config.template_file
    
        if not template_path.exists():
            raise FileNotFoundError(f"Template not found: {config.template_file}")
    
        img = Image.open(template_path)
        draw = ImageDraw.Draw(img)
    
        for name, text in texts.items():
            placeholder = config.placeholders[name]
            try:
                font = ImageFont.truetype("Impact", placeholder.font_size)
            except OSError:
                try:
                    font = ImageFont.truetype(str(get_fallback_font_path()), placeholder.font_size)
                except OSError:
                    font = ImageFont.load_default(placeholder.font_size)
    
            lines = wrap_text(draw, text, font, placeholder.max_width)
    
            anchor_map = {"left": "la", "center": "ma", "right": "ra"}
            anchor = anchor_map[placeholder.align]
    
            y_offset = placeholder.y
            for line in lines:
                bbox = draw.textbbox((0, 0), line, font=font)
                line_height = bbox[3] - bbox[1]
    
                draw.text(
                    (placeholder.x, y_offset),
                    line,
                    font=font,
                    fill=placeholder.fill,
                    stroke_width=placeholder.stroke_width,
                    stroke_fill=placeholder.stroke_fill,
                    anchor=anchor,
                )
                y_offset += line_height + int(placeholder.font_size * 0.2)
    
        output_path = output_dir / f"{int(time.time())}_{meme_type}.jpg"
        img.save(output_path, "JPEG")
        return output_path
  • Utility helper for wrapping meme text to fit within specified pixel width, used by generate_meme_image.
    def wrap_text(
        draw: ImageDraw.ImageDraw,
        text: str,
        font: ImageFont.FreeTypeFont | ImageFont.ImageFont,
        max_width: int,
    ) -> list[str]:
        """Wrap text to fit within max_width pixels."""
        lines: list[str] = []
        current_line: list[str] = []
    
        for word in text.upper().split():
            current_line.append(word)
            test_line = " ".join(current_line)
            bbox = draw.textbbox((0, 0), test_line, font=font)
            if bbox[2] - bbox[0] > max_width:
                if len(current_line) > 1:
                    current_line.pop()
                    lines.append(" ".join(current_line))
                    current_line = [word]
                else:
                    lines.append(test_line)
                    current_line = []
    
        if current_line:
            lines.append(" ".join(current_line))
    
        return lines
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/t0ster/meme-generator-mcp'

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