search_meals
Search the database by meal name or keyword to discover available dishes for wine pairing.
Instructions
Search for meals and dishes in the SommelierX database. Returns meal names, IDs, and descriptions. Use this to discover available meals before using pair_wine_with_meal or group_pairing. Best for: "What pasta dishes are in the database?" | Auth: API key (Bearer sk_live_...) or x402 payment (USDC on Base) | Price: $0.005/call
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search term for meals/dishes (e.g. "risotto", "steak", "sushi") | |
| language | No | Language code for results (e.g. "en", "nl", "fr"). Defaults to "en". |
Implementation Reference
- src/tools/search-meals.ts:36-56 (handler)The main execution function for the search_meals tool. Calls /api/v1/meals?search=... with the query and language, then formats the results. Handles errors and delegates formatting to formatMealResults.
export async function executeSearchMeals( client: SommelierXClient, config: ServerConfig, input: SearchMealsInput, ): Promise<string> { const language = input.language ?? config.defaultLanguage; let result: MealListResult; try { result = await client.get<MealListResult>('/api/v1/meals', { search: input.query, language, perPage: '20', }); } catch (error: unknown) { const message = error instanceof Error ? error.message : 'Unknown error'; return `Error searching meals: ${message}`; } return formatMealResults(input.query, result.data, result.total); } - src/tools/search-meals.ts:15-27 (schema)Zod schema for search_meals input validation. Accepts 'query' (string, min 2 chars) and optional 'language' (string, 2-10 chars).
export const searchMealsSchema = z.object({ query: z .string() .min(2, 'Search query must be at least 2 characters') .max(100) .describe('Search term for meals/dishes (e.g. "risotto", "steak", "sushi")'), language: z .string() .min(2) .max(10) .optional() .describe('Language code for results (e.g. "en", "nl", "fr"). Defaults to "en".'), }); - src/index.ts:134-145 (registration)Registration of the 'search_meals' tool on the MCP server via server.tool(). Imports searchMealsSchema and executeSearchMeals, sets up the handler that parses input and calls executeSearchMeals.
// ── Tool 6: search_meals ── server.tool( 'search_meals', 'Search for meals and dishes in the SommelierX database. Returns meal names, IDs, and descriptions. Use this to discover available meals before using pair_wine_with_meal or group_pairing. Best for: "What pasta dishes are in the database?" | Auth: API key (Bearer sk_live_...) or x402 payment (USDC on Base) | Price: $0.005/call', searchMealsSchema.shape, async (input) => { const parsed = searchMealsSchema.parse(input); const result = await executeSearchMeals(client, config, parsed); return { content: [{ type: 'text' as const, text: result }] }; }, ); - src/tools/search-meals.ts:61-90 (helper)Helper function that formats meal search results into a human-readable string. Lists each meal with name, id, and optional description. Handles empty results and pagination messaging.
function formatMealResults( query: string, meals: MealItem[], total: number, ): string { const lines: string[] = []; lines.push(`Meal search results for "${query}" (${total} total):`); lines.push(''); if (meals.length === 0) { lines.push('No meals found matching your search.'); lines.push('Try a different search term or language.'); return lines.join('\n'); } for (const meal of meals) { lines.push(`- ${meal.name} (id: ${meal.id})`); if (meal.description) { lines.push(` ${meal.description}`); } } if (total > meals.length) { lines.push(''); lines.push(`Showing ${meals.length} of ${total} results. Refine your search for more specific results.`); } return lines.join('\n'); } - src/tools/types.ts:87-105 (helper)Type definitions used by search_meals: MealItem interface (id, name, description, ingredients) and MealListResult interface (data array with pagination fields total, page, perPage).
/** Meal from search/list. */ export interface MealItem { id: number; name: string; description?: string; ingredients?: Array<{ id: number; name: string; amount?: string; }>; } /** Paginated meal list. */ export interface MealListResult { data: MealItem[]; total: number; page: number; perPage: number; }