bbq_get_cooking_guidance
Get cooking guidance for BBQ proteins with target temperatures, time estimates, and tips based on weight, doneness, and serving time.
Instructions
Get comprehensive cooking guidance for a specific protein including target temperatures, time estimates, and tips.
This is the primary tool for planning a cook. It provides:
Target internal temperature based on desired doneness
Pull temperature (accounting for carryover)
Estimated cook time based on weight and method
Timeline for when to start if serving time is specified
Stall warnings for large cuts
Resting instructions
Pro tips for the specific protein
Args:
protein_type: Type of meat (e.g., 'beef_brisket', 'pork_shoulder', 'chicken_whole')
weight_pounds: Weight in pounds (e.g., 12.5)
target_doneness: Desired doneness level (optional, uses recommended if not specified)
cook_method: Cooking method (optional, uses recommended if not specified)
serving_time: Target serving time in ISO 8601 format (optional)
response_format: 'markdown' or 'json'
Examples:
"How should I cook a 14 lb brisket?" -> protein_type='beef_brisket', weight_pounds=14
"I want to serve pulled pork at 6pm" -> protein_type='pork_butt', serving_time='2024-12-25T18:00:00'
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| protein_type | Yes | Type of protein being cooked (e.g., 'beef_brisket', 'pork_shoulder', 'chicken_whole') | |
| weight_pounds | Yes | Weight of the protein in pounds (e.g., 12.5 for a 12.5 lb brisket) | |
| target_doneness | No | Desired doneness level. If not specified, will use the recommended doneness for the protein type. | |
| cook_method | No | Cooking method to use. If not specified, will recommend the best method for this protein. | |
| serving_time | No | Target serving time in ISO 8601 format (e.g., '2024-12-25T18:00:00'). Used to calculate when to start cooking. | |
| response_format | No | Output format: 'markdown' for human-readable or 'json' for structured data | markdown |
Implementation Reference
- src/index.ts:156-260 (handler)Primary handler function for bbq_get_cooking_guidance tool. Orchestrates protein profile lookup, target temperature calculation, cook time estimation, timeline calculation (if serving time provided), and formats output as JSON or Markdown.async (params: GetCookingGuidanceInput) => { try { const profile = getProteinProfile(params.protein_type); const cookMethod = params.cook_method || getRecommendedCookMethod(params.protein_type); const { targetTemp, pullTemp, doneness } = getTargetTemperature( params.protein_type, params.target_doneness ); const estimate = estimateCookTime( params.protein_type, params.weight_pounds, cookMethod ); let startTimeInfo: { startTime: Date; restTime: number; bufferMinutes: number } | undefined; if (params.serving_time) { const servingDate = new Date(params.serving_time); startTimeInfo = calculateStartTime( params.protein_type, params.weight_pounds, cookMethod, servingDate ); } if (params.response_format === "json") { const output = { protein: { type: params.protein_type, displayName: profile.displayName, category: profile.category, weightPounds: params.weight_pounds, }, temperatures: { targetTemp, pullTemp, carryover: profile.carryoverDegrees, usdaSafeMin: profile.usdaSafeTemp, }, doneness: { level: doneness, displayName: DONENESS_INFO[doneness].displayName, description: DONENESS_INFO[doneness].description, }, cookMethod: { method: cookMethod, displayName: COOK_METHOD_INFO[cookMethod].displayName, tempRange: COOK_METHOD_INFO[cookMethod].tempRange, }, timeEstimate: { totalMinutes: estimate.totalMinutes, hoursAndMinutes: estimate.hoursAndMinutes, confidence: estimate.confidence, estimatedDoneTime: estimate.estimatedDoneTime.toISOString(), }, timeline: startTimeInfo ? { startTime: startTimeInfo.startTime.toISOString(), restTimeMinutes: startTimeInfo.restTime, bufferMinutes: startTimeInfo.bufferMinutes, } : null, rest: { required: profile.requiresRest, minutes: profile.restTimeMinutes, }, stall: profile.stallRange ? { expectedRange: profile.stallRange, warning: "Temperature may plateau for 2-4 hours in this range", } : null, tips: profile.tips, assumptions: estimate.assumptions, warnings: estimate.warnings, }; return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }], structuredContent: output, }; } const markdown = formatCookingGuidanceMarkdown( profile, params.weight_pounds, targetTemp, pullTemp, doneness, cookMethod, estimate, startTimeInfo ); return { content: [{ type: "text", text: markdown }], }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error occurred"; return { isError: true, content: [{ type: "text", text: `Error getting cooking guidance: ${message}` }], }; } }
- src/schemas/index.ts:67-91 (schema)Zod input schema defining parameters for the bbq_get_cooking_guidance tool: protein_type, weight_pounds, target_doneness, cook_method, serving_time, response_format.export const GetCookingGuidanceSchema = z .object({ protein_type: ProteinTypeSchema.describe( "Type of protein being cooked (e.g., 'beef_brisket', 'pork_shoulder', 'chicken_whole')" ), weight_pounds: z .number() .positive() .max(50) .describe("Weight of the protein in pounds (e.g., 12.5 for a 12.5 lb brisket)"), target_doneness: DonenessLevelSchema.optional().describe( "Desired doneness level. If not specified, will use the recommended doneness for the protein type." ), cook_method: CookMethodSchema.optional().describe( "Cooking method to use. If not specified, will recommend the best method for this protein." ), serving_time: z .string() .optional() .describe( "Target serving time in ISO 8601 format (e.g., '2024-12-25T18:00:00'). Used to calculate when to start cooking." ), response_format: ResponseFormatSchema.describe("Output format: 'markdown' for human-readable or 'json' for structured data"), }) .strict();
- src/index.ts:122-155 (registration)Registration of the bbq_get_cooking_guidance tool on the MCP server, including title, description, input schema reference, and annotations.server.registerTool( "bbq_get_cooking_guidance", { title: "Get BBQ Cooking Guidance", description: `Get comprehensive cooking guidance for a specific protein including target temperatures, time estimates, and tips. This is the primary tool for planning a cook. It provides: - Target internal temperature based on desired doneness - Pull temperature (accounting for carryover) - Estimated cook time based on weight and method - Timeline for when to start if serving time is specified - Stall warnings for large cuts - Resting instructions - Pro tips for the specific protein Args: - protein_type: Type of meat (e.g., 'beef_brisket', 'pork_shoulder', 'chicken_whole') - weight_pounds: Weight in pounds (e.g., 12.5) - target_doneness: Desired doneness level (optional, uses recommended if not specified) - cook_method: Cooking method (optional, uses recommended if not specified) - serving_time: Target serving time in ISO 8601 format (optional) - response_format: 'markdown' or 'json' Examples: - "How should I cook a 14 lb brisket?" -> protein_type='beef_brisket', weight_pounds=14 - "I want to serve pulled pork at 6pm" -> protein_type='pork_butt', serving_time='2024-12-25T18:00:00'`, inputSchema: GetCookingGuidanceSchema, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, },
- src/services/formatting.ts:19-88 (helper)Helper function to format the cooking guidance output as comprehensive Markdown, used by the main handler for 'markdown' response_format.export function formatCookingGuidanceMarkdown( profile: ProteinProfile, weightPounds: number, targetTemp: number, pullTemp: number, doneness: DonenessLevel, cookMethod: CookMethod, estimate: CookTimeEstimate, startTime?: { startTime: Date; restTime: number; bufferMinutes: number } ): string { const methodInfo = COOK_METHOD_INFO[cookMethod]; const donenessInfo = DONENESS_INFO[doneness]; let output = `## 🍖 Cooking Guide: ${profile.displayName}\n\n`; output += `**Weight:** ${weightPounds} lbs\n`; output += `**Method:** ${methodInfo.displayName} (${methodInfo.tempRange})\n`; output += `**Target Doneness:** ${donenessInfo.displayName} - ${donenessInfo.description}\n\n`; output += `### 🎯 Temperature Targets\n\n`; output += `- **Target Internal Temp:** ${targetTemp}°F\n`; output += `- **Pull Temperature:** ${pullTemp}°F (accounts for ${profile.carryoverDegrees}°F carryover)\n`; output += `- **USDA Safe Minimum:** ${profile.usdaSafeTemp}°F\n\n`; output += `### ⏱️ Time Estimate\n\n`; output += `**Estimated Cook Time:** ${estimate.hoursAndMinutes}\n`; output += `**Confidence:** ${estimate.confidence.charAt(0).toUpperCase() + estimate.confidence.slice(1)}\n\n`; if (estimate.assumptions.length > 0) { output += `**Notes:**\n`; for (const assumption of estimate.assumptions) { output += `- ${assumption}\n`; } output += "\n"; } if (estimate.warnings.length > 0) { output += `**⚠️ Warnings:**\n`; for (const warning of estimate.warnings) { output += `- ${warning}\n`; } output += "\n"; } if (startTime) { output += `### 📅 Timeline\n\n`; output += `- **Start Cooking:** ${formatDateTime(startTime.startTime)}\n`; output += `- **Rest Time:** ${startTime.restTime} minutes\n`; output += `- **Buffer:** ${startTime.bufferMinutes} minutes (for variability)\n\n`; } if (profile.requiresRest) { output += `### 😴 Resting\n\n`; output += `Rest for **${profile.restTimeMinutes} minutes** before slicing.\n`; output += `Temperature will rise approximately ${profile.carryoverDegrees}°F during rest.\n\n`; } if (profile.stallRange) { output += `### 🛑 Stall Warning\n\n`; output += `This cut typically stalls between **${profile.stallRange.start}-${profile.stallRange.end}°F**.\n`; output += `The stall can last 2-4 hours. Consider wrapping to push through faster.\n\n`; } output += `### 💡 Tips\n\n`; for (const tip of profile.tips.slice(0, 5)) { output += `- ${tip}\n`; } return output; }
- src/services/cooking.ts:32-52 (helper)Helper function to compute target and pull temperatures based on protein type and doneness level, accounting for carryover cooking. Called by the main handler.export function getTargetTemperature( proteinType: ProteinType, doneness?: DonenessLevel ): { targetTemp: number; pullTemp: number; doneness: DonenessLevel } { const profile = getProteinProfile(proteinType); // Determine the doneness to use let actualDoneness: DonenessLevel; if (doneness && profile.donenessTemps[doneness] !== undefined) { actualDoneness = doneness; } else { // Use the first available doneness (most common/recommended) const availableDoneness = Object.keys(profile.donenessTemps) as DonenessLevel[]; actualDoneness = availableDoneness[0]; } const targetTemp = profile.donenessTemps[actualDoneness] ?? profile.usdaSafeTemp; const pullTemp = targetTemp - profile.carryoverDegrees; return { targetTemp, pullTemp, doneness: actualDoneness }; }