Koskamo

FlightPowers Google Flights MCP

A hosted Model Context Protocol server returning real-time flight data. It provides read-only tools to search one-way and round-trip flights, offering price insights and verdicts based on Google's historical data. The service is independent and not affiliated with Google.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

FlightPowers Google Flights MCP logo, by FlightPowersVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-06Operated by FlightPowers
You need:Get a key, free tier available, at https://rapidapi.com/mtnrabi/api/google-flights-live-api
MCP endpoint (Streamable HTTP)
https://flights.flightpowers.com/mcp
Vendor documentation

What its tools do

2 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

2 of 2 have a description · 2 of 2 declare behavior hints · 2 of 2 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Passed Official MCP Registry namespace is tied to flightpowers.com ·
  • Passed Endpoint is on the registry namespace domain ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Search one-way flights with date ranges
  • Search round-trip flights with paired itineraries
  • Retrieve price insights and verdicts
  • Get deep links to Google Flights

Source and maintenance

Vendor evidenceRegistry 1.2.0
Maintenance checked

Protocol and capabilities

Server
google-flights-mcp 1.0.0
MCP protocol negotiated in check
2025-11-25
Tools
2 advertised
Resources
1 advertised
Resource templates
0 advertised
Prompts
4 advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "logging": {},
  "prompts": {
    "listChanged": true
  },
  "resources": {
    "subscribe": false,
    "listChanged": true
  },
  "extensions": {
    "io.modelcontextprotocol/ui": {}
  },
  "experimental": {}
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

FlightPowers: real-time Google Flights fare search. 10 free searches a day after sign-in with Google, shared by FlightPowers' flights and hotels servers, nothing to paste; with the caller's own RapidAPI key, connected at https://flights.flightpowers.com/connect, searches run on their RapidAPI plan instead of this allowance. `search_oneway_flights` and `search_roundtrip_flights` return live fares, not schedules. Both accept a date RANGE and a LIST of destination airports and expand them internally, so one call covers a whole range of dates and destinations. Round trips take a `nights` value instead of a fixed return date. Every result carries Google's own historical range for that route and period (`price_insights_low`, `price_insights_high`, and a `price_range_in_relation_to_other_periods` verdict of low / typical / high) that places a fare against its usual range, and a `buy_link` to book it. `search_coverage` lists the dates and destinations the answer is actually based on, which on a sampled search is less than the whole range asked for. A wide search answers with the TOP `results_returned` of `results_total` fares found -- by the requested `sort_by`, cheapest first by default, and never all of one destination at the expense of another -- each row carrying the dates, the destination, trip length in nights, airline, stops, duration, price and the booking link. The two numbers differ only when the server raised `limit` itself to cover the fan-out, and `search_coverage.note` then says so. `by_destination` names every requested destination's own cheapest fare whether or not it fits in `results`, so it answers 'which destination is cheapest' without scanning the rows. `verbose: true` returns every selected row and every upstream field, which on a month-wide search is a megabyte of JSON some hosts will not accept; it is needed only for a field the compact rows drop or for rows past `results_returned`. Fan-out is capped at 30 date/destination combinations per call, and, with the caller's own key, the cap RISES BY ITSELF, up to 300, when the question is bigger than that -- a whole month of departures at three trip lengths is 93 combinations and runs as one call, and so does a whole month at three trip lengths across three destinations (279). On the free sign-in allowance it does not rise: a question larger than what is left of the day's free searches is refused before anything runs; a narrower question fits, and so does `max_searches` set to sample it. `max_searches` sets it explicitly, up or down, to a hard maximum of 300. A request past the cap in force is sampled evenly across the range and says so in `search_coverage`, which also names the cap and why it is that number (`max_searches_source`). Every combination is one search: a whole month at one destination and three trip lengths is 93 searches, the same month over two destinations is 186, and a whole month x 3 nights x 3 destinations is about 279 and takes a couple of minutes. With the caller's own key each search is one request on their RapidAPI plan, and `api_usage.hub_requests_billed` is what that plan was actually charged -- higher than the combination count when a failed search was retried. Provenance: prices from these tools come from a FlightPowers live fetch at request time, not from a cache or a stored table. A price is only meaningful together with the time it was fetched. Results are live prices and go stale within minutes: a current price comes from a new search, not from an earlier result or a cached number, and each price belongs with the time it was fetched. Every response carries `api_usage`. With the caller's own key it is what this call spent on their RapidAPI plan and what is left of it. On the free sign-in allowance each combination is one of the day's free searches, nothing is billed to the user, and `api_usage` carries the free-search counter instead of plan figures; a search larger than what is left today is refused before anything runs; a narrower question (fewer dates, nights or destinations) fits, and a wider grid needs the caller's own key.

