Skip to main content
Glama
zhdenny

Bar Assistant MCP Server

by zhdenny

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):

  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

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
cocktail_idNo🆔 Single cocktail database ID. Use for specific recipe lookup when ID is known.
cocktail_nameNo🍸 Single cocktail name. Use for individual recipe requests (e.g., "Manhattan", "Negroni").
cocktail_idsNo🚀 Array of cocktail IDs for batch processing. Enables parallel retrieval of multiple recipes by database ID. More efficient than multiple single requests.
cocktail_namesNo🚀 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_variationsNo🔄 Include similar/variation recipes in results. Adds related cocktails to expand exploration (default: false).
limitNo🎛️ Maximum number of recipes to return. Controls batch size for optimal performance (default: 10, max: 20). Higher limits may impact response time.

Implementation Reference

  • 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 }] }; } }
  • 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 }] }; }
  • 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 }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zhdenny/bar-assistant-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server