Skip to main content
Glama

bbq_detect_stall

Detect temperature stalls during BBQ cooking by analyzing temperature trends and provide recommendations for large cuts like brisket or pork shoulder.

Instructions

Analyze temperature readings to detect if a cook is experiencing a stall.

The stall is a phenomenon where internal temperature plateaus, common with large cuts like brisket and pork shoulder. This tool analyzes temperature trend to detect stalls and provides recommendations.

Args:

  • protein_type: Type of protein being cooked

  • current_temp: Current internal temperature in °F

  • readings: Array of at least 3 readings with {temp, timestamp}

  • response_format: 'markdown' or 'json'

Examples:

  • "Is my brisket stalling?" -> Provide current_temp and readings array

  • "Temp hasn't moved in 2 hours" -> Include readings over that period

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
protein_typeYesType of protein being cooked
current_tempYesCurrent internal temperature in Fahrenheit
readingsYesAt least 3 temperature readings to analyze trend (most recent last)
response_formatNoOutput formatmarkdown

Implementation Reference

  • Core implementation of stall detection logic. Analyzes temperature readings for a given protein to determine if it's stalled, in stall zone, duration, and provides recommendations.
    export function detectStall( proteinType: ProteinType, currentTemp: number, readings: Array<{ temp: number; timestamp: Date }> ): { isStalled: boolean; stallDurationMinutes: number; inStallZone: boolean; recommendation: string; } { const profile = getProteinProfile(proteinType); // Check if this protein type typically stalls if (!profile.stallRange) { return { isStalled: false, stallDurationMinutes: 0, inStallZone: false, recommendation: `${profile.displayName} typically doesn't experience a stall.`, }; } const inStallZone = currentTemp >= profile.stallRange.start && currentTemp <= profile.stallRange.end; if (!inStallZone) { if (currentTemp < profile.stallRange.start) { return { isStalled: false, stallDurationMinutes: 0, inStallZone: false, recommendation: `Approaching stall zone (${profile.stallRange.start}-${profile.stallRange.end}°F). Be prepared for a plateau.`, }; } else { return { isStalled: false, stallDurationMinutes: 0, inStallZone: false, recommendation: "You've pushed through the stall! Temperature should rise steadily now.", }; } } // Analyze readings to determine if actually stalled (temp not rising) const recentReadings = readings.slice(-6); // Last 6 readings if (recentReadings.length < 3) { return { isStalled: false, stallDurationMinutes: 0, inStallZone: true, recommendation: "In the stall zone but need more readings to confirm stall status.", }; } // Calculate temperature change over the readings const tempChange = recentReadings[recentReadings.length - 1].temp - recentReadings[0].temp; const timeSpanMinutes = (recentReadings[recentReadings.length - 1].timestamp.getTime() - recentReadings[0].timestamp.getTime()) / (1000 * 60); const tempRatePerHour = timeSpanMinutes > 0 ? (tempChange / timeSpanMinutes) * 60 : 0; // Consider stalled if temp is rising less than 3°F per hour in the stall zone const isStalled = tempRatePerHour < 3; // Calculate how long the stall has lasted let stallDurationMinutes = 0; if (isStalled && readings.length >= 3) { // Find when temp first entered stall zone for (let i = readings.length - 1; i >= 0; i--) { if (readings[i].temp >= profile.stallRange.start && readings[i].temp <= profile.stallRange.end) { stallDurationMinutes = (new Date().getTime() - readings[i].timestamp.getTime()) / (1000 * 60); } else { break; } } } let recommendation: string; if (isStalled) { if (stallDurationMinutes < 60) { recommendation = "Stall detected! This is normal - evaporative cooling is slowing the temp rise. The stall can last 2-4 hours."; } else if (stallDurationMinutes < 180) { recommendation = `Stall has lasted ${Math.round(stallDurationMinutes)} minutes. Consider wrapping in butcher paper (Texas crutch) to push through faster.`; } else { recommendation = `Extended stall (${Math.round(stallDurationMinutes)} minutes). Wrapping is strongly recommended, or you can ride it out - eventually, it will break through.`; } } else { recommendation = "In the stall zone but temperature is still rising. Keep monitoring - you may push through without a major plateau."; } return { isStalled, stallDurationMinutes: Math.round(stallDurationMinutes), inStallZone, recommendation, }; }
  • src/index.ts:621-684 (registration)
    MCP tool registration including schema reference, description, and thin wrapper handler that calls the core detectStall function and handles formatting/response.
    server.registerTool( "bbq_detect_stall", { title: "Detect Temperature Stall", description: `Analyze temperature readings to detect if a cook is experiencing a stall. The stall is a phenomenon where internal temperature plateaus, common with large cuts like brisket and pork shoulder. This tool analyzes temperature trend to detect stalls and provides recommendations. Args: - protein_type: Type of protein being cooked - current_temp: Current internal temperature in °F - readings: Array of at least 3 readings with {temp, timestamp} - response_format: 'markdown' or 'json' Examples: - "Is my brisket stalling?" -> Provide current_temp and readings array - "Temp hasn't moved in 2 hours" -> Include readings over that period`, inputSchema: DetectStallSchema, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, }, async (params: DetectStallInput) => { try { const readings = params.readings.map((r) => ({ temp: r.temp, timestamp: new Date(r.timestamp), })); const result = detectStall(params.protein_type, params.current_temp, readings); if (params.response_format === "json") { const output = { currentTemp: params.current_temp, isStalled: result.isStalled, stallDurationMinutes: result.stallDurationMinutes, inStallZone: result.inStallZone, recommendation: result.recommendation, proteinType: params.protein_type, readingsAnalyzed: readings.length, }; return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }], structuredContent: output, }; } const markdown = formatStallDetectionMarkdown(result, params.current_temp); 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 detecting stall: ${message}` }], }; } } );
  • Zod input schema for the bbq_detect_stall tool defining parameters: protein_type, current_temp, readings array, response_format.
    export const DetectStallSchema = z .object({ protein_type: ProteinTypeSchema.describe("Type of protein being cooked"), current_temp: z.number().min(100).max(250).describe("Current internal temperature in Fahrenheit"), readings: z .array( z.object({ temp: z.number().describe("Temperature reading"), timestamp: z.string().describe("Time of reading in ISO 8601 format"), }) ) .min(3) .describe("At least 3 temperature readings to analyze trend (most recent last)"), response_format: ResponseFormatSchema.describe("Output format"), }) .strict(); export type DetectStallInput = z.infer<typeof DetectStallSchema>;
  • Markdown formatter for stall detection results, used by the tool handler for 'markdown' response format.
    export function formatStallDetectionMarkdown( result: { isStalled: boolean; stallDurationMinutes: number; inStallZone: boolean; recommendation: string; }, currentTemp: number ): string { let output = `## 🛑 Stall Analysis\n\n`; output += `**Current Temperature:** ${currentTemp}°F\n`; output += `**In Stall Zone:** ${result.inStallZone ? "Yes" : "No"}\n`; output += `**Stalled:** ${result.isStalled ? "Yes" : "No"}\n`; if (result.isStalled) { output += `**Stall Duration:** ${result.stallDurationMinutes} minutes\n`; } output += `\n### Recommendation\n\n${result.recommendation}\n`; if (result.isStalled) { output += `\n### Options to Push Through\n\n`; output += `1. **Wrap (Texas Crutch):** Wrap in butcher paper or foil to trap moisture and speed cooking\n`; output += `2. **Increase Heat:** Bump smoker to 275-300°F temporarily\n`; output += `3. **Ride It Out:** Be patient - stall will eventually break\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