Koskamo

Meme Studio MCP

An MCP server for Meme Studio that allows AI agents to search a catalog of meme templates, retrieve template details, and create memes using templates or user-uploaded photos. It supports generating finished images and links to the editor for adjustments, with no account required.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

Meme Studio MCP logo, by mrhyde.devVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-06Operated by mrhyde.dev
MCP endpoint (Streamable HTTP)
https://memes.mrhyde.dev/mcp
Vendor documentation

What its tools do

4 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

4 of 4 have a description · 4 of 4 declare behavior hints · 1 of 4 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Passed Official MCP Registry namespace is tied to mrhyde.dev ·
  • Passed Endpoint is on the registry namespace domain ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Search meme templates by name or keywords
  • Retrieve template details and caption slots
  • Create memes using templates or custom photos
  • Generate links to edit memes in the browser

Source and maintenance

Vendor evidenceRegistry 1.0.0

Protocol and capabilities

Server
meme-studio 1.0.0
MCP protocol negotiated in check
2025-11-25
Tools
4 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": false
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Meme Studio (https://memes.mrhyde.dev) is a meme editor with 1321 meme templates (310 animated), in Spanish and English. You build the meme here; the person opens your link in Meme Studio, adjusts it if they like and downloads it (PNG, or GIF for animated templates) with an invisible watermark. The meme is not stored: the link carries it, except the person's picture. 1. search_templates with the joke or the situation, in any language ("choosing between two options"), or popular_templates for what people use now. Pick the template whose used_for fits the joke, or the person's picture (image, image_url). 2. get_template {"template": id, "image": true} shows the picture with its numbered slots: the boxes where captions go. In panel templates each slot is one panel; read its hint. 3. create_meme {"template": id, "captions": [...]}. Give each caption a slot when the template has slots; otherwise position top or bottom for a single photo, or a box (x, y = top-left corner, width, height, fractions 0 to 1) next to a head or on an object, never over a face. One caption per idea, a few words each, under the slot's fits_chars; never split one sentence across captions. Write in the person's language and set language. The server fits each caption in its box without splitting words, keeps margins, gives similar boxes one size and picks black text on plain light panels and white outlined text on photos; set color or style only to override it. Extras only if they add to the joke: author (their handle, if given), emojis, stickers (pixel_glasses, laser_eye), shapes with text, a filter (deep_fried). Captions and shapes are placed by their top-left corner; emojis and stickers by their center. Emojis go in emojis, not in captions. 4. Look at the preview and the warnings. If the note asks for fixes, or a caption covers a face or sits in the wrong panel, fix it and call create_meme again before giving the person the url. If you cannot see images, use preview: false and image: false.

Tools

4 advertised

search_templates
Advertised by the server during the last successful anonymous check.
Advertised read-only

Search the Meme Studio catalog by name, keywords or what the meme is used for (intent), in Spanish or English. Best matches first, each with what it is used for.

search_templates input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "query"
  ],
  "properties": {
    "limit": {
      "type": "integer",
      "maximum": 20,
      "minimum": 1
    },
    "query": {
      "type": "string",
      "maxLength": 200,
      "minLength": 1,
      "description": "The joke, the situation or the template name, in any language"
    },
    "animated": {
      "type": "boolean",
      "description": "true: only animated templates; false: only still ones"
    }
  }
}
search_templates annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_template
Advertised by the server during the last successful anonymous check.
Advertised read-only

Details of one template: names, what it is used for, tags, size, whether it is animated and its slots (the boxes where captions go). Each slot has fits_chars, about how many characters fit in it at a good size (0 is a small slot for a word or two): keep its caption under that or the text comes out small. With image: true (or show_slots: true) it also returns the picture with the slots outlined and numbered. Instead of template, give your own picture as image (base64) or image_url, as in create_meme: you get the slots found in that picture, the same ones create_meme uses with it.

