Skip to main content
Glama

bbq_analyze_temperature

Analyze live BBQ temperature data to assess progress, detect stalls, estimate remaining cook time, and provide actionable recommendations for optimal results.

Instructions

Analyze current temperature reading and provide progress assessment, trend analysis, and recommendations.

Use this tool to interpret live temperature data from a thermometer. It provides:

  • Progress percentage toward target

  • Temperature trend (rising, falling, stalled, stable)

  • Rate of temperature change per hour

  • Estimated time remaining

  • Stall detection

  • Actionable recommendations

Args:

  • current_temp: Current internal temperature in °F

  • target_temp: Target internal temperature in °F

  • protein_type: Type of protein being cooked

  • cook_method: Cooking method (optional)

  • cook_start_time: When cook started, ISO 8601 format (optional)

  • previous_readings: Array of {temp, timestamp} for trend analysis (optional)

  • response_format: 'markdown' or 'json'

Examples:

  • "My brisket is at 165°F, target is 203°F" -> current_temp=165, target_temp=203, protein_type='beef_brisket'

  • "Temperature hasn't moved in 2 hours" -> Include previous_readings for stall detection

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
current_tempYesCurrent internal temperature reading in Fahrenheit
target_tempYesTarget internal temperature in Fahrenheit
protein_typeYesType of protein being cooked
cook_methodNoCooking method being used
cook_start_timeNoWhen the cook started in ISO 8601 format (e.g., '2024-12-25T06:00:00')
previous_readingsNoPrevious temperature readings to calculate trend (most recent last)
response_formatNoOutput formatmarkdown