Tools

2 advertised

search_oneway_flights — FlightPowers: search one-way flights
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

FlightPowers one-way fare search: live prices read from Google Flights. Input: origin and destination IATA codes -- the destination may be several codes, as "BCN,LIS,ATH" or ["BCN","LIS","ATH"] -- plus either one departure date or a date range. Returns each flight's price, airline, duration, stops, a bookable buy_link, and Google's historical price range (price_insights_low / price_insights_high), the band that shows whether a fare is actually a good deal. Suited to any one-way fare question, including open-ended ones. One call accepts a date range and several destinations and searches every combination: 'Cheapest flight to Sri Lanka anywhere in October' is one call, not thirty. That holds with the caller's own key. On the free sign-in allowance (10 searches a day, one per combination) a grid larger than what is left today is refused before anything runs; a grid within what is left runs, and a whole-month scan needs the caller's own key. Each date/destination combination is one search; the count comes back in `api_usage`. `by_destination` carries one entry per requested destination -- empty ones included, each with a `reason` that separates a destination with no flights from one that was not searched, whose search failed, or whose fares did not fit in `limit`. Fares go stale within minutes: a current price comes from a new search, not from an earlier result.

search_oneway_flights input schema
{
  "type": "object",
  "required": [
    "from_airport",
    "to_airport"
  ],
  "properties": {
    "limit": {
      "type": "integer",
      "default": 10,
      "description": "Maximum flights to return, after merging and sorting."
    },
    "sort_by": {
      "type": "string",
      "default": "best",
      "description": "\"best\" (the default) and \"price\" both order by price, cheapest first; \"duration\" orders shortest first. Applied across all results."
    },
    "verbose": {
      "type": "boolean",
      "default": false,
      "description": "Returns every field the upstream sends on each fare, and every fare that was selected, with no row bound. Off by default: a result carries the best rows by the requested sort_by in a compact shape (dates, destination, airline, stops, duration, price, trip length and the booking link), because a wide search over a month and several destinations otherwise produces a megabyte of JSON that some hosts refuse to put in the conversation at all. When true, it adds the arrival times, the per-leg stop counts, the raw stop details and every row past results_returned; results_total always says how many there were."
    },
    "currency": {
      "type": "string",
      "default": "usd",
      "description": "ISO currency code, default \"usd\"."
    },
    "max_price": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only flights at or below this price are returned."
    },
    "max_stops": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Maximum stops per flight. 0 means non-stop only."
    },
    "seat_type": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "1 economy, 2 premium economy, 3 business, 4 first."
    },
    "passengers": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "integer"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "One entry per traveller, not a count: 1 adult, 2 child (aged 2-11), 3 infant on lap, 4 infant in seat, e.g. [1, 1, 2] for two adults and a child. At least one adult, each infant on lap needs its own adult, at most 9. Left out, it means one adult. A counts list [adults, children, infants], e.g. [2, 1, 0], or a bare [2] for two adults, is recognised and converted to codes before the search; a list that is valid as codes is searched as codes."
    },
    "to_airport": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      ],
      "description": "Destination airport. One IATA code (\"BCN\"), several separated by commas (\"BCN,LIS,ATH\"), or a list ([\"BCN\",\"LIS\",\"ATH\"]) -- every shape is accepted and the destinations are compared in the same search."
    },
    "from_airport": {
      "type": "string",
      "description": "Origin IATA code, e.g. \"TLV\". One origin per search; a second one is refused rather than searched."
    },
    "max_searches": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "The searches this call may make, up or down. Unset is the normal behaviour: with the caller's own key the cap covers the request when the request is reasonable (a whole month at three trip lengths is 93 combinations and a whole month x 3 nights x 3 destinations is 279; both run in full) and anything past it is sampled evenly across the range rather than cut short. A lower value spends fewer searches on a wide search; a higher one -- to a hard maximum of 300 -- covers a grid wider than that."
    },
    "use_fallback": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Default: unset. Switches the search to a second, independent flight data source instead of the usual Google Flights page read. Unset already escalates to that source once, automatically, after a search's retries have failed. true forces it inline on every attempt -- much slower, and it can time out. false disables it entirely, that automatic retry included."
    },
    "airline_codes": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Restricts the search to these airline codes, e.g. [\"LY\"]."
    },
    "departure_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Single departure date, \"YYYY-MM-DD\"."
    },
    "arrival_time_max": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Latest arrival hour, 0-23."
    },
    "arrival_time_min": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Earliest arrival hour, 0-23."
    },
    "departure_date_to": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Last date of a departure range."
    },
    "departure_time_max": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Latest departure hour, 0-23."
    },
    "departure_time_min": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Earliest departure hour, 0-23."
    },
    "departure_date_from": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "First date of a departure range."
    },
    "exclude_airline_codes": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Airline codes left out of the results."
    }
  },
  "additionalProperties": false
}
search_oneway_flights output schema
{
  "type": "object",
  "title": "Flight search result",
  "required": [
    "results"
  ],
  "properties": {
    "message": {
      "type": "string",
      "description": "Present when the result carries a statement for the person who asked -- no results, a degraded search, a missing key or a spent quota."
    },
    "partial": {
      "type": "string",
      "description": "Present when some searches failed but others succeeded. Plain text saying how much of the request the results cover."
    },
    "results": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": true
      },
      "description": "The fares found, already sorted and deduplicated. An empty array is only meaningful when search_status is 'empty'.\n\nThis is the TOP results_returned of results_total rows by the requested sort -- cheapest first by default, shortest first on sort_by 'duration' -- with every destination that has fares still represented. Each row is in a compact shape: destination, the date or dates, trip length in nights on a round trip, airline (both legs on a round trip), stops, duration, the price as a string and a number, Google's price band with its verdict, and the booking link. The origin is on the response as from_airport rather than repeated on every row. Arrival descriptions, per-leg stop counts, raw stop details and the duration in seconds are dropped; `verbose: true` returns them, and every row that was selected, on that call."
    },
    "api_usage": {
      "type": "object",
      "properties": {
        "note": {
          "type": "string",
          "description": "The same figures as one plain sentence."
        },
        "hub_requests_billed": {
          "type": "integer",
          "minimum": 0,
          "description": "How many HTTP requests RapidAPI actually billed. Larger than requests_used_by_this_call when a search failed with a server error and was retried, because the retry is billed too. With the caller's own key this is the figure their RapidAPI plan is charged. Absent on a free search."
        },
        "plan_requests_limit": {
          "type": "integer"
        },
        "free_searches_day_cap": {
          "type": "integer",
          "minimum": 0
        },
        "plan_requests_remaining": {
          "type": "integer"
        },
        "free_searches_used_today": {
          "type": "integer",
          "minimum": 0
        },
        "requests_used_by_this_call": {
          "type": "integer",
          "minimum": 0,
          "description": "How many date/destination combinations were searched -- what the answer COVERS."
        },
        "free_searches_remaining_today": {
          "type": "integer",
          "minimum": 0
        }
      },
      "description": "With the caller's own key: what this call cost their RapidAPI plan, and what remains on it. On a free signed-in search (`trial` present): the day's free-search counter instead, and no plan figures -- the search ran on FlightPowers' key and nothing is billed to the user. Present on every response that reached the upstream, including a degraded one.",
      "additionalProperties": true
    },
    "signup_url": {
      "type": "string",
      "description": "Where the caller subscribes or changes plan."
    },
    "from_airport": {
      "type": "string",
      "description": "The origin, as the upstream renders it ('Tel Aviv (TLV)'). One origin per search, so it is on the response rather than repeated on every row."
    },
    "result_count": {
      "type": "integer",
      "minimum": 0,
      "description": "How many rows are in `results`; same as results_returned."
    },
    "needs_api_key": {
      "type": "boolean",
      "description": "True when no usable RapidAPI key arrived with the call, or the upstream rejected the one that did. No search was run and nothing was billed; signup_url and message describe the fix."
    },
    "results_total": {
      "type": "integer",
      "minimum": 0,
      "description": "How many fares the search selected across every searched combination, before any row bound. Equal to results_returned unless the server bounded a response it had widened itself."
    },
    "search_status": {
      "enum": [
        "ok",
        "empty",
        "partial",
        "degraded",
        "trial_exhausted",
        "quota_exceeded"
      ],
      "type": "string",
      "description": "Whether the underlying search actually completed, read from the backend's X-Search-Status header. 'ok': every combination searched returned results. 'empty': the search completed and Google genuinely has no itineraries for it -- a real answer, not a failure. 'partial': some combinations returned results and some failed, so the list is incomplete. 'degraded': every combination failed, so the search did not happen and an empty list means nothing; this case is also flagged with isError: true. A repeat is a new billed request: repeat it at most once, and not when the error says the backend expects a repeat to fail (retry: false). 'trial_exhausted': the free signed-in allowance on this server is spent for today, so nothing was searched and nothing was billed; it renews at 00:00 UTC and the caller's own RapidAPI key, once connected, removes the cap. Retrying does not help. 'quota_exceeded': the search was refused because the caller's remaining allowance or plan quota cannot cover the number of combinations asked for; combos_requested and combos_allowed_now carry the two numbers. Nothing was searched beyond what it cost to read the quota. Retrying the same search does not help; a request with fewer dates or nights, or a larger plan, does."
    },
    "by_destination": {
      "type": "object",
      "description": "One entry per destination the REQUEST asked for, in request order, present whether or not that destination has any flights in `results`. A destination with an empty `rows` array is a hole in the answer, and `reason` says which kind of hole: 'no_flights' (searched, answered, Google has nothing), 'search_failed' (searched and the search errored, so nothing is known), 'not_in_limit' (searched, found flights, none fitted in `limit`) or 'not_searched' (never searched -- the per-call fan-out cap sampled it away). 'ok' means it has rows.\n\nCoverage comes from here, not from `results`: a destination missing from `results` looks identical to one that has no flights, and they are not the same answer. `row_count` is how many of this destination's fares were selected; the fares themselves are in `results` and are not repeated here. `verbose: true` restores the `rows` array for callers that consume it.",
      "additionalProperties": {
        "type": "object",
        "required": [
          "row_count",
          "searched",
          "reason"
        ],
        "properties": {
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Only on `verbose: true`: this destination's selected rows, the same objects that are in `results`."
          },
          "dates": {
            "type": "object",
            "description": "Present only on multi-date searches: one entry per departure date requested for this destination, so a date the fan-out cap sampled away is visible rather than absent. `cheapest_price` is null when that date has no row in `results`.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "reason": {
                  "enum": [
                    "ok",
                    "no_flights",
                    "search_failed",
                    "not_in_limit",
                    "not_searched"
                  ],
                  "type": "string"
                },
                "searched": {
                  "type": "boolean"
                },
                "row_count": {
                  "type": "integer",
                  "minimum": 0
                },
                "cheapest_price": {
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "additionalProperties": true
            }
          },
          "reason": {
            "enum": [
              "ok",
              "no_flights",
              "search_failed",
              "not_in_limit",
              "not_searched"
            ],
            "type": "string"
          },
          "cheapest": {
            "anyOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The lowest-priced of this destination's rows in `results`, or null when it has none."
          },
          "searched": {
            "type": "boolean",
            "description": "Whether at least one search actually ran for this destination. False means the fan-out cap dropped it."
          },
          "row_count": {
            "type": "integer",
            "minimum": 0,
            "description": "How many of this destination's fares were selected. Not all of them are necessarily in `results`: a wide search returns the top results_returned of results_total overall, and `cheapest` below is this destination's own best fare either way."
          }
        },
        "additionalProperties": true
      }
    },
    "quota_exhausted": {
      "type": "boolean",
      "description": "True when the caller's RapidAPI plan has no requests left for the current period."
    },
    "search_coverage": {
      "type": "object",
      "properties": {
        "note": {
          "type": "string"
        },
        "truncated": {
          "type": "boolean",
          "description": "True when the request expanded past this call's spend ceiling and was sampled. A date absent from departure_dates_searched was never searched, which is not the same as having no flights."
        },
        "stopped_early": {
          "type": "string",
          "description": "Present when something other than the cap ended the fan-out. 'deadline': the call reached its time limit and the remaining combinations were never sent or billed, so the results are real but cover only part of the range."
        },
        "hub_requests_billed": {
          "type": "integer",
          "minimum": 0,
          "description": "HTTP requests billed by RapidAPI for this call, retries included; see api_usage.hub_requests_billed."
        },
        "destinations_searched": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "searched_combinations": {
          "type": "integer",
          "minimum": 0
        },
        "requested_combinations": {
          "type": "integer",
          "minimum": 0
        },
        "departure_dates_searched": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "max_searches_per_request": {
          "type": "integer",
          "minimum": 1
        }
      },
      "description": "What was actually searched. Present whether or not the request was truncated, so the answer's basis is on the record either way.",
      "additionalProperties": true
    },
    "results_returned": {
      "type": "integer",
      "minimum": 0,
      "description": "How many of them are in `results` -- the best ones by the sort_by asked for, cheapest first by default, and never all of one destination at the expense of another. Lower than results_total only when `limit` was raised by the server to cover the fan-out rather than asked for; search_coverage.note says so when it happens, and `verbose: true` returns them all."
    }
  },
  "description": "A completed flight search. An empty `results` array means 'no flights' only when search_status is 'empty'.",
  "additionalProperties": true
}
search_oneway_flights annotations
{
  "title": "FlightPowers: search one-way flights",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
search_roundtrip_flights — FlightPowers: search round-trip flights
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

FlightPowers round-trip fare search: live prices read from Google Flights, priced as paired legs rather than two separate one-ways. Input: origin and destination IATA codes -- the destination may be several codes, as "BCN,LIS,ATH" or ["BCN","LIS","ATH"] -- a departure date or range, and either a return date or a trip length in nights. Returns the total price for both legs, per-leg airline, stops and duration, and a single bookable buy_link for the trip. Suited to any return-trip fare question. A flexible search is ONE call: departure_date_from / departure_date_to set the outbound range and `nights`, in place of return_date, compares trip lengths -- '5 to 7 nights in Rome sometime in May' is one call. A WHOLE MONTH is one call too. departure_date_from "2026-10-01", departure_date_to "2026-10-31" and nights [3, 4, 5] prices every departure day in October at three trip lengths and shows which combination is cheapest. That is 93 date/night combinations and the cap rises to cover them by itself, so the whole grid runs in that one call. That holds with the caller's own key. On the free sign-in allowance (10 searches a day, one per combination) a grid larger than what is left today is refused before anything runs; a grid within what is left runs, and a whole-month scan needs the caller's own key. Each date/night/destination combination is ONE search, so a month at three trip lengths is 93 of them and the same month across two destinations is 186. A search that fails with a server error is retried once, so with the caller's own key the figure the plan is charged is `api_usage.hub_requests_billed` (retries included), not the combination count. `by_destination` carries one entry per requested destination -- empty ones included, each with a `reason` that separates a destination with no flights from one that was not searched, whose search failed, or whose fares did not fit in `limit`. Fares go stale within minutes: a current price comes from a new search, not from an earlier result.

search_roundtrip_flights input schema
{
  "type": "object",
  "required": [
    "from_airport",
    "to_airport"
  ],
  "properties": {
    "limit": {
      "type": "integer",
      "default": 10,
      "description": "Maximum trips to return, after merging and sorting."
    },
    "nights": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "array",
          "items": {
            "type": "integer"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Trip length in nights; a number, or a list like [5, 6, 7]. The return date is derived from each departure date."
    },
    "sort_by": {
      "type": "string",
      "default": "best",
      "description": "\"best\" (the default) and \"price\" both order by price, cheapest first; \"duration\" orders shortest first. Applied across all results."
    },
    "verbose": {
      "type": "boolean",
      "default": false,
      "description": "Returns every field the upstream sends on each fare, and every fare that was selected, with no row bound. Off by default: a result carries the best rows by the requested sort_by in a compact shape (dates, destination, airline, stops, duration, price, trip length and the booking link), because a wide search over a month and several destinations otherwise produces a megabyte of JSON that some hosts refuse to put in the conversation at all. When true, it adds the arrival times, the per-leg stop counts, the raw stop details and every row past results_returned; results_total always says how many there were."
    },
    "currency": {
      "type": "string",
      "default": "usd",
      "description": "ISO currency code, default \"usd\"."
    },
    "max_price": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only trips at or below this total price are returned."
    },
    "seat_type": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "1 economy, 2 premium economy, 3 business, 4 first."
    },
    "passengers": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "integer"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "One entry per traveller, not a count: 1 adult, 2 child (aged 2-11), 3 infant on lap, 4 infant in seat, e.g. [1, 1, 2] for two adults and a child. At least one adult, each infant on lap needs its own adult, at most 9. Left out, it means one adult. A counts list [adults, children, infants], e.g. [2, 1, 0], or a bare [2] for two adults, is recognised and converted to codes before the search; a list that is valid as codes is searched as codes."
    },
    "to_airport": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      ],
      "description": "Destination airport. One IATA code (\"BCN\"), several separated by commas (\"BCN,LIS,ATH\"), or a list ([\"BCN\",\"LIS\",\"ATH\"]) -- every shape is accepted and the destinations are compared in the same search."
    },
    "return_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Fixed return date. Mutually exclusive with `nights`."
    },
    "from_airport": {
      "type": "string",
      "description": "Origin IATA code, e.g. \"TLV\". One origin per search; a second one is refused rather than searched."
    },
    "max_searches": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "The searches this call may make, up or down. Unset is the normal behaviour: with the caller's own key the cap covers the request when the request is reasonable (a whole month at three trip lengths is 93 combinations and a whole month x 3 nights x 3 destinations is 279; both run in full) and anything past it is sampled evenly across the range rather than cut short. A lower value spends fewer searches on a wide search; a higher one -- to a hard maximum of 300 -- covers a grid wider than that."
    },
    "use_fallback": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Default: unset. Switches the search to a second, independent flight data source instead of the usual Google Flights page read. Unset already escalates to that source once, automatically, after a search's retries have failed. true forces it inline on every attempt -- much slower, and it can time out. false disables it entirely, that automatic retry included."
    },
    "departure_date": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Single outbound date, \"YYYY-MM-DD\"."
    },
    "max_return_stops": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Maximum stops on the return leg."
    },
    "departure_date_to": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Last date of an outbound range."
    },
    "departure_date_from": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "First date of an outbound range."
    },
    "max_departure_stops": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Maximum stops on the outbound leg."
    },
    "return_airline_codes": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Restricts the return leg to these airlines."
    },
    "returns_per_outbound": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "How many return flights to pair with each outbound flight, 1 to 5 (default 2). Each date/destination combination searched still returns at most 10 trips; at 5 they are picked from up to 50 pairings instead of 20. It adds no requests. Not applied when results come from the fallback source."
    },
    "departure_airline_codes": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Restricts the outbound leg to these airlines."
    }
  },
  "additionalProperties": false
}
search_roundtrip_flights output schema
{
  "type": "object",
  "title": "Flight search result",
  "required": [
    "results"
  ],
  "properties": {
    "message": {
      "type": "string",
      "description": "Present when the result carries a statement for the person who asked -- no results, a degraded search, a missing key or a spent quota."
    },
    "partial": {
      "type": "string",
      "description": "Present when some searches failed but others succeeded. Plain text saying how much of the request the results cover."
    },
    "results": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": true
      },
      "description": "The fares found, already sorted and deduplicated. An empty array is only meaningful when search_status is 'empty'.\n\nThis is the TOP results_returned of results_total rows by the requested sort -- cheapest first by default, shortest first on sort_by 'duration' -- with every destination that has fares still represented. Each row is in a compact shape: destination, the date or dates, trip length in nights on a round trip, airline (both legs on a round trip), stops, duration, the price as a string and a number, Google's price band with its verdict, and the booking link. The origin is on the response as from_airport rather than repeated on every row. Arrival descriptions, per-leg stop counts, raw stop details and the duration in seconds are dropped; `verbose: true` returns them, and every row that was selected, on that call."
    },
    "api_usage": {
      "type": "object",
      "properties": {
        "note": {
          "type": "string",
          "description": "The same figures as one plain sentence."
        },
        "hub_requests_billed": {
          "type": "integer",
          "minimum": 0,
          "description": "How many HTTP requests RapidAPI actually billed. Larger than requests_used_by_this_call when a search failed with a server error and was retried, because the retry is billed too. With the caller's own key this is the figure their RapidAPI plan is charged. Absent on a free search."
        },
        "plan_requests_limit": {
          "type": "integer"
        },
        "free_searches_day_cap": {
          "type": "integer",
          "minimum": 0
        },
        "plan_requests_remaining": {
          "type": "integer"
        },
        "free_searches_used_today": {
          "type": "integer",
          "minimum": 0
        },
        "requests_used_by_this_call": {
          "type": "integer",
          "minimum": 0,
          "description": "How many date/destination combinations were searched -- what the answer COVERS."
        },
        "free_searches_remaining_today": {
          "type": "integer",
          "minimum": 0
        }
      },
      "description": "With the caller's own key: what this call cost their RapidAPI plan, and what remains on it. On a free signed-in search (`trial` present): the day's free-search counter instead, and no plan figures -- the search ran on FlightPowers' key and nothing is billed to the user. Present on every response that reached the upstream, including a degraded one.",
      "additionalProperties": true
    },
    "signup_url": {
      "type": "string",
      "description": "Where the caller subscribes or changes plan."
    },
    "from_airport": {
      "type": "string",
      "description": "The origin, as the upstream renders it ('Tel Aviv (TLV)'). One origin per search, so it is on the response rather than repeated on every row."
    },
    "result_count": {
      "type": "integer",
      "minimum": 0,
      "description": "How many rows are in `results`; same as results_returned."
    },
    "needs_api_key": {
      "type": "boolean",
      "description": "True when no usable RapidAPI key arrived with the call, or the upstream rejected the one that did. No search was run and nothing was billed; signup_url and message describe the fix."
    },
    "results_total": {
      "type": "integer",
      "minimum": 0,
      "description": "How many fares the search selected across every searched combination, before any row bound. Equal to results_returned unless the server bounded a response it had widened itself."
    },
    "search_status": {
      "enum": [
        "ok",
        "empty",
        "partial",
        "degraded",
        "trial_exhausted",
        "quota_exceeded"
      ],
      "type": "string",
      "description": "Whether the underlying search actually completed, read from the backend's X-Search-Status header. 'ok': every combination searched returned results. 'empty': the search completed and Google genuinely has no itineraries for it -- a real answer, not a failure. 'partial': some combinations returned results and some failed, so the list is incomplete. 'degraded': every combination failed, so the search did not happen and an empty list means nothing; this case is also flagged with isError: true. A repeat is a new billed request: repeat it at most once, and not when the error says the backend expects a repeat to fail (retry: false). 'trial_exhausted': the free signed-in allowance on this server is spent for today, so nothing was searched and nothing was billed; it renews at 00:00 UTC and the caller's own RapidAPI key, once connected, removes the cap. Retrying does not help. 'quota_exceeded': the search was refused because the caller's remaining allowance or plan quota cannot cover the number of combinations asked for; combos_requested and combos_allowed_now carry the two numbers. Nothing was searched beyond what it cost to read the quota. Retrying the same search does not help; a request with fewer dates or nights, or a larger plan, does."
    },
    "by_destination": {
      "type": "object",
      "description": "One entry per destination the REQUEST asked for, in request order, present whether or not that destination has any flights in `results`. A destination with an empty `rows` array is a hole in the answer, and `reason` says which kind of hole: 'no_flights' (searched, answered, Google has nothing), 'search_failed' (searched and the search errored, so nothing is known), 'not_in_limit' (searched, found flights, none fitted in `limit`) or 'not_searched' (never searched -- the per-call fan-out cap sampled it away). 'ok' means it has rows.\n\nCoverage comes from here, not from `results`: a destination missing from `results` looks identical to one that has no flights, and they are not the same answer. `row_count` is how many of this destination's fares were selected; the fares themselves are in `results` and are not repeated here. `verbose: true` restores the `rows` array for callers that consume it.",
      "additionalProperties": {
        "type": "object",
        "required": [
          "row_count",
          "searched",
          "reason"
        ],
        "properties": {
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Only on `verbose: true`: this destination's selected rows, the same objects that are in `results`."
          },
          "dates": {
            "type": "object",
            "description": "Present only on multi-date searches: one entry per departure date requested for this destination, so a date the fan-out cap sampled away is visible rather than absent. `cheapest_price` is null when that date has no row in `results`.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "reason": {
                  "enum": [
                    "ok",
                    "no_flights",
                    "search_failed",
                    "not_in_limit",
                    "not_searched"
                  ],
                  "type": "string"
                },
                "searched": {
                  "type": "boolean"
                },
                "row_count": {
                  "type": "integer",
                  "minimum": 0
                },
                "cheapest_price": {
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "additionalProperties": true
            }
          },
          "reason": {
            "enum": [
              "ok",
              "no_flights",
              "search_failed",
              "not_in_limit",
              "not_searched"
            ],
            "type": "string"
          },
          "cheapest": {
            "anyOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The lowest-priced of this destination's rows in `results`, or null when it has none."
          },
          "searched": {
            "type": "boolean",
            "description": "Whether at least one search actually ran for this destination. False means the fan-out cap dropped it."
          },
          "row_count": {
            "type": "integer",
            "minimum": 0,
            "description": "How many of this destination's fares were selected. Not all of them are necessarily in `results`: a wide search returns the top results_returned of results_total overall, and `cheapest` below is this destination's own best fare either way."
          }
        },
        "additionalProperties": true
      }
    },
    "quota_exhausted": {
      "type": "boolean",
      "description": "True when the caller's RapidAPI plan has no requests left for the current period."
    },
    "search_coverage": {
      "type": "object",
      "properties": {
        "note": {
          "type": "string"
        },
        "truncated": {
          "type": "boolean",
          "description": "True when the request expanded past this call's spend ceiling and was sampled. A date absent from departure_dates_searched was never searched, which is not the same as having no flights."
        },
        "stopped_early": {
          "type": "string",
          "description": "Present when something other than the cap ended the fan-out. 'deadline': the call reached its time limit and the remaining combinations were never sent or billed, so the results are real but cover only part of the range."
        },
        "hub_requests_billed": {
          "type": "integer",
          "minimum": 0,
          "description": "HTTP requests billed by RapidAPI for this call, retries included; see api_usage.hub_requests_billed."
        },
        "destinations_searched": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "searched_combinations": {
          "type": "integer",
          "minimum": 0
        },
        "requested_combinations": {
          "type": "integer",
          "minimum": 0
        },
        "departure_dates_searched": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "max_searches_per_request": {
          "type": "integer",
          "minimum": 1
        }
      },
      "description": "What was actually searched. Present whether or not the request was truncated, so the answer's basis is on the record either way.",
      "additionalProperties": true
    },
    "results_returned": {
      "type": "integer",
      "minimum": 0,
      "description": "How many of them are in `results` -- the best ones by the sort_by asked for, cheapest first by default, and never all of one destination at the expense of another. Lower than results_total only when `limit` was raised by the server to cover the fan-out rather than asked for; search_coverage.note says so when it happens, and `verbose: true` returns them all."
    }
  },
  "description": "A completed flight search. An empty `results` array means 'no flights' only when search_status is 'empty'.",
  "additionalProperties": true
}
search_roundtrip_flights annotations
{
  "title": "FlightPowers: search round-trip flights",
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}

