search_gallery
Search AI image prompts using semantic understanding to find visually and conceptually similar results, including image URLs for easy browsing and style picking.
Instructions
Search AI image prompts with semantic understanding — finds visually and conceptually similar results, not just keyword matches. Results include image URLs — render them as markdown images () so users can visually browse and pick styles. Use when users need inspiration, want to explore styles, or say "generate an image" without a specific idea.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Search keywords (e.g., "cyberpunk", "product photo", "portrait"). Supports semantic search — natural language descriptions work well. Leave empty to browse by category or get random picks. | |
| category | No | Filter by category. Available: Photography, Illustration & 3D, Product & Brand, Food & Drink, Poster Design, UI & Graphic | |
| limit | No | Number of results (1-20, default 5) | |
| offset | No | Pagination offset | |
| sortBy | No | Sort order when browsing without search query (default: rank) | rank |
Implementation Reference
- src/tools/search-gallery.ts:29-94 (handler)Main handler function that registers the 'search_gallery' tool on the MCP server. Contains the core logic: 1) If no query/category → return random prompts from local library with stats. 2) If query without category → try semantic search via external API (apiSearchPosts). 3) Falls through to local keyword-based search via searchPrompts (supports category filter). Returns formatted results with markdown image previews.
export function registerSearchGallery(server: McpServer, config: MeiGenConfig) { server.tool( 'search_gallery', 'Search AI image prompts with semantic understanding — finds visually and conceptually similar results, not just keyword matches. Results include image URLs — render them as markdown images () so users can visually browse and pick styles. Use when users need inspiration, want to explore styles, or say "generate an image" without a specific idea.', searchGallerySchema, { readOnlyHint: true }, async ({ query, category, limit, offset, sortBy }) => { // No search criteria — return random picks from local library if (!query && !category && offset === 0) { const random = getRandomPrompts(limit) const stats = getLibraryStats() const header = `Curated Prompt Library: ${stats.total} trending prompts\nCategories: ${Object.entries(stats.categories).map(([k, v]) => `${k} (${v})`).join(', ')}\n\nHere are ${limit} random picks — show the preview images to the user:\n` return { content: [{ type: 'text' as const, text: header + formatLocalResults(random), }], } } // Has query and no category filter → try semantic search via API if (query && query.trim() && !category) { const apiResults = await apiSearchPosts(config.meigenBaseUrl, query, limit, offset) if (apiResults && apiResults.length > 0) { const text = `Found ${apiResults.length} results for "${query}" (semantic search):\n\n${formatApiResults(apiResults)}\n\nShow the preview images above to the user so they can visually browse. Use get_inspiration(imageId) to get the full prompt and all images for any entry the user likes.` return { content: [{ type: 'text' as const, text, }], } } // API failed or no results — fall through to local search } // Local search (keyword-based): with category filter, or as API fallback const results = searchPrompts({ query, category, limit, offset, sortBy }) if (results.length === 0) { const suggestion = category ? `No results for "${query || ''}" in category "${category}". Try a different keyword or remove the category filter.` : `No results for "${query}". Try broader keywords like "portrait", "landscape", "product", "anime".` return { content: [{ type: 'text' as const, text: suggestion, }], } } const searchDesc = [ query ? `"${query}"` : null, category ? `category: ${category}` : null, ].filter(Boolean).join(', ') const text = `Found ${results.length} results${searchDesc ? ` for ${searchDesc}` : ''}:\n\n${formatLocalResults(results)}\n\nShow the preview images above to the user so they can visually browse. Use get_inspiration(imageId) to get the full prompt and all images for any entry the user likes.` return { content: [{ type: 'text' as const, text, }], } } ) } - src/tools/search-gallery.ts:16-27 (schema)Zod schema for the search_gallery tool parameters: query (optional string), category (enum of 6 categories), limit (1-20, default 5), offset (default 0), sortBy (rank/likes/views/date, default rank).
export const searchGallerySchema = { query: z.string().optional() .describe('Search keywords (e.g., "cyberpunk", "product photo", "portrait"). Supports semantic search — natural language descriptions work well. Leave empty to browse by category or get random picks.'), category: z.enum(['Photography', 'Illustration & 3D', 'Product & Brand', 'Food & Drink', 'Poster Design', 'UI & Graphic']).optional() .describe('Filter by category. Available: Photography, Illustration & 3D, Product & Brand, Food & Drink, Poster Design, UI & Graphic'), limit: z.number().min(1).max(20).optional().default(5) .describe('Number of results (1-20, default 5)'), offset: z.number().min(0).optional().default(0) .describe('Pagination offset'), sortBy: z.enum(['rank', 'likes', 'views', 'date']).optional().default('rank') .describe('Sort order when browsing without search query (default: rank)'), } - src/server.ts:255-270 (registration)The tool is registered in createServer() by calling registerSearchGallery(server, config) — part of free features that require no authentication.
export function createServer() { const config = loadConfig() const apiClient = new MeiGenApiClient(config) const server = new McpServer( { name: 'meigen', version: '1.3.2' }, { instructions: SERVER_INSTRUCTIONS }, ) // Free features (no configuration required) registerEnhancePrompt(server) registerSearchGallery(server, config) registerListModels(server, apiClient, config) registerGetInspiration(server, apiClient) registerManagePreferences(server) - src/server.ts:10-10 (registration)Import statement for the registerSearchGallery function from the search-gallery.ts tool module.
import { registerSearchGallery } from './tools/search-gallery.js' - src/tools/search-gallery.ts:96-117 (helper)Helper functions formatApiResults and formatLocalResults that format API and local search results into user-facing text with markdown image previews, prompt snippets, stats, and IDs.
function formatApiResults(results: ApiSearchResult[]): string { return results.map((item, i) => { // Use text field as prompt, truncate for preview const promptText = item.text || '' const promptPreview = promptText.length > 150 ? promptText.slice(0, 150).replace(/\n/g, ' ') + '...' : promptText.replace(/\n/g, ' ') const imageUrl = item.thumbnail_url || (item.media_urls?.[0]) const author = item.author_display_name || item.author_username || 'Unknown' const model = item.model || 'unknown' const parts = [ `${i + 1}. by ${author} — ${model}`, imageUrl ? ` ` : null, ` Prompt: ${promptPreview}`, ` Stats: ${item.likes} likes, ${item.views.toLocaleString()} views`, ` ID: ${item.id}`, ].filter(Boolean) return parts.join('\n') }).join('\n\n') }