Implementation Reference

  • Core handler function that performs temperature analysis, calculates progress percentage, detects trends and stalls, estimates time remaining, and generates cooking recommendations.
    export function analyzeTemperature( currentTemp: number, targetTemp: number, proteinType: ProteinType, cookMethod?: CookMethod, cookStartTime?: Date, previousReadings?: Array<{ temp: number; timestamp: Date }> ): TemperatureAnalysis { const profile = getProteinProfile(proteinType); const tempDelta = targetTemp - currentTemp; const startingTemp = 40; // Assume refrigerator temp as starting point const totalTempRange = targetTemp - startingTemp; const tempProgress = currentTemp - startingTemp; const percentComplete = Math.min(100, Math.max(0, (tempProgress / totalTempRange) * 100)); // Determine trend from previous readings let trend: "rising" | "falling" | "stable" | "stalled" = "stable"; let trendRatePerHour = 0; if (previousReadings && previousReadings.length >= 2) { const recentReadings = previousReadings.slice(-5); // Look at last 5 readings const firstReading = recentReadings[0]; const lastReading = recentReadings[recentReadings.length - 1]; const tempChange = lastReading.temp - firstReading.temp; const timeChange = (lastReading.timestamp.getTime() - firstReading.timestamp.getTime()) / (1000 * 60 * 60); // hours if (timeChange > 0) { trendRatePerHour = tempChange / timeChange; if (Math.abs(trendRatePerHour) < 2) { // Less than 2°F/hour trend = profile.stallRange && currentTemp >= profile.stallRange.start && currentTemp <= profile.stallRange.end ? "stalled" : "stable"; } else if (trendRatePerHour > 0) { trend = "rising"; } else { trend = "falling"; } } } // Check if in stall zone const inStallZone = profile.stallRange !== undefined && currentTemp >= profile.stallRange.start && currentTemp <= profile.stallRange.end; // Estimate time remaining let estimatedMinutesRemaining: number | null = null; if (trendRatePerHour > 0 && trend === "rising") { const hoursRemaining = tempDelta / trendRatePerHour; estimatedMinutesRemaining = Math.round(hoursRemaining * 60); } else if (trend === "stalled") { // During stall, estimate based on typical stall duration estimatedMinutesRemaining = null; // Can't reliably estimate during stall } // Generate recommendations const recommendations: string[] = []; if (inStallZone && trend === "stalled") { recommendations.push("🛑 You're in the stall zone! Temperature may plateau for 2-4 hours."); recommendations.push( "💡 Consider wrapping in butcher paper or foil (Texas crutch) to push through faster." ); } else if (inStallZone && trend === "rising") { recommendations.push("📈 Temperature is rising through the stall zone - looking good!"); } if (tempDelta <= profile.carryoverDegrees + 5) { recommendations.push( `🎯 Getting close! Consider pulling at ${targetTemp - profile.carryoverDegrees}°F to account for carryover.` ); } if (tempDelta <= 0) { recommendations.push("✅ Target temperature reached! Time to rest."); if (profile.requiresRest) { recommendations.push(`⏰ Rest for ${profile.restTimeMinutes} minutes before slicing.`); } } if (trend === "falling") { recommendations.push("⚠️ Temperature is dropping - check your heat source!"); if (cookMethod?.includes("smoke")) { recommendations.push("🔥 You may need to add more fuel or adjust airflow."); } } if (percentComplete < 25 && previousReadings && previousReadings.length > 0) { recommendations.push("🕐 Still in early stages - patience is key!"); } return { currentTemp, targetTemp, tempDelta, percentComplete: Math.round(percentComplete * 10) / 10, trend, trendRatePerHour: Math.round(trendRatePerHour * 10) / 10, estimatedMinutesRemaining, inStallZone, recommendations, };
  • Zod schema defining the input parameters and validation for the bbq_analyze_temperature tool.
    export const AnalyzeTemperatureSchema = z .object({ current_temp: z.number().min(-40).max(500).describe("Current internal temperature reading in Fahrenheit"), target_temp: z.number().min(100).max(250).describe("Target internal temperature in Fahrenheit"), protein_type: ProteinTypeSchema.describe("Type of protein being cooked"), cook_method: CookMethodSchema.optional().describe("Cooking method being used"), cook_start_time: z .string() .optional() .describe("When the cook started in ISO 8601 format (e.g., '2024-12-25T06:00:00')"), previous_readings: z .array( z.object({ temp: z.number().describe("Temperature reading"), timestamp: z.string().describe("Time of reading in ISO 8601 format"), }) ) .optional() .describe("Previous temperature readings to calculate trend (most recent last)"), response_format: ResponseFormatSchema.describe("Output format"), }) .strict(); export type AnalyzeTemperatureInput = z.infer<typeof AnalyzeTemperatureSchema>;
  • src/index.ts:267-350 (registration)
    MCP server tool registration including schema reference, description, annotations, and inline handler that delegates to analyzeTemperature core logic and formatting.
    server.registerTool( "bbq_analyze_temperature", { title: "Analyze Temperature Progress", description: `Analyze current temperature reading and provide progress assessment, trend analysis, and recommendations. Use this tool to interpret live temperature data from a thermometer. It provides: - Progress percentage toward target - Temperature trend (rising, falling, stalled, stable) - Rate of temperature change per hour - Estimated time remaining - Stall detection - Actionable recommendations Args: - current_temp: Current internal temperature in °F - target_temp: Target internal temperature in °F - protein_type: Type of protein being cooked - cook_method: Cooking method (optional) - cook_start_time: When cook started, ISO 8601 format (optional) - previous_readings: Array of {temp, timestamp} for trend analysis (optional) - response_format: 'markdown' or 'json' Examples: - "My brisket is at 165°F, target is 203°F" -> current_temp=165, target_temp=203, protein_type='beef_brisket' - "Temperature hasn't moved in 2 hours" -> Include previous_readings for stall detection`, inputSchema: AnalyzeTemperatureSchema, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async (params: AnalyzeTemperatureInput) => { try { const previousReadings = params.previous_readings?.map((r) => ({ temp: r.temp, timestamp: new Date(r.timestamp), })); const cookStart = params.cook_start_time ? new Date(params.cook_start_time) : undefined; const analysis = analyzeTemperature( params.current_temp, params.target_temp, params.protein_type, params.cook_method, cookStart, previousReadings ); if (params.response_format === "json") { const output = { currentTemp: analysis.currentTemp, targetTemp: analysis.targetTemp, tempDelta: analysis.tempDelta, percentComplete: analysis.percentComplete, trend: analysis.trend, trendRatePerHour: analysis.trendRatePerHour, estimatedMinutesRemaining: analysis.estimatedMinutesRemaining, inStallZone: analysis.inStallZone, recommendations: analysis.recommendations, }; return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }], structuredContent: output, }; } const markdown = formatTemperatureAnalysisMarkdown(analysis); 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 analyzing temperature: ${message}` }], }; } } );
  • Helper function to format the temperature analysis results as human-readable Markdown output.
    export function formatTemperatureAnalysisMarkdown(analysis: TemperatureAnalysis): string { let output = `## 🌡️ Temperature Analysis\n\n`; output += `**Current:** ${analysis.currentTemp}°F → **Target:** ${analysis.targetTemp}°F\n`; output += `**Progress:** ${analysis.percentComplete}% complete\n`; output += `**Remaining:** ${analysis.tempDelta}°F to go\n\n`; const trendEmoji = analysis.trend === "rising" ? "📈" : analysis.trend === "falling" ? "📉" : analysis.trend === "stalled" ? "⏸️" : "➡️"; output += `### Trend: ${trendEmoji} ${analysis.trend.charAt(0).toUpperCase() + analysis.trend.slice(1)}\n\n`; if (analysis.trendRatePerHour !== 0) { output += `**Rate:** ${analysis.trendRatePerHour > 0 ? "+" : ""}${analysis.trendRatePerHour}°F/hour\n`; } if (analysis.estimatedMinutesRemaining !== null) { const hours = Math.floor(analysis.estimatedMinutesRemaining / 60); const minutes = analysis.estimatedMinutesRemaining % 60; const timeString = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`; output += `**ETA:** ~${timeString} remaining\n`; } else if (analysis.inStallZone) { output += `**ETA:** Cannot estimate during stall\n`; } if (analysis.inStallZone) { output += `\n⚠️ **Currently in the stall zone!**\n`; } if (analysis.recommendations.length > 0) { output += `\n### Recommendations\n\n`; for (const rec of analysis.recommendations) { output += `${rec}\n`; } } return output; }

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/jweingardt12/bbq-mcp'

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