get_recipe
Retrieve cocktail recipes individually or in batches using names or IDs, with options for including variations and controlling batch size.
Instructions
🍸 Advanced recipe retrieval with powerful batch processing for multiple cocktails.
🚀 BATCH PROCESSING SYSTEM:
High Performance: 5-10x faster than sequential requests
Parallel Processing: Simultaneous API calls with error isolation
Smart Caching: 70%+ cache hit rate for repeated requests
Flexible Input: Mix cocktail names and IDs in single request
Error Resilience: Individual failures don't break entire batch
📋 LLM Usage Patterns:
Single Recipe: When user asks for "how to make [cocktail]"
Recipe Comparison: When user wants to compare multiple cocktails
Menu Planning: Batch retrieve recipes for event planning
Variation Exploration: Get base recipe + similar cocktails
Research Mode: Efficient lookup of multiple specific recipes
🎯 Input Methods (Choose Based on Use Case):
Single Recipe (Backwards Compatible):
cocktail_name: "Manhattan" → One complete recipe
cocktail_id: 123 → Recipe by database ID
Batch by Names (Most Common):
cocktail_names: ["Negroni", "Manhattan", "Martini"] → Multiple complete recipes
Batch by IDs (When Available):
cocktail_ids: [1, 2, 3] → Multiple recipes by database IDs
Mixed Batch (Maximum Flexibility):
cocktail_names: ["Aviation"] + cocktail_ids: [123, 456] → Combined approach
With Variations (Exploration):
Any above + include_variations: true → Base recipes + similar cocktails
📊 Response Format: Structured output with complete recipe data:
Precise ingredient measurements (auto-converted to oz)
Step-by-step preparation instructions
Cocktail specifications (ABV, glassware, method, garnish)
Direct database links for each recipe
Performance metrics (timing, cache usage)
Similar recipes when requested
Rich formatting with emojis and clear sections
⚡ Performance Examples:
Single recipe: ~150-300ms (cached responses faster)
Batch (3 cocktails): ~250-400ms (vs 900ms+ sequential)
Mixed batch (5 cocktails): ~300-500ms with parallel processing
Cache hit: <50ms instant response
🎛️ Batch Control Parameters:
limit: 1-20 recipes (default: 10) - controls batch size
include_variations: Boolean - adds similar cocktails to results
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cocktail_id | No | 🆔 Single cocktail database ID. Use for specific recipe lookup when ID is known. | |
| cocktail_name | No | 🍸 Single cocktail name. Use for individual recipe requests (e.g., "Manhattan", "Negroni"). | |
| cocktail_ids | No | 🚀 Array of cocktail IDs for batch processing. Enables parallel retrieval of multiple recipes by database ID. More efficient than multiple single requests. | |
| cocktail_names | No | 🚀 Array of cocktail names for batch processing. Enables parallel retrieval of multiple recipes by name (e.g., ["Manhattan", "Negroni", "Martini"]). Triggers name resolution + batch fetching. | |
| include_variations | No | 🔄 Include similar/variation recipes in results. Adds related cocktails to expand exploration (default: false). | |
| limit | No | 🎛️ Maximum number of recipes to return. Controls batch size for optimal performance (default: 10, max: 20). Higher limits may impact response time. |
Implementation Reference
- src/bar-assistant-mcp-server.ts:1075-1257 (registration)Registration of the 'get_recipe' tool in the MCP server, including detailed description, input schema matching GetRecipeParams, and output schema definition.name: 'get_recipe', description: `🍸 Advanced recipe retrieval with powerful batch processing for multiple cocktails. **🚀 BATCH PROCESSING SYSTEM:** - **High Performance**: 5-10x faster than sequential requests - **Parallel Processing**: Simultaneous API calls with error isolation - **Smart Caching**: 70%+ cache hit rate for repeated requests - **Flexible Input**: Mix cocktail names and IDs in single request - **Error Resilience**: Individual failures don't break entire batch **📋 LLM Usage Patterns:** - **Single Recipe**: When user asks for "how to make [cocktail]" - **Recipe Comparison**: When user wants to compare multiple cocktails - **Menu Planning**: Batch retrieve recipes for event planning - **Variation Exploration**: Get base recipe + similar cocktails - **Research Mode**: Efficient lookup of multiple specific recipes **🎯 Input Methods (Choose Based on Use Case):** 1. **Single Recipe (Backwards Compatible)**: - cocktail_name: "Manhattan" → One complete recipe - cocktail_id: 123 → Recipe by database ID 2. **Batch by Names (Most Common)**: - cocktail_names: ["Negroni", "Manhattan", "Martini"] → Multiple complete recipes 3. **Batch by IDs (When Available)**: - cocktail_ids: [1, 2, 3] → Multiple recipes by database IDs 4. **Mixed Batch (Maximum Flexibility)**: - cocktail_names: ["Aviation"] + cocktail_ids: [123, 456] → Combined approach 5. **With Variations (Exploration)**: - Any above + include_variations: true → Base recipes + similar cocktails **📊 Response Format:** Structured output with complete recipe data: - Precise ingredient measurements (auto-converted to oz) - Step-by-step preparation instructions - Cocktail specifications (ABV, glassware, method, garnish) - Direct database links for each recipe - Performance metrics (timing, cache usage) - Similar recipes when requested - Rich formatting with emojis and clear sections **⚡ Performance Examples:** - Single recipe: ~150-300ms (cached responses faster) - Batch (3 cocktails): ~250-400ms (vs 900ms+ sequential) - Mixed batch (5 cocktails): ~300-500ms with parallel processing - Cache hit: <50ms instant response **🎛️ Batch Control Parameters:** - limit: 1-20 recipes (default: 10) - controls batch size - include_variations: Boolean - adds similar cocktails to results`, inputSchema: { type: 'object', description: '🎛️ Flexible input schema supporting single recipes and high-performance batch processing', properties: { // Single recipe parameters (backwards compatible) cocktail_id: { type: 'number', description: '🆔 Single cocktail database ID. Use for specific recipe lookup when ID is known.', }, cocktail_name: { type: 'string', description: '🍸 Single cocktail name. Use for individual recipe requests (e.g., "Manhattan", "Negroni").', }, // Batch processing parameters (high performance) cocktail_ids: { type: 'array', items: { type: 'number' }, description: '🚀 Array of cocktail IDs for batch processing. Enables parallel retrieval of multiple recipes by database ID. More efficient than multiple single requests.', }, cocktail_names: { type: 'array', items: { type: 'string' }, description: '🚀 Array of cocktail names for batch processing. Enables parallel retrieval of multiple recipes by name (e.g., ["Manhattan", "Negroni", "Martini"]). Triggers name resolution + batch fetching.', }, // Enhancement parameters include_variations: { type: 'boolean', description: '🔄 Include similar/variation recipes in results. Adds related cocktails to expand exploration (default: false).', default: false, }, // Batch control parameters limit: { type: 'number', description: '🎛️ Maximum number of recipes to return. Controls batch size for optimal performance (default: 10, max: 20). Higher limits may impact response time.', default: 10, minimum: 1, maximum: 20, }, }, // Schema validation rules for LLMs oneOf: [ { description: 'Single recipe by name', required: ['cocktail_name'] }, { description: 'Single recipe by ID', required: ['cocktail_id'] }, { description: 'Batch processing by names', required: ['cocktail_names'] }, { description: 'Batch processing by IDs', required: ['cocktail_ids'] }, { description: 'Mixed batch processing', anyOf: [ { required: ['cocktail_names', 'cocktail_ids'] }, { required: ['cocktail_names', 'cocktail_id'] }, { required: ['cocktail_name', 'cocktail_ids'] } ] } ], }, outputSchema: { type: 'object', properties: { recipes: { type: 'array', items: { type: 'object', properties: { id: { type: 'number' }, name: { type: 'string' }, description: { type: 'string' }, ingredients: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, formatted: { type: 'string' }, amount: { type: 'string' }, optional: { type: 'boolean' } } } }, instructions: { type: 'array', items: { type: 'object', properties: { step: { type: 'number' }, instruction: { type: 'string' } } } }, details: { type: 'object', properties: { abv: { type: 'number' }, glass: { type: 'string' }, method: { type: 'string' }, garnish: { type: 'string' }, direct_link: { type: 'string' }, tags: { type: 'array', items: { type: 'string' } } } } } } }, performance: { type: 'object', properties: { processing_time: { type: 'number' }, recipes_fetched: { type: 'number' }, cache_hits: { type: 'number' }, batch_processing: { type: 'boolean' } } } } }, },
- Primary handler function for executing the get_recipe tool. Determines if batch or single request and delegates accordingly, with error handling and performance timing.private async handleGetRecipe(args: GetRecipeParams) { const startTime = Date.now(); try { // Determine if this is a batch request or single request const isBatchRequest = args.cocktail_ids || args.cocktail_names; const limit = Math.min(args.limit || 10, 20); if (isBatchRequest) { return await this.handleBatchRecipeRequest(args, startTime, limit); } else { return await this.handleSingleRecipeRequest(args, startTime); } } catch (error) { const errorText = `# Recipe Error\n\n` + `Sorry, I encountered an error while fetching recipes.\n\n` + `**Error:** ${error instanceof Error ? error.message : String(error)}\n\n` + `Please try again or contact support if the issue persists.`; return { content: [{ type: 'text', text: errorText }] }; } }
- src/types.ts:237-244 (schema)TypeScript interface defining the input parameters for the get_recipe tool.export interface GetRecipeParams { cocktail_name?: string; cocktail_id?: number; cocktail_ids?: number[]; cocktail_names?: string[]; include_variations?: boolean; limit?: number; }
- Batch processing handler for get_recipe tool. Handles multiple cocktail requests with parallel API calls, caching, name resolution, and complete recipe formatting.private async handleBatchRecipeRequest(args: any, startTime: number, limit: number) { const cocktailRequests: Array<{id?: number, name?: string}> = []; // Collect all cocktail requests if (args.cocktail_ids) { cocktailRequests.push(...args.cocktail_ids.slice(0, limit).map((id: number) => ({ id }))); } if (args.cocktail_names) { const remainingSlots = limit - cocktailRequests.length; cocktailRequests.push(...args.cocktail_names.slice(0, remainingSlots).map((name: string) => ({ name }))); } if (cocktailRequests.length === 0) { return { content: [{ type: 'text', text: `# No Cocktails Specified\n\n` + `Please provide cocktail_ids, cocktail_names, cocktail_id, or cocktail_name.` }] }; } // Resolve names to IDs first (with caching) const resolvedCocktails: Array<{id: number, originalRequest: any}> = []; for (const request of cocktailRequests) { if (request.id) { resolvedCocktails.push({ id: request.id, originalRequest: request }); } else if (request.name) { try { const searchResults = await this.barClient.findCocktailByName(request.name); if (searchResults.data.length > 0) { resolvedCocktails.push({ id: searchResults.data[0].id, originalRequest: request }); } else { console.warn(`Cocktail not found: ${request.name}`); } } catch (error) { console.warn(`Error searching for ${request.name}:`, error); } } } if (resolvedCocktails.length === 0) { return { content: [{ type: 'text', text: `# No Cocktails Found\n\n` + `None of the specified cocktails could be found in the database.\n\n` + `**Tried:** ${cocktailRequests.map(r => r.name || `ID ${r.id}`).join(', ')}\n\n` + `**Suggestions:**\n` + `• Check spelling of cocktail names\n` + `• Use \`smart_search_cocktails\` to find available cocktails\n` + `• Verify cocktail IDs are correct` }] }; } // Use existing batch fetching infrastructure const mockCocktails = resolvedCocktails.map(r => ({ id: r.id })); const completeRecipes = await this.fetchCompleteRecipes(mockCocktails); const processingTime = Date.now() - startTime; // Build response let response = `# 📖 Batch Recipe Results\n\n`; response += `Successfully retrieved ${completeRecipes.length} of ${cocktailRequests.length} requested recipes in ${processingTime}ms\n\n`; if (completeRecipes.length > 1) { response += this.formatMultipleCocktails(completeRecipes); } else if (completeRecipes.length === 1) { response += this.formatSingleRecipeDetailed(completeRecipes[0]); } // Add variations if requested if (args.include_variations && completeRecipes.length === 1) { try { const variations = await this.barClient.findSimilarCocktails(completeRecipes[0].id, 3); if (variations.length > 0) { response += `\n\n# 🔄 Similar Recipes\n\n`; const variationRecipes = await this.fetchCompleteRecipes( variations.map(v => v.cocktail) ); response += this.formatMultipleCocktails(variationRecipes); } } catch (error) { console.warn('Failed to fetch variations:', error); } } // Add performance summary response += `\n\n---\n\n**⚡ Performance Summary:**\n`; response += `• **Total time:** ${processingTime}ms\n`; response += `• **Recipes fetched:** ${completeRecipes.length}\n`; response += `• **Cache utilization:** Enabled\n`; response += `• **Batch processing:** ${completeRecipes.length > 1 ? 'Used' : 'Single recipe'}`; return { content: [{ type: 'text', text: response }] }; }
- src/bar-assistant-client.ts:115-121 (helper)Core API client method that fetches detailed cocktail recipe data from the Bar Assistant backend API, used by the tool handlers.async getCocktailRecipe(cocktailId: number): Promise<DetailedRecipe> { // Try different include parameters to get ingredients and instructions const response: AxiosResponse<{ data: DetailedRecipe }> = await this.client.get( `/api/cocktails/${cocktailId}?include=ingredients,instructions,tags,glass,method,images` ); return response.data.data; // Extract the nested data }