get_template input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "image": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "string",
          "maxLength": 8388608,
          "minLength": 1
        }
      ],
      "description": "true: also return the picture with the numbered slots. Or your own picture in base64 instead of template, as in create_meme"
    },
    "template": {
      "type": "string",
      "pattern": "^[a-z0-9]{6}$",
      "description": "Template id from search_templates, the same you give create_meme; or give image or image_url instead"
    },
    "image_url": {
      "type": "string",
      "maxLength": 2048,
      "minLength": 1,
      "description": "Your own picture instead of template: an https address the server downloads"
    },
    "show_slots": {
      "type": "boolean",
      "description": "Also return the picture with the numbered slots, the same as image: true"
    }
  }
}
get_template annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
popular_templates
Advertised by the server during the last successful anonymous check.
Advertised read-only

Templates people choose most in Meme Studio: trending this week or most used overall.

popular_templates input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "kind": {
      "enum": [
        "trending",
        "most_used"
      ],
      "type": "string",
      "default": "trending"
    },
    "limit": {
      "type": "integer",
      "maximum": 30,
      "minimum": 1
    },
    "animated": {
      "type": "boolean"
    }
  }
}
popular_templates annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
create_meme
Advertised by the server during the last successful anonymous check.
Advertised read-only

Create a meme on exactly one of: template (a catalog id), image (your own picture in base64 or a data: URL; JPEG, PNG, WebP or GIF, up to 5 MB and 25 megapixels (16 for WebP, 8 for GIF, less for a large progressive JPEG), 100 px or more a side, at most 4:1; a GIF gives its first frame) or image_url (an https address the server downloads). Your own picture is laid out like a template, with slots found in it (see get_template). Captions go in slots, classic top/bottom positions or boxes (fractions of the image, x and y the top-left corner), plus optional author, emojis, stickers, shapes with text and a filter. The server fits and colours every caption, and may write a line break (\n) into a returned caption text, to keep a short word or a number off the end of a line, to keep a quote on one line or to break a long word after an underscore: a returned text sent back as it is comes out the same. With author, the handle goes in the first corner free of other layers, and of faces when it can: bottom right, top right, bottom left, top left. When a top and a bottom caption leave no corner free, the bottom one moves up a little to free one for the handle, given or saved by the person in the studio. Returns the link that opens the meme in Meme Studio (an editor link, never an image source), what each caption got, warnings and a picture: picture "preview" (800 px to check, the default with a template) or "final" (the finished meme at 1200 px with the invisible watermark, like the studio download; the default with your own picture, because the link cannot carry it and only reopens the captions). For a file on disk, with a terminal, do not paste its base64 yourself: pipe the tools/call JSON from the shell into curl --data-binary @-, without a temporary copy of the picture, to the server's /mcp (Content-Type: application/json, Accept: application/json, text/event-stream; no initialize needed), then decode the data of the image item in result.content from base64 into a file for the person.

