Skip to main content
Glama

get_price_forecast

Predict flight and hotel price trends to determine optimal booking timing. Analyzes historical data to recommend whether to buy now or wait for better rates.

Instructions

Get Hopper's AI price forecast for a flight or hotel. Returns whether to buy now, wait for lower prices, or watch for changes — with confidence percentage and reasoning.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
trip_typeYesType of travel to forecast
originNoIATA airport code for flight origin (required for flights)
destinationYesDestination city or IATA code
travel_dateYesTravel/check-in date in YYYY-MM-DD format
return_dateNoReturn/check-out date for round trips or hotel stays (YYYY-MM-DD)

Implementation Reference

  • The handler function 'getPriceForecast' which scrapes price forecast information from hopper.com.
    async function getPriceForecast(params: PriceForecastParams): Promise<string> {
      const page = await session.newPage();
      try {
        let url: string;
        if (params.trip_type === "flight" && params.origin) {
          url =
            `https://www.hopper.com/flights/${params.origin}/${params.destination}` +
            `?departure=${params.travel_date}` +
            (params.return_date ? `&return=${params.return_date}` : "");
        } else {
          url =
            `https://www.hopper.com/hotels/${encodeURIComponent(params.destination)}` +
            `?checkin=${params.travel_date}` +
            (params.return_date ? `&checkout=${params.return_date}` : "");
        }
    
        await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
        await page.waitForTimeout(3000);
    
        const forecast = await page.evaluate(() => {
          const body = document.body.textContent ?? "";
          const recommendation = body.match(/\b(buy now|wait|watch prices|prices are low|prices are high)\b/gi)?.[0] ?? null;
          const confidence = body.match(/(\d+)%\s*confidence/i)?.[1] ?? null;
          const priceHistory = body.match(/was\s*\$(\d[\d,]*)/i)?.[1] ?? null;
          const forecastedPrice = body.match(/forecast[^\$]*\$(\d[\d,]*)/i)?.[1] ?? null;
          return { recommendation, confidence, priceHistory, forecastedPrice };
        });
    
        const currentPrices = await page.evaluate(() => {
          const prices: number[] = [];
          document.querySelectorAll("[class*='price'], [class*='Price']").forEach((el) => {
            const m = el.textContent?.match(/\$(\d[\d,]*)/);
            if (m) prices.push(parseInt(m[1].replace(",", "")));
          });
          return prices.filter((p) => p > 0).slice(0, 5);
        });
    
        const avgPrice = currentPrices.length > 0
          ? Math.round(currentPrices.reduce((a, b) => a + b, 0) / currentPrices.length)
          : null;
    
        const result = {
          trip_type: params.trip_type,
          destination: params.destination,
          origin: params.origin,
          travel_date: params.travel_date,
          return_date: params.return_date,
          recommendation: forecast.recommendation ?? deriveRecommendation(currentPrices),
          confidence_pct: forecast.confidence ? parseInt(forecast.confidence) : null,
          current_avg_price_usd: avgPrice,
          historical_avg_usd: forecast.priceHistory ? parseInt(forecast.priceHistory.replace(",", "")) : null,
          forecasted_price_usd: forecast.forecastedPrice ? parseInt(forecast.forecastedPrice.replace(",", "")) : null,
          analysis: buildAnalysis(params, avgPrice, forecast.recommendation),
          source_url: page.url(),
          retrieved_at: new Date().toISOString(),
        };
  • src/index.ts:626-642 (registration)
    Tool registration for 'get_price_forecast'.
      name: "get_price_forecast",
      description:
        "Get Hopper's AI price forecast for a flight or hotel. Returns whether to buy now, wait for lower prices, or watch for changes — with confidence percentage and reasoning.",
      inputSchema: {
        type: "object",
        properties: {
          trip_type: { type: "string", enum: ["flight", "hotel"], description: "Type of travel to forecast" },
          origin: { type: "string", description: "IATA airport code for flight origin (required for flights)" },
          destination: { type: "string", description: "Destination city or IATA code" },
          travel_date: { type: "string", description: "Travel/check-in date in YYYY-MM-DD format" },
          return_date: { type: "string", description: "Return/check-out date for round trips or hotel stays (YYYY-MM-DD)" },
        },
        required: ["trip_type", "destination", "travel_date"],
      },
    },
    {
      name: "set_price_alert",
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. Compensates by disclosing return value structure: categorical recommendation (buy/wait/watch), confidence percentage, and reasoning. Lacks operational details like rate limits or caching, but covers the critical behavioral trait of what the forecast contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with zero waste. Front-loaded action ('Get...') followed immediately by return value specification. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 100% schema coverage and no output schema, description adequately compensates by explaining return values. Missing only forecast horizon/validity window details. Sufficient for agent to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so parameters are fully documented in structured fields. Description implicitly references trip_type via 'flight or hotel' but adds no semantic detail beyond schema (no examples, formats, or conditional logic explanations). Baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb 'Get' + resource 'AI price forecast' + clear domain 'flight or hotel'. Distinguishes from siblings (search_flights, book_flight, set_price_alert) by emphasizing predictive analytics rather than search, booking, or alerts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage context ('whether to buy now, wait...') which signals this is for purchase timing decisions. However, lacks explicit when-not-to-use guidance or comparison to set_price_alert for ongoing monitoring vs one-time forecasts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/markswendsen-code/mcp-hopper'

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