MCP 서버

whentofly

io.github.dimabalony/whentofly
여행 및 호스피탈리티 사용 불가 MCP 2025-11-25

이 MCP로 할 수 있는 일

Finds flexible-date economy and business flights and resolves city or airport search locations.

search_flights
Find the cheapest round-trip across a FLEXIBLE multi-month date window with a min/max trip length — e.g. "10–15 days, anytime Sep–Nov". Search a broad date window rather than requiring the traveler to choose exact dates first. First call the search_locations MCP tool for city or airport names, then pass each returned airport:AAA or city:AAA value unchanged as origin/destination (explicit legacy IATA codes remain supported). Dates are OPTIONAL: add an earliest/latest window when the traveler has one, or omit them (or give just one side) and a sensible default window is searched — metadata.window_defaulted says so and query echoes the window used, so a dateless call always returns flights instead of an error. Add min/max trip duration; get back a ranked list of the cheapest fares (with booking links) plus a price verdict — an honest read of whether the cheapest fare is low, typical, or high versus the route's usual price, or unknown when we lack a usable typical-price band (a price-level read, not a buy-now-or-wait timing prediction). Non-economy requests may return action-bound Google Flights seller quotes or separate route-price evidence in metadata.route_price_check. For a specific route, set checked_bags=1 when the traveler needs one checked bag, then inspect each result's price_basis; anywhere discovery does not support baggage pricing. Checked-bag searches still run seller enrichment but set the fare-only verdict and metadata.route_price_check to null; verify=full does not override that boundary. Use it for any flight question where the dates are flexible, unknown, or the user wants the cheapest time to fly. If a window comes back thin or cannot fit the return, the search widens it one step itself and reports that in metadata.hints — no second call needed. A city:/airport: prefix that contradicts its code (city:CDG names an airport, airport:PAR names a city) is likewise searched as the identity the catalog does know, with a selector_corrected entry in metadata.hints naming the requested and used tokens. Dates already in the past get the same treatment: a window that only STARTS in the past is searched from today with a window_clamped entry in metadata.hints, and a window that has already ENDED is not searched at all — the results are empty and a window_in_past entry names a suggested window to ask for instead, so do not retry the same dates. If metadata.refresh_hint is present, this response shipped without something a repeat call can add: issue the same call again immediately (do not sleep or poll) and read refresh_hint.action for what will be included. If you can wait longer for that best-effort cross-check, set verify=full. It uses a longer ~35s budget, but never treats a different airline, itinerary, gate, or booking URL as verification of the displayed offer. Pass sellers=false when the traveler wants the price picture but is not booking through this answer: it skips the live seller-quote wave, so the ranked calendar fares, booking links and metadata.route_price_check still come back but metadata.seller_enrichment_status is `skipped` and no seller quote, seller-level baggage fee or direct seller action is resolved. Provider failure, unavailability, or a spend cap can still return only cached indicators; always inspect metadata.seller_enrichment_status (`applied` means complete date-pair coverage put Serp-derived seller data in results; `complete` means the selected plan and action resolution completed without such data entering results; `partial` means date-pair or direct-action coverage has gaps though valid seller data may still rank; `skipped` is reserved for response surfaces where enrichment does not apply) and metadata.seller_enrichment_coverage. That object reports the theoretical query-valid date pairs and how many were targeted/searched; it is not exhaustive provider inventory. Default requests target at most three pairs, while explicit verify=full targets at most seven with bounded longer budgets. Inspect metadata.freshness, and metadata.route_price_check.
읽기 전용 외부 접근 가능 멱등성
입력 스키마
{'type': 'object', 'title': 'search_flightsArguments', 'required': ['from'], 'properties': {'ch': {'type': 'string', 'title': 'ch', 'default': 'direct', 'examples': ['web', 'mcp', 'direct'], 'maxLength': 64, 'description': "Acquisition channel tag (e.g. web, mcp, a campaign name) for first-party analytics. Durable booking links retain the validated Travelpayouts marker for commission but do not trust opaque shortlinks solely to carry provider-dashboard sub_id attribution. Defaults to 'direct'; reduced to a bounded registered channel."}, 'to': {'type': 'string', 'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'to', 'examples': ['ICN', 'airport:PVG', 'city:BJS', 'anywhere'], 'description': 'Destination location: a legacy code, airport:AAA, or city:AAA. Pass `anywhere` (or omit) to get the cheapest destinations from the origin instead of a specific route.'}, 'from': {'type': 'string', 'title': 'from', 'examples': ['SGN', 'airport:SHA', 'city:SHA'], 'description': 'Origin location. Use a legacy 3-letter code (SHA), an exact airport (airport:SHA), or an all-airports city (city:SHA). Required for every search, including to=anywhere.'}, 'cabin': {'type': 'string', 'title': 'cabin', 'default': 'economy', 'examples': ['economy', 'business'], 'description': 'Cabin class: economy (default), premium_economy, business, or first. The Travelpayouts calendar covers economy; Google Flights may additionally return action-bound seller quotes for the requested cabin. Actionless evidence remains in metadata.route_price_check.'}, 'top_n': {'type': 'integer', 'title': 'top_n', 'default': 10, 'maximum': 50, 'minimum': 1, 'examples': [10], 'description': 'Maximum number of results to return, sorted cheapest-first. Specific routes allow up to 50; anywhere mode returns at most 12.'}, 'latest': {'type': 'string', 'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'title': 'latest', 'examples': ['2026-12-28'], 'description': 'Latest acceptable return date for round-trip, or latest acceptable departure for one-way (ISO YYYY-MM-DD). Window from earliest must be ≤365 days. Optional: omit it and it is derived from `earliest` (or from the default window when both are omitted). A window ending before today is not searched; the response is empty with a `window_in_past` hint. Ignored in anywhere mode.'}, 'verify': {'type': 'string', 'title': 'verify', 'default': 'false', 'examples': ['false', 'true', 'full'], 'description': "How hard to cross-check the top result's route, dates, and cabin against Google Flights (SerpApi). `false` (default): the check still runs automatically on a fresh search when the top isn't already a live price, within a client-aware time budget. `true`: force the check even on a cache hit. `full`: THOROUGH mode — force the same best-effort check with a longer ~35s budget and widen the request-local seller/date sample from at most three pairs to at most seven (set it when you can wait, e.g. an autonomous agent). The six-hour base and its cache key do not change. This does not verify the displayed airline, itinerary, gate, or booking URL; inspect `metadata.route_price_check` separately. Checked-bag searches keep this fare-only route check and verdict null even when verify=true or verify=full; seller-level baggage enrichment still runs. Displayed Travelpayouts fares remain explicitly labeled cached indicators. No-op unless a SerpApi key is configured."}, 'one_way': {'type': 'boolean', 'title': 'one_way', 'default': False, 'description': 'If true, search one-way flights; return_date and duration_days will be null.'}, 'sellers': {'type': 'boolean', 'title': 'sellers', 'default': True, 'examples': [True, False], 'description': 'Whether to run the live seller-quote wave (Google Flights `booking_options`) for this request. Default `true`: unchanged behavior — the bounded frontier resolves seller prices, baggage basis, and the executable booking action. Set `sellers=false` to ask for the ranked fare calendar and the route-level price check ONLY: the response then carries `metadata.seller_enrichment_status="skipped"`, results keep their Travelpayouts-grounded prices and durable booking links, and no seller quote, seller-level baggage fee, or direct seller action is resolved. It exists for callers that want the price picture cheaply and do not intend to book — our own curve-seeding crons use it — because the seller wave is where a search\'s provider spend actually goes (about seven of its ~eight calls). Non-economy cabins have no calendar source, so `sellers=false` there leaves `metadata.route_price_check` as the only priced evidence and `results` may be empty.'}, 'currency': {'type': 'string', 'title': 'currency', 'default': 'USD', 'examples': ['USD', 'EUR', 'SGD'], 'description': 'Result currency, 3-letter ISO code UPPERCASE.'}, 'earliest': {'type': 'string', 'anyOf': [{'type': 'string', 'format': 'date'}, {'type': 'null'}], 'title': 'earliest', 'examples': ['2026-09-29'], 'description': 'Earliest acceptable departure date (ISO YYYY-MM-DD). Optional: omit it and a default window is searched, with the applied window echoed in `query` and flagged by `metadata.window_defaulted`. A date already in the past is clamped to today and reported as `window_clamped` in `metadata.hints` — unless `latest` has passed too, in which case the whole window is declined rather than clamped (see `latest`). Ignored in anywhere mode.'}, 'max_days': {'type': 'integer', 'title': 'max_days', 'default': 30, 'maximum': 365, 'minimum': 1, 'examples': [15], 'description': 'Maximum round-trip duration in days (return - departure); ignored for one-way and anywhere mode.'}, 'min_days': {'type': 'integer', 'title': 'min_days', 'default': 3, 'maximum': 365, 'minimum': 1, 'examples': [10], 'description': 'Minimum round-trip duration in days (return - departure); ignored for one-way and anywhere mode.'}, 'checked_bags': {'type': 'integer', 'title': 'checked_bags', 'default': 0, 'maximum': 1, 'minimum': 0, 'examples': [0, 1], 'description': "Checked bags requested for the current one-adult, specific-route search contract. Anywhere discovery rejects checked_bags=1. Set to 1 to add a seller's unambiguous first-checked-bag fee to the ranked customer price. Unknown fees remain labeled in results[].price_basis instead of being guessed. Seller enrichment still runs, but the fare-only verdict and route-price check remain null, including when verify=true or verify=full."}, 'max_transfers': {'type': 'integer', 'anyOf': [{'type': 'integer', 'maximum': 5, 'minimum': 0}, {'type': 'null'}], 'title': 'max_transfers', 'examples': [0, 1], 'description': 'Maximum number of transfers/layovers per leg. 0 = nonstop only, 1 = up to 1 stop, etc. Omit for no filter.'}}}
search_locations
Resolve a city or airport name or code before searching flights. Returns typed values such as city:SHA to search every catalog airport in Shanghai or airport:SHA for Hongqiao only. Pass the selected value unchanged to search_flights. Ask the traveler when multiple results are plausible.
읽기 전용 멱등성
입력 스키마
{'type': 'object', 'title': 'search_locationsArguments', 'required': ['q'], 'properties': {'q': {'type': 'string', 'title': 'q', 'examples': ['Shanghai', 'SHA', 'Zhangjiajie'], 'maxLength': 80, 'minLength': 1, 'description': 'Airport/city name or 3-letter code prefix.'}, 'limit': {'type': 'integer', 'title': 'limit', 'default': 12, 'maximum': 50, 'minimum': 1}}}
추가됨
search_flights
2026년 9월 17일 12:41 PM
추가됨
search_locations
2026년 9월 17일 12:41 PM