Prompts

4 advertised

cheapest_dates — Find the cheapest dates to fly

Advertised by the server during the last successful anonymous check.

Scans a whole month (or any date range) for the lowest fare on a route and reports whether the winner is actually a good price.

from_airport
Origin IATA code, e.g. "TLV". Provide as a JSON string matching the following schema: {"description":"Origin IATA code, e.g. \"TLV\".","type":"string"} (required)
to_airport
Destination IATA code, e.g. "BUD". Provide as a JSON string matching the following schema: {"description":"Destination IATA code, e.g. \"BUD\".","type":"string"} (required)
month
The month or range to scan, e.g. "October 2026". Provide as a JSON string matching the following schema: {"description":"The month or range to scan, e.g. \"October 2026\".","type":"string"} (required)
compare_destinations — Compare destinations on price

Advertised by the server during the last successful anonymous check.

Prices several destinations from one origin over the same dates and ranks them, to answer 'where can I go cheaply'.

from_airport
Origin IATA code, e.g. "TLV". Provide as a JSON string matching the following schema: {"description":"Origin IATA code, e.g. \"TLV\".","type":"string"} (required)
destinations
Comma-separated IATA codes, e.g. "BUD,VIE,ATH". Provide as a JSON string matching the following schema: {"description":"Comma-separated IATA codes, e.g. \"BUD,VIE,ATH\".","type":"string"} (required)
when
The dates or range to search, e.g. "the first half of October". Provide as a JSON string matching the following schema: {"description":"The dates or range to search, e.g. \"the first half of October\".","type":"string"} (required)
plan_trip — Plan a round trip on a budget

