whentofly

whentofly: flexible-date economy/business flight search + price-level context for AI agents

我該用這個嗎

品質與安全性

A
說明品質
100%
結構描述完整度
95%
命名品質
100%
汙染風險
100%
權限相符程度
100%
協定合規性
100%

根據工具定義與協定合規性的自動化分析。

上下文成本

~2,548Token(工具定義)
~10.0 KB典型回應大小
中等的注意力影響(128k 上下文的 1.99%)

這是每次將伺服器的工具載入模型上下文時所消耗的約略 token 數量。數量越高,可用於其他工作的注意力就越少。

安裝

一鍵安裝

將以下內容加入你的 `claude_desktop_config.json` 檔案:

{
  "mcpServers": {
    "whentofly": {
      "url": "https://whentofly.io/mcp?ch=mcp-registry"
    }
  }
}

遠端端點

https://whentofly.io/mcp?ch=mcp-registrystreamable-http

它能做什麼

工具清單

工具(2)

🟢 唯讀🟡 寫入🔴 刪除⚪ 未知
🟢search_locations(q, limit)

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",
  "properties": {
    "q": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80,
      "description": "Airport/city name or 3-letter code prefix.",
      "examples": [
        "Shanghai",
        "SHA",
        "Zhangjiajie"
      ],
      "title": "q"
    },
    "limit": {
      "type": "integer",
      "maximum": 50,
      "minimum": 1,
      "default": 12,
      "title": "limit"
    }
  },
  "required": [
    "q"
  ],
  "title": "search_locationsArguments"
}
🟢search_flights(from, to, earliest, latest, min_days, ...)

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",
  "properties": {
    "from": {
      "type": "string",
      "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.",
      "examples": [
        "SGN",
        "airport:SHA",
        "city:SHA"
      ],
      "title": "from"
    },
    "to": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "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.",
      "examples": [
        "ICN",
        "airport:PVG",
        "city:BJS",
        "anywhere"
      ],
      "title": "to",
      "type": "string"
    },
    "earliest": {
      "anyOf": [
        {
          "type": "string",
          "format": "date"
        },
        {
          "type": "null"
        }
      ],
      "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.",
      "examples": [
        "2026-09-29"
      ],
      "title": "earliest",
      "type": "string"
    },
    "latest": {
      "anyOf": [
        {
          "type": "string",
          "format": "date"
        },
        {
          "type": "null"
        }
      ],
      "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.",
      "examples": [
        "2026-12-28"
      ],
      "title": "latest",
      "type": "string"
    },
    "min_days": {
      "type": "integer",
      "maximum": 365,
      "minimum": 1,
      "description": "Minimum round-trip duration in days (return - departure); ignored for one-way and anywhere mode.",
      "examples": [
        10
      ],
      "default": 3,
      "title": "min_days"
    },
    "max_days": {
      "type": "integer",
      "maximum": 365,
      "minimum": 1,
      "description": "Maximum round-trip duration in days (return - departure); ignored for one-way and anywhere mode.",
      "examples": [
        15
      ],
      "default": 30,
      "title": "max_days"
    },
    "one_way": {
      "type": "boolean",
      "description": "If true, search one-way flights; return_date and duration_days will be null.",
      "default": false,
      "title": "one_way"
    },
    "top_n": {
      "type": "integer",
      "maximum": 50,
      "minimum": 1,
      "description": "Maximum number of results to return, sorted cheapest-first. Specific routes allow up to 50; anywhere mode returns at most 12.",
      "examples": [
        10
      ],
      "default": 10,
      "title": "top_n"
    },
    "currency": {
      "type": "string",
      "description": "Result currency, 3-letter ISO code UPPERCASE.",
      "examples": [
        "USD",
        "EUR",
        "SGD"
      ],
      "default": "USD",
      "title": "currency"
    },
    "max_transfers": {
      "anyOf": [
        {
          "type": "integer",
          "maximum": 5,
          "minimum": 0
        },
        {
          "type": "null"
        }
      ],
      "description": "Maximum number of transfers/layovers per leg. 0 = nonstop only, 1 = up to 1 stop, etc. Omit for no filter.",
      "examples": [
        0,
        1
      ],
      "title": "max_transfers",
      "type": "integer"
    },
    "cabin": {
      "type": "string",
      "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.",
      "examples": [
        "economy",
        "business"
      ],
      "default": "economy",
      "title": "cabin"
    },
    "checked_bags": {
      "type": "integer",
      "maximum": 1,
      "minimum": 0,
      "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.",
      "examples": [
        0,
        1
      ],
      "default": 0,
      "title": "checked_bags"
    },
    "verify": {
      "type": "string",
      "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.",
      "examples": [
        "false",
        "true",
        "full"
      ],
      "default": "false",
      "title": "verify"
    },
    "sellers": {
      "type": "boolean",
      "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.",
      "examples": [
        true,
        false
      ],
      "default": true,
      "title": "sellers"
    },
    "ch": {
      "type": "string",
      "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.",
      "examples": [
        "web",
        "mcp",
        "direct"
      ],
      "default": "direct",
      "title": "ch"
    }
  },
  "required": [
    "from"
  ],
  "title": "search_flightsArguments"
}

社群

為此伺服器評分

證據

近期觀測

已驗證未記錄版本2 個工具
已驗證未記錄版本2 個工具
已驗證未記錄版本2 個工具