bbq_get_cooking_guidance
Plan BBQ cooks by getting target temperatures, time estimates, and expert tips for specific proteins based on weight, desired doneness, and cooking method.
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. Computes cooking guidance using protein profile, target temps, cook time estimates, and optional timeline. Supports markdown and JSON output formats.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 schema defining input parameters and validation for the bbq_get_cooking_guidance tool, including protein_type, weight, doneness, method, serving_time.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-261 (registration)Registration of bbq_get_cooking_guidance tool in main index.ts entrypoint, linking schema and handler with metadata 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, }, }, 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/smithery.ts:81-132 (handler)Alternative handler implementation for Smithery deployment with inline Zod schema. Logic mirrors main handler.server.tool( "bbq_get_cooking_guidance", "Get comprehensive cooking guidance for a protein", { protein_type: z.string().describe("Type of protein (e.g., 'beef_brisket')"), weight_pounds: z.number().positive().describe("Weight in pounds"), target_doneness: z.string().optional().describe("Target doneness level"), cook_method: z.string().optional().describe("Cooking method"), serving_time: z.string().optional().describe("Target serving time (ISO 8601)"), }, async ({ protein_type, weight_pounds, target_doneness, cook_method, serving_time }) => { try { const profile = getProteinProfile(protein_type as ProteinType); const method = (cook_method as CookMethod) || getRecommendedCookMethod(protein_type as ProteinType); const { targetTemp, pullTemp, doneness } = getTargetTemperature( protein_type as ProteinType, target_doneness as DonenessLevel | undefined ); const timeEstimate = estimateCookTime(protein_type as ProteinType, weight_pounds, method); let startTimeInfo: { startTime: Date; restTime: number; bufferMinutes: number } | undefined; if (serving_time) { const result = calculateStartTime( protein_type as ProteinType, weight_pounds, method, new Date(serving_time) ); startTimeInfo = { startTime: result.startTime, restTime: result.restTime, bufferMinutes: result.bufferMinutes, }; } const markdown = formatCookingGuidanceMarkdown( profile, weight_pounds, targetTemp, pullTemp, doneness, method, timeEstimate, startTimeInfo ); return { content: [{ type: "text", text: markdown }] }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; return { content: [{ type: "text", text: `Error: ${message}` }], isError: true }; } }
- src/services/cooking.ts:32-52 (helper)Key helper function getTargetTemperature used by the handler to compute target and pull temperatures based on protein and doneness.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 }; }