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