Advertised by the server during the last successful anonymous check.

Finds round-trip options for a destination across flexible trip lengths, priced as paired legs, within a budget.

from_airport
Origin IATA code, e.g. "TLV". Provide as a JSON string matching the following schema: {"description":"Origin IATA code, e.g. \"TLV\".","type":"string"} (required)
to_airport
Destination IATA code, e.g. "FCO". Provide as a JSON string matching the following schema: {"description":"Destination IATA code, e.g. \"FCO\".","type":"string"} (required)
when
Departure window, e.g. "sometime in May". Provide as a JSON string matching the following schema: {"description":"Departure window, e.g. \"sometime in May\".","type":"string"} (required)
nights
Trip lengths to compare, e.g. "5, 6 or 7". Provide as a JSON string matching the following schema: {"description":"Trip lengths to compare, e.g. \"5, 6 or 7\".","type":"string"}
budget
Optional total budget, e.g. "$400". Provide as a JSON string matching the following schema: {"description":"Optional total budget, e.g. \"$400\".","type":"string"}
is_this_fare_good — Is this fare a good deal?

Advertised by the server during the last successful anonymous check.

Checks a specific route and date against Google's historical price band and answers book-now or wait.

from_airport
Origin IATA code, e.g. "TLV". Provide as a JSON string matching the following schema: {"description":"Origin IATA code, e.g. \"TLV\".","type":"string"} (required)
to_airport
Destination IATA code, e.g. "BUD". Provide as a JSON string matching the following schema: {"description":"Destination IATA code, e.g. \"BUD\".","type":"string"} (required)
departure_date
The date to check, "YYYY-MM-DD". Provide as a JSON string matching the following schema: {"description":"The date to check, \"YYYY-MM-DD\".","type":"string"} (required)
quoted_price
Optional price you were quoted elsewhere, e.g. "$260". Provide as a JSON string matching the following schema: {"description":"Optional price you were quoted elsewhere, e.g. \"$260\".","type":"string"}

