build_prompt
Generate Stable Diffusion prompts from character names by analyzing Gelbooru tag frequency data to create accurate image generation strings.
Instructions
Given a character name, returns a ready-to-use image-generation prompt string like 'misty (pokemon), green eyes, orange hair, side ponytail, ...'. Internally calls get_character_tags with caching, then assembles the prompt with tags ordered by frequency (eye → hair → other).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| character_name | Yes | The Gelbooru tag for the character, e.g. 'misty_(pokemon)'. Use underscores as Gelbooru does. | |
| max_images | No | Posts to analyse (default 300). Cached after first fetch. | |
| include_other | No | Whether to include non-eye/hair tags (clothing, accessories, etc.) in the prompt. Default true. |
Implementation Reference
- gelbooru_mcp.py:241-275 (handler)Main handler function _build_prompt that executes the tool logic: fetches character tags via _fetch_character_tags, orders them (eye → hair → other tags), and assembles a ready-to-use image-generation prompt string.
def _build_prompt(character_name: str, max_images: int, include_other: bool) -> Dict[str, Any]: """ Calls _fetch_character_tags and assembles a ready-to-use image-gen prompt string. Tags are ordered: character name → eye → hair → other (highest frequency first). """ tags_result = _fetch_character_tags(character_name, max_images) if "error" in tags_result: return tags_result ct = tags_result["character_tags"] # Human-readable character name: strip _(series) suffix for the label display_name = character_name.replace("_", " ") parts: List[str] = [display_name] parts.extend(e["tag"] for e in ct["eye"]) parts.extend(h["tag"] for h in ct["hair"]) if include_other: parts.extend(o["tag"] for o in ct["other"]) prompt_string = ", ".join(parts) return { "prompt": { "character": display_name, "posts_analysed": ct["posts_analysed"], "cache_hit": ct.get("cache_hit", False), "prompt_string": prompt_string, "tags": { "eye": [e["tag"] for e in ct["eye"]], "hair": [h["tag"] for h in ct["hair"]], "other": [o["tag"] for o in ct["other"]] if include_other else [], }, } } - gelbooru_mcp.py:460-495 (registration)Tool registration definition: declares the build_prompt tool with its name, description, and JSON input schema defining three parameters (character_name, max_images, include_other).
Tool( name="build_prompt", description=( "Given a character name, returns a ready-to-use image-generation prompt " "string like 'misty (pokemon), green eyes, orange hair, side ponytail, ...'. " "Internally calls get_character_tags with caching, then assembles the prompt " "with tags ordered by frequency (eye → hair → other)." ), inputSchema={ "type": "object", "properties": { "character_name": { "type": "string", "description": ( "The Gelbooru tag for the character, e.g. 'misty_(pokemon)'. " "Use underscores as Gelbooru does." ), }, "max_images": { "type": "integer", "description": "Posts to analyse (default 300). Cached after first fetch.", "default": 300, "minimum": 10, }, "include_other": { "type": "boolean", "description": ( "Whether to include non-eye/hair tags (clothing, accessories, etc.) " "in the prompt. Default true." ), "default": True, }, }, "required": ["character_name"], }, ), - gelbooru_mcp.py:285-496 (registration)The list_tools() decorated function that registers all tools with the MCP server, including build_prompt in the list of available tools.
@server.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="search_posts", description=( "Search Gelbooru posts by tags, page, limit, or ID. " "Supports all Gelbooru tag syntax: AND (tag1 tag2), OR ({t1~t2}), " "NOT (-tag), wildcards (*tag / tag*), meta-tags like " "rating:safe/questionable/explicit, score:>=N, width:>=N, " "user:name, sort:random, sort:score:desc, etc." ), inputSchema={ "type": "object", "properties": { "tags": { "type": "string", "description": ( "Tag query string. Examples: 'cat_ears blue_eyes', " "'touhou -rating:explicit', 'score:>=50 sort:score:desc'" ), }, "limit": { "type": "integer", "description": "Number of posts to return (default 20, max 100).", "default": 20, "minimum": 1, "maximum": 100, }, "pid": { "type": "integer", "description": "Page number (0-indexed).", "default": 0, }, "id": { "type": "integer", "description": "Fetch a single post by its Gelbooru ID.", }, "cid": { "type": "integer", "description": "Fetch posts by change ID (Unix timestamp).", }, }, }, ), Tool( name="get_deleted_posts", description=( "Retrieve deleted posts. Pass last_id to get everything deleted " "above that post ID." ), inputSchema={ "type": "object", "properties": { "last_id": { "type": "integer", "description": "Return deleted posts whose ID is above this value.", }, "limit": {"type": "integer", "default": 20, "minimum": 1, "maximum": 100}, }, }, ), Tool( name="search_tags", description=( "Search Gelbooru tags by name, pattern, or ID. " "Useful for autocomplete, tag counts, and tag type lookup." ), inputSchema={ "type": "object", "properties": { "name": { "type": "string", "description": "Exact tag name to look up.", }, "names": { "type": "string", "description": "Space-separated list of tag names, e.g. 'cat dog fox'.", }, "name_pattern": { "type": "string", "description": ( "Wildcard tag search using SQL LIKE syntax. " "Use % for multi-char wildcard, _ for single-char. " "Example: '%choolgirl%'" ), }, "id": { "type": "integer", "description": "Look up a tag by its database ID.", }, "after_id": { "type": "integer", "description": "Return tags whose ID is greater than this value.", }, "limit": {"type": "integer", "default": 20, "minimum": 1, "maximum": 100}, "order": { "type": "string", "enum": ["ASC", "DESC"], "description": "Sort direction.", }, "orderby": { "type": "string", "enum": ["date", "count", "name"], "description": "Field to sort by.", }, }, }, ), Tool( name="search_users", description="Search Gelbooru users by name or name pattern.", inputSchema={ "type": "object", "properties": { "name": { "type": "string", "description": "Exact username to search for.", }, "name_pattern": { "type": "string", "description": "Wildcard username search (SQL LIKE syntax).", }, "limit": {"type": "integer", "default": 20, "minimum": 1, "maximum": 100}, "pid": {"type": "integer", "default": 0}, }, }, ), Tool( name="get_comments", description="Retrieve comments for a specific Gelbooru post.", inputSchema={ "type": "object", "properties": { "post_id": { "type": "integer", "description": "The post ID whose comments you want to retrieve.", }, }, "required": ["post_id"], }, ), Tool( name="get_character_tags", description=( "Given a character name (e.g. 'misty_(pokemon)'), fetches the top " "highest-scored general/solo posts across multiple pages and returns " "the most frequently occurring tags split into three semantic buckets: " "eye colour/shape, hair colour/style, and other character traits. " "Each tag includes a frequency score. Results are cached to disk for 24 hours." ), inputSchema={ "type": "object", "properties": { "character_name": { "type": "string", "description": ( "The Gelbooru tag for the character, e.g. 'misty_(pokemon)', " "'rem_(re:zero)', 'saber_(fate)'. Use underscores as Gelbooru does." ), }, "max_images": { "type": "integer", "description": ( "How many top-scored posts to analyse across all pages " "(default 300). More images = slower but more reliable results. " "Fetched in pages of 100." ), "default": 300, "minimum": 10, }, }, "required": ["character_name"], }, ), Tool( name="build_prompt", description=( "Given a character name, returns a ready-to-use image-generation prompt " "string like 'misty (pokemon), green eyes, orange hair, side ponytail, ...'. " "Internally calls get_character_tags with caching, then assembles the prompt " "with tags ordered by frequency (eye → hair → other)." ), inputSchema={ "type": "object", "properties": { "character_name": { "type": "string", "description": ( "The Gelbooru tag for the character, e.g. 'misty_(pokemon)'. " "Use underscores as Gelbooru does." ), }, "max_images": { "type": "integer", "description": "Posts to analyse (default 300). Cached after first fetch.", "default": 300, "minimum": 10, }, "include_other": { "type": "boolean", "description": ( "Whether to include non-eye/hair tags (clothing, accessories, etc.) " "in the prompt. Default true." ), "default": True, }, }, "required": ["character_name"], }, ), ] - gelbooru_mcp.py:550-556 (handler)Routing/dispatch logic in call_tool() that handles build_prompt requests: extracts arguments from the request and calls _build_prompt via the executor.
elif name == "build_prompt": character_name = arguments["character_name"] max_images = arguments.get("max_images", 300) include_other = arguments.get("include_other", True) result = await loop.run_in_executor( None, _build_prompt, character_name, max_images, include_other )