create_meme input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "captions"
  ],
  "properties": {
    "image": {
      "type": "string",
      "maxLength": 8388608,
      "minLength": 1,
      "description": "Your own picture instead of a template: JPEG, PNG, WebP or GIF in base64 (a data: URL works too), up to 5 MB and 25 megapixels (16 for WebP, 8 for GIF, less for a large progressive JPEG)"
    },
    "author": {
      "type": "string",
      "maxLength": 25,
      "minLength": 1,
      "description": "The person's handle, with or without @, only if they gave it"
    },
    "emojis": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "emoji",
          "center_x",
          "center_y"
        ],
        "properties": {
          "angle": {
            "type": "number",
            "maximum": 180,
            "minimum": -180
          },
          "emoji": {
            "enum": [
              "😂",
              "🤣",
              "😭",
              "💀",
              "🔥",
              "👀",
              "🤡",
              "😎",
              "🙄",
              "😳",
              "🥲",
              "😡",
              "🤔",
              "😱",
              "🤯",
              "🥵",
              "🥶",
              "😈",
              "🗿",
              "👍",
              "👎",
              "👏",
              "🙏",
              "💪",
              "🤝",
              "👌",
              "💯",
              "❤️",
              "❤",
              "💔",
              "✨",
              "🎉",
              "🚀",
              "💩",
              "👑",
              "💸",
              "🍿",
              "☕",
              "🐐",
              "🧢",
              "🧠",
              "✅",
              "❌",
              "⚠️",
              "⚠",
              "📈",
              "📉",
              "🎯"
            ],
            "type": "string",
            "description": "One of the emojis Meme Studio offers"
          },
          "width": {
            "type": "number",
            "maximum": 0.6,
            "minimum": 0.04,
            "description": "Fraction of the width"
          },
          "center_x": {
            "type": "number",
            "maximum": 1,
            "minimum": 0
          },
          "center_y": {
            "type": "number",
            "maximum": 1,
            "minimum": 0,
            "description": "From the top: 0 is the top edge, 1 the bottom; a larger value moves it down"
          }
        }
      },
      "maxItems": 8
    },
    "filter": {
      "enum": [
        "grayscale",
        "sepia",
        "invert",
        "contrast",
        "brightness",
        "saturation",
        "pixelate",
        "blur",
        "deep_fried",
        "vignette"
      ],
      "type": "string"
    },
    "shapes": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "shape",
          "x",
          "y",
          "width",
          "height"
        ],
        "properties": {
          "x": {
            "type": "number",
            "maximum": 1,
            "minimum": 0,
            "description": "Left edge"
          },
          "y": {
            "type": "number",
            "maximum": 1,
            "minimum": 0,
            "description": "Top edge"
          },
          "flip": {
            "type": "boolean",
            "description": "Mirror it; the bubble tail goes to the right"
          },
          "text": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1,
            "description": "Text written inside the shape"
          },
          "angle": {
            "type": "number",
            "maximum": 45,
            "minimum": -45
          },
          "color": {
            "anyOf": [
              {
                "enum": [
                  "white",
                  "black",
                  "yellow"
                ],
                "type": "string"
              },
              {
                "type": "string",
                "pattern": "^#[0-9a-f]{6}$"
              }
            ],
            "description": "white, black, yellow or #rrggbb"
          },
          "shape": {
            "enum": [
              "bubble",
              "rect",
              "rounded",
              "ellipse",
              "arrow",
              "star",
              "heart",
              "diamond",
              "triangle"
            ],
            "type": "string"
          },
          "width": {
            "type": "number",
            "maximum": 1,
            "minimum": 0.04
          },
          "height": {
            "type": "number",
            "maximum": 1,
            "minimum": 0.04
          },
          "opacity": {
            "type": "number",
            "maximum": 1,
            "minimum": 0.1
          },
          "text_color": {
            "anyOf": [
              {
                "enum": [
                  "auto",
                  "white",
                  "yellow",
                  "black"
                ],
                "type": "string"
              },
              {
                "type": "string",
                "pattern": "^#[0-9a-f]{6}$"
              }
            ]
          }
        }
      },
      "maxItems": 6
    },
    "picture": {
      "enum": [
        "preview",
        "final"
      ],
      "type": "string",
      "description": "preview: 800 px to check (the default with a template); final: the finished meme at 1200 px (the default with image or image_url)"
    },
    "preview": {
      "type": "boolean",
      "description": "false: return no picture"
    },
    "captions": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "x": {
            "type": "number",
            "maximum": 1,
            "minimum": 0,
            "description": "Left edge of the box, fraction of the width"
          },
          "y": {
            "type": "number",
            "maximum": 1,
            "minimum": 0,
            "description": "Top edge of the box, fraction of the height"
          },
          "font": {
            "enum": [
              "impact",
              "arial"
            ],
            "type": "string",
            "default": "impact"
          },
          "slot": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 40,
                "minLength": 1
              },
              {
                "type": "integer",
                "maximum": 12,
                "minimum": 1
              }
            ],
            "description": "Slot number or name from get_template"
          },
          "text": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1,
            "description": "The caption, under the fits_chars of its slot. \\n forces a line break. It is written in capitals"
          },
          "align": {
            "enum": [
              "center",
              "left",
              "right"
            ],
            "type": "string",
            "default": "center"
          },
          "angle": {
            "type": "number",
            "maximum": 45,
            "minimum": -45,
            "description": "Degrees, clockwise"
          },
          "color": {
            "anyOf": [
              {
                "enum": [
                  "auto",
                  "white",
                  "yellow",
                  "black"
                ],
                "type": "string"
              },
              {
                "type": "string",
                "pattern": "^#[0-9a-f]{6}$"
              }
            ],
            "description": "auto, white, yellow, black or #rrggbb"
          },
          "style": {
            "enum": [
              "auto",
              "outline",
              "plain",
              "box"
            ],
            "type": "string",
            "default": "auto",
            "description": "outline, plain or box (text on a solid box)"
          },
          "width": {
            "type": "number",
            "maximum": 1,
            "minimum": 0.08,
            "description": "Box width, fraction of the width (0.9 by default)"
          },
          "height": {
            "type": "number",
            "maximum": 1,
            "minimum": 0.03,
            "description": "Box height, fraction of the height"
          },
          "max_size": {
            "type": "number",
            "maximum": 2,
            "minimum": 0.4,
            "description": "Largest text size, 1 = the usual meme size"
          },
          "position": {
            "enum": [
              "top",
              "bottom",
              "middle"
            ],
            "type": "string",
            "description": "Classic placement on a single photo; ignored with slot or x and y"
          }
        }
      },
      "maxItems": 12,
      "minItems": 1
    },
    "language": {
      "enum": [
        "es",
        "en"
      ],
      "type": "string",
      "default": "es",
      "description": "Language of the person: es opens the Spanish studio, en the English one"
    },
    "stickers": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "sticker",
          "center_x",
          "center_y"
        ],
        "properties": {
          "flip": {
            "type": "boolean"
          },
          "angle": {
            "type": "number",
            "maximum": 180,
            "minimum": -180
          },
          "width": {
            "type": "number",
            "maximum": 1,
            "minimum": 0.04,
            "description": "Fraction of the width"
          },
          "sticker": {
            "enum": [
              "pixel_glasses",
              "laser_eye"
            ],
            "type": "string"
          },
          "center_x": {
            "type": "number",
            "maximum": 1,
            "minimum": 0
          },
          "center_y": {
            "type": "number",
            "maximum": 1,
            "minimum": 0,
            "description": "From the top: 0 is the top edge, 1 the bottom; a larger value moves it down"
          }
        }
      },
      "maxItems": 4
    },
    "template": {
      "type": "string",
      "pattern": "^[a-z0-9]{6}$",
      "description": "Template id; or give image or image_url instead"
    },
    "image_url": {
      "type": "string",
      "maxLength": 2048,
      "minLength": 1,
      "description": "Your own picture instead of a template: an https address the server downloads"
    },
    "filter_strength": {
      "type": "number",
      "maximum": 1,
      "minimum": 0,
      "description": "0 to 1; the studio default when missing"
    }
  }
}
create_meme annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

Not advertised

No resource definitions available.

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (1 of 1 answered).

  1. 2026-11-07: 1 of 1 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
1412 ms
95th percentile latency
1412 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 1412 ms · metadata changed · 4 tool(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http meme-studio-mcp https://memes.mrhyde.dev/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add meme-studio-mcp --url https://memes.mrhyde.dev/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable meme-studio-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "meme-studio-mcp": {
      "url": "https://memes.mrhyde.dev/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "meme-studio-mcp": {
      "type": "streamableHttp",
      "url": "https://memes.mrhyde.dev/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start meme-studio-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "meme-studio-mcp": {
      "type": "http",
      "url": "https://memes.mrhyde.dev/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http meme-studio-mcp https://memes.mrhyde.dev/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://memes.mrhyde.dev/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "meme-studio-mcp": {
      "serverUrl": "https://memes.mrhyde.dev/mcp"
    }
  }
}

Let your agent find its tools

Find servers like Meme Studio MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run Meme Studio MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing