Skip to main content
Glama
recipes.py11.4 kB
""" Recipe Resources for Mealie MCP Server Provides recipe information as MCP resources. """ from typing import Optional # Handle imports for both module and script execution try: from ..client import MealieClient, MealieAPIError except ImportError: # Running as a script, use absolute imports import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.parent)) from client import MealieClient, MealieAPIError def get_recipes_list() -> str: """ Get a summary of all recipes in Mealie. URI: recipes://list Returns: Formatted text with recipe names, slugs, tags, and categories """ try: client = MealieClient() # Get all recipes (paginate if necessary) all_recipes = [] page = 1 per_page = 100 while True: response = client.get("/api/recipes", params={ "page": page, "perPage": per_page, "orderBy": "name", "orderDirection": "asc" }) if not response or "items" not in response: break recipes = response["items"] if not recipes: break all_recipes.extend(recipes) # Check if there are more pages total = response.get("total", 0) if len(all_recipes) >= total: break page += 1 client.close() # Organize recipes by category by_category = {} uncategorized = [] for recipe in all_recipes: category = recipe.get("recipeCategory") if category: if isinstance(category, list): category = category[0] if category else "Uncategorized" # Handle dict category (convert to string) if isinstance(category, dict): category = category.get("name", "Uncategorized") # Ensure category is a string category_str = str(category) if category_str not in by_category: by_category[category_str] = [] by_category[category_str].append(recipe) else: uncategorized.append(recipe) # Format output output = ["# Recipes in Mealie", ""] output.append(f"**Total Recipes**: {len(all_recipes)}") output.append("") # List by category for category in sorted(by_category.keys()): recipes = by_category[category] output.append(f"## {category} ({len(recipes)} recipes)") output.append("") for recipe in recipes: name = recipe.get("name", "Unknown") slug = recipe.get("slug", "") tags = recipe.get("tags", []) # Format tags tag_str = "" if tags: if isinstance(tags, list): tag_names = [t.get("name", str(t)) if isinstance(t, dict) else str(t) for t in tags] tag_str = f" [{', '.join(tag_names)}]" output.append(f"- **{name}** (`{slug}`){tag_str}") output.append("") # Add uncategorized if uncategorized: output.append(f"## Uncategorized ({len(uncategorized)} recipes)") output.append("") for recipe in uncategorized: name = recipe.get("name", "Unknown") slug = recipe.get("slug", "") tags = recipe.get("tags", []) tag_str = "" if tags: if isinstance(tags, list): tag_names = [t.get("name", str(t)) if isinstance(t, dict) else str(t) for t in tags] tag_str = f" [{', '.join(tag_names)}]" output.append(f"- **{name}** (`{slug}`){tag_str}") output.append("") return "\n".join(output) except MealieAPIError as e: return f"Error fetching recipes: {e}" except Exception as e: return f"Unexpected error: {e}" def get_recipe_detail(slug: str) -> str: """ Get detailed information about a specific recipe. URI: recipes://{slug} Args: slug: Recipe slug identifier Returns: Formatted recipe with ingredients, instructions, and nutrition """ try: client = MealieClient() recipe = client.get(f"/api/recipes/{slug}") client.close() if not recipe: return f"Recipe '{slug}' not found" # Format output output = [] # Header name = recipe.get("name", "Unknown Recipe") output.append(f"# {name}") output.append("") # Metadata description = recipe.get("description", "") if description: output.append(f"*{description}*") output.append("") # Basic info output.append("## Information") output.append("") category = recipe.get("recipeCategory") if category: if isinstance(category, list): category = ", ".join(category) output.append(f"- **Category**: {category}") tags = recipe.get("tags", []) if tags: if isinstance(tags, list): tag_names = [t.get("name", str(t)) if isinstance(t, dict) else str(t) for t in tags] output.append(f"- **Tags**: {', '.join(tag_names)}") yield_amount = recipe.get("recipeYield") if yield_amount: output.append(f"- **Yield**: {yield_amount}") total_time = recipe.get("totalTime") if total_time: output.append(f"- **Total Time**: {total_time}") prep_time = recipe.get("prepTime") if prep_time: output.append(f"- **Prep Time**: {prep_time}") perform_time = recipe.get("performTime") if perform_time: output.append(f"- **Cook Time**: {perform_time}") output.append("") # Ingredients ingredients = recipe.get("recipeIngredient", []) if ingredients: output.append("## Ingredients") output.append("") for ingredient in ingredients: if isinstance(ingredient, dict): # Structured ingredient quantity = ingredient.get("quantity", "") unit = ingredient.get("unit", {}) if isinstance(unit, dict): unit = unit.get("name", "") food = ingredient.get("food", {}) if isinstance(food, dict): food = food.get("name", "") note = ingredient.get("note", "") line = f"- {quantity} {unit} {food}".strip() if note: line += f" ({note})" output.append(line) else: # Simple string ingredient output.append(f"- {ingredient}") output.append("") # Instructions instructions = recipe.get("recipeInstructions", []) if instructions: output.append("## Instructions") output.append("") for i, instruction in enumerate(instructions, 1): if isinstance(instruction, dict): text = instruction.get("text", "") title = instruction.get("title", "") if title: output.append(f"### Step {i}: {title}") output.append("") else: output.append(f"### Step {i}") output.append("") output.append(text) else: output.append(f"{i}. {instruction}") output.append("") # Nutrition nutrition = recipe.get("nutrition") if nutrition and isinstance(nutrition, dict): output.append("## Nutrition") output.append("") calories = nutrition.get("calories") if calories: output.append(f"- **Calories**: {calories}") protein = nutrition.get("proteinContent") if protein: output.append(f"- **Protein**: {protein}") carbs = nutrition.get("carbohydrateContent") if carbs: output.append(f"- **Carbohydrates**: {carbs}") fat = nutrition.get("fatContent") if fat: output.append(f"- **Fat**: {fat}") fiber = nutrition.get("fiberContent") if fiber: output.append(f"- **Fiber**: {fiber}") sodium = nutrition.get("sodiumContent") if sodium: output.append(f"- **Sodium**: {sodium}") output.append("") # Notes notes = recipe.get("notes", []) if notes: output.append("## Notes") output.append("") for note in notes: if isinstance(note, dict): title = note.get("title", "") text = note.get("text", "") if title: output.append(f"### {title}") output.append("") output.append(text) else: output.append(note) output.append("") # Source recipe_url = recipe.get("orgURL") if recipe_url: output.append("## Source") output.append("") output.append(f"[Original Recipe]({recipe_url})") output.append("") return "\n".join(output) except MealieAPIError as e: return f"Error fetching recipe '{slug}': {e}" except Exception as e: return f"Unexpected error: {e}" if __name__ == "__main__": """Test recipe resources.""" import sys from pathlib import Path # Add parent directory to path for imports sys.path.insert(0, str(Path(__file__).parent.parent)) from dotenv import load_dotenv from client import MealieClient load_dotenv() print("Testing Recipe Resources") print("=" * 70) print() # Test 1: Get recipes list print("TEST 1: Get Recipes List") print("-" * 70) result = get_recipes_list() print(result) print() # Test 2: Get recipe detail (you'll need to update this with an actual slug) print("TEST 2: Get Recipe Detail") print("-" * 70) # Get the first recipe slug from the list for testing client = MealieClient() try: response = client.get("/api/recipes", params={"page": 1, "perPage": 1}) if response and "items" in response and response["items"]: test_slug = response["items"][0].get("slug", "") if test_slug: print(f"Testing with recipe slug: {test_slug}") print() result = get_recipe_detail(test_slug) print(result) else: print("No recipes found to test with") else: print("No recipes found to test with") except Exception as e: print(f"Error: {e}") finally: client.close()

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/mdlopresti/mealie-mcp'

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