Resources

1 advertised

flights_result_card

Advertised by the server during the last successful anonymous check.

flights_result_card URI
ui://flightpowers/flights-card.html

MIME type: text/html;profile=mcp-app

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (3 of 3 answered).

  1. 2026-11-06: 1 of 1 checks answered
  2. 2026-11-07: 2 of 2 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
1049 ms
95th percentile latency
1049 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 1049 ms · metadata changed · 2 tool(s), 1 resource(s), 0 resource template(s), 4 prompt(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http flightpowers-google-flights-mcp https://flights.flightpowers.com/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add flightpowers-google-flights-mcp --url https://flights.flightpowers.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable flightpowers-google-flights-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "flightpowers-google-flights-mcp": {
      "url": "https://flights.flightpowers.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "flightpowers-google-flights-mcp": {
      "type": "streamableHttp",
      "url": "https://flights.flightpowers.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start flightpowers-google-flights-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "flightpowers-google-flights-mcp": {
      "type": "http",
      "url": "https://flights.flightpowers.com/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http flightpowers-google-flights-mcp https://flights.flightpowers.com/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://flights.flightpowers.com/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "flightpowers-google-flights-mcp": {
      "serverUrl": "https://flights.flightpowers.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like FlightPowers Google Flights MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run FlightPowers Google Flights MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing