aviasales-mcp
aviasales-mcp
MCP server for flight price search via Aviasales / Travelpayouts Data API. Thirteen read-only tools that let Claude Code, Claude Desktop, Cursor or any other MCP client answer flight-price questions: fares by route and month, the cheapest day to fly, flexible dates, budget and inspiration search, plus airport/city/airline lookup.
Unlike Google-Flights-scraping MCP servers, place names do not have to be
guessed into IATA codes by the model: lookup_cities and find_nearest_airports
resolve them.
Example prompts
Ask in plain language. The server picks the tool.
How much is a flight from Moscow to Istanbul in March?
What is the cheapest day to fly to Bangkok in September?
I am flying Berlin to Lisbon on 12 May and back on the 19th. Would shifting a day either way be cheaper?
Where can I fly from St Petersburg for under 30 000 rubles?
Which airport should I fly into for Pattaya, and what does it cost from Dubai?
Related MCP server: @theyahia/travelpayouts-mcp
Common prompts
The same kind of question, with the tools a typical agent reaches for.
Prompt | Tools it reaches for |
"How much is a flight from Moscow to Istanbul in March?" |
|
"What's the cheapest day to fly to Bangkok in September?" |
|
"I'm flying Berlin→Lisbon on 12 May, back on the 19th — would shifting a day either way be cheaper?" |
|
"Where can I fly from St Petersburg for under 30 000 ₽?" |
|
"Which airport should I fly into for Pattaya, and what does it cost from Dubai?" |
|
"Evening departures only, two adults and a child, business class." |
|
Install
Paste this into a terminal. It is the same docker command every client block
below runs; the process speaks MCP on stdin and waits there.
AVIASALES_API_TOKEN=your-token-here AVIASALES_MARKET=ru \
docker run -i --rm \
-e AVIASALES_API_TOKEN \
-e AVIASALES_MARKET \
ghcr.io/stufently/aviasales-mcp:latestYou need Docker, and a free Travelpayouts API token from
https://www.travelpayouts.com/programs/100/tools/api. A wrong token still
lets the process start (so does no token at all in the Docker image); it
surfaces as an error on the first search.
AVIASALES_MARKET is optional — see Configuration. Drop
that variable and its -e pair if you do not need it.
:latest follows releases; pin a version tag (:0.5.3) if you would rather
upgrade by hand.
Without Docker, the same server is on PyPI as
aviasales-mcp (Python 3.12+).
uvx fetches and runs it in one step:
AVIASALES_API_TOKEN=your-token-here AVIASALES_MARKET=ru uvx aviasales-mcppip install aviasales-mcp puts the same aviasales-mcp command on your PATH.
In a client config, use "command": "uvx", "args": ["aviasales-mcp"] with the
token in env instead of the docker command in the blocks below.
MCP client configs
Every block runs the same docker command as the terminal snippet above.
-e AVIASALES_API_TOKEN with no value hands the container the variable the
client sets in env, so the token is written in exactly one place.
Keep the token out of anything you commit. A project-level
.mcp.json,.cursor/mcp.jsonor.zed/settings.jsonis a normal thing to check into git, and a token pasted there goes with it. Prefer the user-level config file, or.gitignorethe project one.
Claude Code
Project file: .mcp.json in the project root.
{
"mcpServers": {
"aviasales": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "AVIASALES_API_TOKEN",
"-e", "AVIASALES_MARKET",
"ghcr.io/stufently/aviasales-mcp:latest"
],
"env": {
"AVIASALES_API_TOKEN": "your-token-here",
"AVIASALES_MARKET": "ru"
}
}
}
}Or from the terminal:
claude mcp add --scope user aviasales \
-e AVIASALES_API_TOKEN=your-token-here -e AVIASALES_MARKET=ru -- \
docker run -i --rm -e AVIASALES_API_TOKEN -e AVIASALES_MARKET \
ghcr.io/stufently/aviasales-mcp:latest--scope user makes it available in every project and keeps the token in
~/.claude.json, out of the repository. Check with claude mcp list.
Claude Desktop
File: claude_desktop_config.json — macOS
~/Library/Application Support/Claude/claude_desktop_config.json, Windows
%APPDATA%\Claude\claude_desktop_config.json, Linux
~/.config/Claude/claude_desktop_config.json.
{
"mcpServers": {
"aviasales": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "AVIASALES_API_TOKEN",
"-e", "AVIASALES_MARKET",
"ghcr.io/stufently/aviasales-mcp:latest"
],
"env": {
"AVIASALES_API_TOKEN": "your-token-here",
"AVIASALES_MARKET": "ru"
}
}
}
}One click, without editing JSON: download the .mcpb from
https://github.com/stufently/aviasales-mcp/releases/latest and open it.
Claude Desktop installs the extension and asks for the Travelpayouts API token.
The same release includes checksums.txt, the SHA256 of every file attached
to it: the .mcpb, and from the first PyPI release on also the sdist and the
wheel, byte for byte the files uploaded to PyPI. Download it into the same
directory as the bundle and check it before opening the bundle:
sha256sum -c --ignore-missing checksums.txt # run next to the downloaded filesOn macOS, shasum -a 256 -c checks the same file.
Claude Desktop starts with a trimmed PATH and may not find docker by name: if
the server fails to start, replace "docker" with its absolute path
(which docker).
Cursor
File: ~/.cursor/mcp.json (every project) or .cursor/mcp.json (this project).
{
"mcpServers": {
"aviasales": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "AVIASALES_API_TOKEN",
"-e", "AVIASALES_MARKET",
"ghcr.io/stufently/aviasales-mcp:latest"
],
"env": {
"AVIASALES_API_TOKEN": "your-token-here",
"AVIASALES_MARKET": "ru"
}
}
}
}Windsurf
File: mcp_config.json — macOS and Linux ~/.config/devin/mcp_config.json
(or $XDG_CONFIG_HOME/devin/mcp_config.json), Windows
%APPDATA%\devin\mcp_config.json. Older builds read
~/.codeium/windsurf/mcp_config.json.
{
"mcpServers": {
"aviasales": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "AVIASALES_API_TOKEN",
"-e", "AVIASALES_MARKET",
"ghcr.io/stufently/aviasales-mcp:latest"
],
"env": {
"AVIASALES_API_TOKEN": "your-token-here",
"AVIASALES_MARKET": "ru"
}
}
}
}Zed
File: settings.json at ~/.config/zed/settings.json (or zed: open settings).
{
"context_servers": {
"aviasales": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "AVIASALES_API_TOKEN",
"-e", "AVIASALES_MARKET",
"ghcr.io/stufently/aviasales-mcp:latest"
],
"env": {
"AVIASALES_API_TOKEN": "your-token-here",
"AVIASALES_MARKET": "ru"
}
}
}
}Codex
codex mcp add aviasales --env AVIASALES_API_TOKEN=your-token-here -- \
docker run -i --rm -e AVIASALES_API_TOKEN ghcr.io/stufently/aviasales-mcp:latestOr by hand in ~/.codex/config.toml:
[mcp_servers.aviasales]
command = "docker"
args = ["run", "-i", "--rm", "-e", "AVIASALES_API_TOKEN", "-e", "AVIASALES_MARKET",
"ghcr.io/stufently/aviasales-mcp:latest"]
[mcp_servers.aviasales.env]
AVIASALES_API_TOKEN = "your-token-here"
AVIASALES_MARKET = "ru"Any other stdio client
Command docker, arguments
run -i --rm -e AVIASALES_API_TOKEN ghcr.io/stufently/aviasales-mcp:latest, and
AVIASALES_API_TOKEN in the environment the client gives the process. The
server is also listed in the official MCP registry as
io.github.stufently/aviasales-mcp, which clients with a registry browser can
install from directly.
Verified clients and OS
Only what was actually run is marked verified. Everything else is a config written from the client's documentation and has not been tried.
Client or path | OS | Status | How |
Test suite, Python 3.12 / 3.13 / 3.14 | Linux (GitHub | Verified on every PR and push to |
|
Docker runtime image build | Linux (GitHub | Verified on every PR and push to |
|
Plain MCP over stdio ( | Linux x86_64 | Verified 2026-10-12 | 13 tools listed, every one |
Claude Code 2.1.296, Docker command from this README | Linux x86_64 | Verified 2026-10-12: connects and lists all 13 tools | A placeholder token; no tool call reached the API in this check |
| Linux, | Verified 2026-10-10: starts and answers | Without Claude Desktop |
Travelpayouts Data API with a real token | Linux | Verified 2026-07-29 (live probe of the Data API endpoints) | See CHANGELOG |
Claude Desktop ( | macOS, Windows, Linux | Not verified | No Claude Desktop on the test host |
Cursor, Windsurf, Zed, Codex | any | Not verified | Configs follow each client's docs as of 2026-10-10 |
Any client on macOS or Windows | macOS, Windows | Not verified | |
| Linux, | Verified 2026-10-14: 13 tools listed | A placeholder token; no tool call reached the API |
Tools
All thirteen tools only read: they search cached fares and reference data. None books, buys, writes or changes anything, and none costs money to call beyond the Travelpayouts rate limit, so there is no separate read-only mode to turn on.
Flight prices
Tool | Description |
| Prices between two cities on a date or across a month (v3/prices_for_dates) |
| Prices grouped by day or month — the cheapest day to fly |
| Prices for the days around your dates — "would shifting a day be cheaper?" |
| Most recently found fares, optionally filtered by route |
| Where travellers reach a destination from |
| Cheapest destinations reachable from a city — inspiration search |
| Prices for nearby airports/cities |
| Flights inside a budget; omit the destination to search anywhere (no date filter — the endpoint ignores one) |
search_flights, get_prices_calendar, get_flexible_date_prices and
get_latest_prices accept adults (1–9), children (0–8), infants (0–8) and
trip_class (economy/comfort/business/first).
The Data API serves a cache of recent searches and takes no passenger
parameters, so the party is encoded into each ticket's booking_link instead —
the link opens Aviasales with the full party and class pre-filled and shows the
real total. The prices themselves are always per adult in economy, which is
what the price_note field on every price response spells out for the model.
search_flights also takes depart_after / depart_before (HH:MM, 24-hour)
to keep only departures in a time window; set depart_after later than
depart_before for a window that wraps midnight (red-eyes).
Tickets carry duration_total (door-to-door minutes), duration_to /
duration_back (flight time per direction) and layover_minutes (combined
ground time between connections). Every price response also carries a
price_summary (min/median/max) so the model can tell a good fare from a bad one
without a second search.
Reference data
Tool | Description |
| Airlines by name or IATA code |
| Airports by name, IATA code, or city code |
| Cities by name or IATA code — turn a city name into a code |
| Countries by name or code |
| Airports closest to a place or to lat/lon, by distance |
The lookup_* tools take search, limit (default 50, max 500) and locale,
and return {status, total, returned, truncated, data}. Always pass search:
the underlying datasets are ~10k airports and ~9.6k cities, which is far more
than any model can hold in context. Matches are ranked (exact code, then exact
city code, then name), and airports with no scheduled service sort last. Each
dataset is downloaded once per process and cached for 24 hours.
find_nearest_airports answers the question lookup_airports cannot: the
closest airport is rarely named after the town. It resolves near="Pattaya"
against the cached city and airport datasets and ranks by great-circle distance —
no third-party geocoder involved.
Errors and empty results
Every response carries status ("ok" or "error"), so an empty data list is
never confused with a failure. Bad input is refused before the API call, with the
expected format spelled out ("departure_at must be \"YYYY-MM-DD\" or \"YYYY-MM\"…"), and both error and empty responses carry a hint naming what to
try next. On a rejected argument the hint says what to substitute and which tool
resolves it — enough for the model to fix the call itself on the second attempt.
Setup
Building the image yourself from a checkout, instead of pulling it:
Get an API token at https://www.travelpayouts.com/programs/100/tools/api
Copy
.env.exampleto.envand fill in your tokenBuild and run with Docker:
docker build -t aviasales-mcp .
docker run --env-file .env aviasales-mcpConfiguration
Variable | Required | Description |
| Yes | Travelpayouts API token |
| No | Partner ID for booking links |
| No | Default price currency (default: |
| No | 2-letter market whose price cache to read (unset → |
| No | Language of reference data names (default: |
| No | Logging level (default: INFO) |
| No | Serve streamable-HTTP on this port instead of stdio ( |
| No | Bind address for HTTP mode (default: |
| No | Shared secret required on every HTTP request |
| No | Also accept the token as |
| No | Permit a non-loopback bind with no token (default: false) |
AVIASALES_MARKET is worth setting: the price cache is per market, and the same
route in the same currency comes back at a different price for ru and us.
HTTP transport
By default the server speaks stdio, which is what local MCP clients expect.
Setting MCP_PORT switches it to streamable-HTTP so it can be reached remotely:
docker run --env-file .env \
-e MCP_PORT=8080 -e MCP_HOST=0.0.0.0 -e MCP_AUTH_TOKEN=<your-secret> \
-p 8080:8080 aviasales-mcpThe endpoint is then http://<host>:8080/mcp, and every request must present
the token as Authorization: Bearer <token>; anything else gets a 401.
Some MCP clients cannot set headers. MCP_AUTH_ALLOW_QUERY_TOKEN=true also
accepts ?token=<token>, but note that uvicorn — and any proxy in front of it —
writes the full URL to its access log, so the secret ends up in logs. Prefer the
header.
There is no TLS here: terminate it at a reverse proxy if the port is reachable from anywhere untrusted.
Without MCP_AUTH_TOKEN the port is unauthenticated and anyone who reaches it
can spend your Travelpayouts quota. Loopback binds are allowed (with a warning);
binding anything else refuses to start unless you also set
MCP_ALLOW_INSECURE_HTTP=true.
Limitations
Prices are a cache of recent searches, not live availability. A fare can be gone by the time the link opens;
expires_atsays when the quote lapses.Prices are always per adult in economy. Passenger count and cabin change the booking link, never the quoted number.
No booking. This server searches and links out; it never holds or buys.
Cache coverage is uneven. An empty result means nobody searched that route recently, not that the route does not exist.
get_latest_prices, the matrices and nearby airports come from the older v2 response shape: they name the sellingagencyrather than the airline and carry no flight number.Rate limits are per endpoint (600/min for most, 60/min for the week and nearby matrices). The server retries 429s and warns when the published quota runs low.
Development
docker build --target dev -t aviasales-mcp-dev .
docker run --rm aviasales-mcp-dev pytest -q
docker run --rm -v "$(pwd)":/app -w /app aviasales-mcp-dev ruff check src/ tests/CI runs the suite on Python 3.12, 3.13 and 3.14 plus a Docker image build — see
.github/workflows/ci.yml.
Releasing
Pushing a v* tag runs .github/workflows/release.yml: the CI suite, then an
sdist and a wheel checked against the tag version and twine check, an upload
to PyPI through Trusted Publishing (no token stored anywhere), and finally the
GitHub Release with the sdist, wheel, .mcpb and checksums.txt.
registry.yml publishes the image and the MCP registry entry from the same tag.
version in pyproject.toml and server.json must match the tag.
License
GPL-3.0-or-later — see LICENSE.
Available Tools
13 toolsfind_nearest_airportsARead-onlyIdempotent
Find the airports closest to a place name or to a latitude and longitude.
Use when the user asks which airport to fly into for a town, a resort, or
a point on the map. lookup_airports only matches a name, and the nearest
airport is rarely named after the town, so call this tool for that
question. Feed the returned city code, not the airport code, to
search_flights for fares.
Pass either near (resolved against the city and airport datasets) or an
explicit latitude/longitude pair.
| Name | Required | Description | Default |
|---|---|---|---|
| near | No | Place name or IATA code to search around (e.g. "Pattaya", "UTP"). | |
| limit | No | Max airports to return (1-50, default 5). | |
| locale | No | 2-letter locale for names. Defaults to the server's locale. | |
| latitude | No | Latitude in degrees, -90 to 90. Overrides `near`. | |
| longitude | No | Longitude in degrees, -180 to 180. Overrides `near`. | |
| flightable_only | No | Skip airports with no scheduled service (default True). | |
| max_distance_km | No | Ignore airports further away than this. Optional. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, open-world behavior, so the safety profile is covered. The description adds real behavioral context beyond that: `near` is resolved against both city and airport datasets, and the result carries a city code rather than an airport code. It stops short of describing distance ordering or pagination limits, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short paragraphs, each doing distinct work: what it does, when to use it versus the sibling plus the downstream handoff, and the input-mode selection. The scoping and routing guidance is front-loaded and no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and annotations covering the safety profile, the description only needs to carry purpose, usage routing, and input-mode selection — all of which it does. An agent has everything required to choose and call this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents each parameter, including the override relationship ('latitude ... Overrides `near`'). The description restates the either/or selection of `near` versus a lat/long pair but adds no format, unit, or constraint detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (find airports closest to a place or coordinates) and immediately contrasts with the sibling lookup_airports, which only matches names. An agent can distinguish the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('when the user asks which airport to fly into for a town, a resort, or a point on the map'), names the alternative tool and why it fails for this question, and routes the downstream step (feed the returned city code, not airport code, to search_flights). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_alternative_directionsARead-onlyIdempotent
Get prices for nearby airports and cities around a chosen route.
Use when the traveller can fly from or into a different airport and wants
those fares. To learn which airports are near a place, use
find_nearest_airports first; for the named city pair only, use
search_flights.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (1-20, default 10). | |
| market | No | 2-letter market whose price cache to read. Defaults to the server's configured market. | |
| origin | Yes | Origin IATA code. | |
| currency | No | Price currency (3 letters). Defaults to the server's currency. | |
| return_at | No | Return date (YYYY-MM-DD or YYYY-MM). Optional. | |
| destination | Yes | Destination IATA code. | |
| departure_at | No | Departure date (YYYY-MM-DD or YYYY-MM). Optional. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and non-destructive, so the safety profile is covered. The description adds scope ('nearby airports and cities') but no extra behavioral detail such as caching, pagination, or result freshness. Adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loading the purpose and then the routing guidance. No wasted text, though it is slightly denser than strictly necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and annotations cover safety. The description supplies the selection logic relative to siblings, making it complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all seven parameters (origin, destination, dates, currency, market, limit) are already documented. The description adds no meaning beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get prices for nearby airports and cities around a chosen route') with clear scope. It is immediately distinguishable from search_flights (named city pair) and find_nearest_airports (airport discovery).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use it ('when the traveller can fly from or into a different airport') and routes to alternatives: find_nearest_airports for discovery and search_flights for the exact city pair. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_city_directionsARead-onlyIdempotent
List the cheapest destinations reachable from a city, with a fare and dates.
Use when the user asks where they can fly from a city, or wants somewhere
cheap without naming a destination. For who flies into a city use
get_popular_directions; to price one chosen route afterwards use
search_flights or get_prices_calendar.
| Name | Required | Description | Default |
|---|---|---|---|
| origin | Yes | Origin city IATA code (e.g. "MOW"). Use `lookup_cities` to resolve a city name first. | |
| currency | No | Price currency (3 letters). Defaults to the server's currency. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is fully covered by structured data. The description adds useful context that results include fares and dates, but discloses nothing about pagination, result limits, or currency behavior beyond what's in the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core action and immediately followed by routing guidance. No filler or repetition of schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value details need not be spelled out; the description covers action, scope, and sibling routing for a two-parameter read-only tool. Nothing an agent needs to select or call it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (origin IATA, currency) are already documented in the schema, including the pointer to lookup_cities. The description's 'from a city' adds no meaning beyond the schema's 'Origin city IATA code'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the cheapest destinations reachable from a city') plus scope ('with a fare and dates'), and explicitly distinguishes itself from the similarly-named siblings get_popular_directions and get_alternative_directions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use condition ('user asks where they can fly from a city, or wants somewhere cheap without naming a destination') and routes to named alternatives (get_popular_directions for inbound, search_flights/get_prices_calendar for pricing a chosen route).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_flexible_date_pricesARead-onlyIdempotent
Compare prices for the days around a departure and an optional return.
Use when the user already has dates and asks whether shifting a day either
way would be cheaper. For one exact date use search_flights; for the
cheapest day across a whole month use get_prices_calendar. This covers
roughly a week around both the outbound and the return.
| Name | Required | Description | Default |
|---|---|---|---|
| adults | No | Number of adult passengers, 1-9 (default 1). | |
| market | No | 2-letter market whose price cache to read. Defaults to the server's configured market. | |
| origin | Yes | Origin IATA code. | |
| infants | No | Number of infants under 2, 0-8 (default 0). | |
| children | No | Number of children 2-11 years, 0-8 (default 0). | |
| currency | No | Price currency (3 letters). Defaults to the server's currency. | |
| trip_class | No | "economy", "comfort", "business" or "first" (default "economy"). | economy |
| depart_date | Yes | Intended departure date (YYYY-MM-DD). Required. | |
| destination | Yes | Destination IATA code. | |
| return_date | No | Intended return date (YYYY-MM-DD). Omit for one-way. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the bar is lower. The description adds genuinely useful scope context — roughly a week of dates around both outbound and return — which the annotations do not convey. It stops short of describing caching behavior or result volume, keeping it at a 4.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the action, then the usage trigger, then the alternatives. Every sentence earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the annotations carry the safety profile. For a read-only, fully-documented 10-parameter query tool, the description covers what an agent needs to select and call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all ten parameters including the adult/child/infant breakdown and date formats. The description only implicitly touches depart_date/return_date via 'days around', adding little beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Compare prices for the days around a departure and an optional return') and immediately contrasts itself with two named siblings. An agent can distinguish it from search_flights and get_prices_calendar without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('user already has dates and asks whether shifting a day either way would be cheaper') and routes the two adjacent cases to the correct alternatives with their selecting conditions. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_latest_pricesARead-onlyIdempotent
Get the most recently found flight prices from other travellers' searches.
Use when the user wants the latest fares that just appeared, on one route
or across the whole cache. For a specific trip on chosen dates use
search_flights instead. Prices are per adult (cached); passenger
parameters are encoded into each booking_link.
These rows come from the older v2 shape: they name the selling agency
rather than an airline, carry no flight number, and their booking_link is
reconstructed from the route and dates.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (1-100, default 20). | |
| adults | No | Number of adult passengers, 1-9 (default 1). | |
| market | No | 2-letter market whose price cache to read. Defaults to the server's configured market. | |
| origin | No | Origin IATA code. Optional. | |
| infants | No | Number of infants under 2, 0-8 (default 0). Cannot exceed the number of adults; the excess is trimmed. | |
| one_way | No | One-way tickets only. | |
| children | No | Number of children 2-11 years, 0-8 (default 0). Adults plus children cannot exceed 9; the excess is trimmed. | |
| currency | No | Price currency (3 letters). Defaults to the server's currency. | |
| trip_class | No | "economy", "comfort", "business" or "first" (default "economy"). | economy |
| destination | No | Destination IATA code. Optional. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the read-only, idempotent safety profile, so the bar is lower, but the description adds real behavioral context: rows are cached v2-shape data naming an agency rather than an airline, lack flight numbers, and have reconstructed booking_links. The only thing not addressed is pagination/ordering of results, which is minor given the output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight paragraphs: purpose and scope first, the routing alternative second, the data-shape caveat last. Every sentence adds information an agent needs; nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter read tool with full schema coverage, full annotations, and an output schema, the description fills the remaining gaps: routing to the correct sibling and warning about the legacy v2 row shape. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every parameter is already documented in the schema, and the output schema covers the response. The description adds only incidental parameter-relevant notes (per-adult pricing, passenger details encoded in booking_link), not syntax or format guidance beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb (get) and resource (latest flight prices from other travellers' searches), and explicitly contrasts itself with search_flights. An agent can disambiguate it from all twelve siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('when the user wants the latest fares that just appeared') plus a named alternative ('For a specific trip on chosen dates use search_flights instead'). Both the use and the when-not-to-use case are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_popular_directionsARead-onlyIdempotent
List the cities people most often fly to a destination from, with a fare.
Use when the user asks where travellers reach a city from and what that
costs. The request is keyed on the destination. For where someone can fly
from a city use get_city_directions; for prices on one known route use
search_flights.
| Name | Required | Description | Default |
|---|---|---|---|
| locale | No | 2-letter locale for city names. Defaults to the server's locale. | |
| currency | No | Price currency (3 letters). Defaults to the server's currency. | |
| destination | Yes | Destination IATA code (e.g. "BKK"). Required — the API rejects a request without it. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds the result shape (cities plus a fare) and the direction semantics (origins into the destination), which is real value beyond annotations, but it says nothing about rate limits, locale/currency defaults, or result volume.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs; the capability statement is front-loaded and the routing guidance follows with zero filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description plus annotations and full schema coverage give everything an agent needs to select and invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the required IATA code and locale/currency defaults, so the schema carries the parameter burden. The description only reiterates that the request is keyed on the destination, adding no format or syntax detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: lists origin cities for flights into a destination, with fares. It explicitly distinguishes itself from get_city_directions and search_flights, so the agent can route correctly without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States when to use it ('where travellers reach a city from and what that costs'), the keying ('the request is keyed on the destination'), and names two alternatives with the condition that selects each ('where someone can fly from a city' vs 'prices on one known route').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_prices_calendarARead-onlyIdempotent
Get grouped calendar prices for a route, one fare per day or per month.
Use when the user asks which day or month is cheapest to fly a known route.
For fares on one specific date use search_flights; for a few days either
side of dates already chosen use get_flexible_date_prices. Codes are
IATA; use lookup_cities to resolve a name first.
Prices are per adult (cached); passenger parameters are encoded into each booking_link.
| Name | Required | Description | Default |
|---|---|---|---|
| adults | No | Number of adult passengers, 1-9 (default 1). | |
| market | No | 2-letter market whose price cache to read (e.g. "us", "ru"). Defaults to the server's configured market. | |
| origin | Yes | Origin IATA code. | |
| infants | No | Number of infants under 2, 0-8 (default 0). Cannot exceed the number of adults; the excess is trimmed. | |
| children | No | Number of children 2-11 years, 0-8 (default 0). Adults plus children cannot exceed 9; the excess is trimmed. | |
| currency | No | Price currency (3 letters). Defaults to the server's currency. | |
| group_by | No | Group results by "departure_at" or "month" (default "departure_at"). | departure_at |
| return_at | No | Return month (YYYY-MM). Optional. | |
| trip_class | No | "economy", "comfort", "business" or "first" (default "economy"). | economy |
| destination | Yes | Destination IATA code. | |
| departure_at | No | Departure month (YYYY-MM). Optional. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds real behavioral context beyond that: prices are cached, quoted per adult, and passenger counts are encoded into the booking_link rather than affecting the returned fare. It stops short of describing coverage limits or freshness of the cache, so it is not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short blocks: what it returns, when to use it versus siblings, and pricing/param caveats. The routing rules are front-loaded before the caveats, and no sentence is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and rich annotations, the description does not need to explain return values, and it covers usage, code semantics, and pricing basis. The only mild gap is the absence of any note on cache staleness or result scope given the market parameter selects a cache.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description goes one step further by telling the agent that the location fields are IATA codes and that lookup_cities must be used to resolve plain names first, plus clarifying that passenger parameters are baked into booking_link rather than the quoted price — details the schema does not spell out.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ("Get grouped calendar prices for a route") and immediately clarifies the granularity of the result ("one fare per day or per month"), which maps directly to the group_by enum. It is clearly distinguishable from siblings like search_flights and get_flexible_date_prices without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the exact scenario for this tool ("which day or month is cheapest to fly a known route") and then names two alternatives with the conditions that select them: search_flights for one specific date, get_flexible_date_prices for a few days either side. It also routes to lookup_cities when codes must be resolved from a name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_airlinesARead-onlyIdempotent
Look up airlines by name or IATA code.
Use when the user asks which airline a code belongs to, or wants the IATA
code for an airline name. For an airport, city, or country code use
lookup_airports, lookup_cities, or lookup_countries; for fares use
search_flights.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results to return (1-500, default 50). | |
| locale | No | 2-letter locale for names (e.g. "en", "ru"). Defaults to the server's locale. | |
| search | No | Airline name substring or exact IATA code (e.g. "aeroflot", "SU"). Omit to list airlines from the start of the dataset. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is fully covered without description help. The description adds only routing context, disclosing nothing about result caps, dataset ordering, or locale-dependent output beyond what the schema states. Adequate but adds little behavioral value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight paragraphs; the capability statement is front-loaded and the sibling routing follows, with zero filler. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the annotations carry the safety semantics. With all three parameters documented in the schema and clear routing, nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: search (name substring or exact IATA), locale, and limit are all documented in the schema with examples and defaults. The description's mention of 'name or IATA code' restates the search parameter rather than adding syntax or edge-case guidance, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Look up airlines') plus the two lookup keys (name or IATA code), immediately telling the agent what entity this resolves. It is clearly distinguished from lookup_airports, lookup_cities, lookup_countries, and search_flights, all of which are named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the triggering condition ('user asks which airline a code belongs to, or wants the IATA code for an airline name') and routes the agent away from this tool for airports, cities, countries, and fares by naming the correct alternatives. Nothing about when-not-to-use is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_airportsARead-onlyIdempotent
Look up airports by name, IATA code, or city code.
Use when the user names an airport or a code and needs its city, country,
or coordinates. For the closest airport to a town that does not share the
airport's name, use find_nearest_airports instead of this tool.
The full dataset is ~10k airports, so always pass search — an unfiltered
call just returns the first limit entries in dataset order. Results are
ranked: exact code, then exact city code, then name matches, with airports
you cannot actually fly to last.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results to return (1-500, default 50). | |
| locale | No | 2-letter locale for names (e.g. "en", "ru"). Defaults to the server's locale. | |
| search | No | Airport name substring, exact IATA code, or city code (e.g. "heathrow", "LHR", "MOW"). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this read-only, idempotent, open-world and non-destructive, so the safety profile is covered. The description goes further, disclosing dataset scale (~10k), the consequence of an unfiltered call (first `limit` in dataset order), and the ranking order with 'can't fly to' airports last. This is rich behavioral context beyond annotations; only return-shape detail is missing, and an output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core verb and keys, then the routing rule, then the operational caveat and ranking order. Four tight clauses, each earning its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-parameter lookup with annotations and an output schema, everything an agent needs is present: when to call it, when to call the sibling instead, the mandatory search argument, and how results are ranked. Nothing material is omitted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters are already documented. The description adds meaning beyond the schema by giving examples of each search key (name substring, exact IATA code, city code) and by stating that an unfiltered call behaves differently from a filtered one, which informs how to use `limit`.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a clear verb and resource ('look up airports') and specifies the three lookup keys (name, IATA code, city code). It explicitly distinguishes itself from the sibling find_nearest_airports, so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use ('user names an airport or code and needs city/country/coordinates') and when-not (redirects to find_nearest_airports for towns not sharing the airport's name). It even adds an operational constraint: always pass search. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_citiesARead-onlyIdempotent
Look up cities by name or IATA code and return the code flight tools expect.
Use when the user names a city and a flight search needs its IATA code.
For an airport code use lookup_airports; for the nearest airport to a
place that is not itself a city, use find_nearest_airports.
Every flight tool takes IATA codes, so this is usually the first call when
the user names a place. The full dataset is ~9.6k cities, so always pass
search. Names are only available in the requested locale: searching
"Мюнхен" needs locale="ru".
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results to return (1-500, default 50). | |
| locale | No | 2-letter locale for names (e.g. "en", "ru"). Defaults to the server's locale. | |
| search | No | City name substring or exact IATA code (e.g. "bangkok", "BKK"). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds genuinely new behavioral context: the ~9.6k city dataset means search must always be supplied, and names are locale-bound ('searching "Мюнхен" needs locale="ru"'), which is a real failure mode an agent would otherwise hit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then routes to alternatives, then closes with the two operational constraints. Every sentence carries information; nothing is restated from the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation. Combined with full annotation coverage and complete parameter descriptions, the description supplies exactly the missing pieces: sibling routing, dataset scale, and locale-dependent matching.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: it explains why `search` should always be passed and that `locale` gates which name spellings will match. `limit` is left to the schema, which documents it fully, so no gap remains.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (look up) and resource (cities) plus the output contract: the IATA code flight tools expect. It explicitly distinguishes itself from lookup_airports and find_nearest_airports by name, so an agent can route correctly without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use condition ('when the user names a city and a flight search needs its IATA code'), names two sibling alternatives with the conditions that select them ('for an airport code use lookup_airports', 'for the nearest airport to a place that is not itself a city, use find_nearest_airports'), and adds the imperative 'always pass search'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_countriesARead-onlyIdempotent
Look up countries by name or two-letter country code.
Use when the user asks which country a code belongs to, or wants that
country's code or currency. For a city or airport code use lookup_cities
or lookup_airports; this tool does not search flight prices.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results to return (1-500, default 50). | |
| locale | No | 2-letter locale for names (e.g. "en", "ru"). Defaults to the server's locale. | |
| search | No | Country name substring or exact code (e.g. "thailand", "TH"). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is fully covered by structured fields. The description adds only light behavioral value: the scope exclusion about flight prices and the fact that currency is returned. No pagination or locale behavior is disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the primary capability front-loaded and the sibling routing in the second. No filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and rich annotations, the description only needs to carry purpose, usage context and sibling routing, all of which it does. Nothing required for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit, locale and search are already documented in the schema. The description mentions the two accepted lookup forms but adds no format or constraint detail beyond what the schema provides; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Look up countries') and the two acceptable input forms (name or two-letter country code). It also names the sibling tools it is not (lookup_cities, lookup_airports), so an agent can distinguish it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit activation conditions are given ('when the user asks which country a code belongs to, or wants that country's code or currency'), plus named alternatives for the confusable cases and an explicit exclusion ('this tool does not search flight prices').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_by_price_rangeARead-onlyIdempotent
Find flights whose cached fare falls inside a minimum and maximum price.
Use when the user has a budget, including anywhere under a price with no
destination named. Leave destination unset to let the budget pick the
city; prices are per adult in economy. For a named route on a date or a
month use search_flights or get_prices_calendar.
There is deliberately no date argument: this endpoint ignores one (verified —
passing a December date returns the same July and September fares), and each
result carries its own departure_at.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (1-100, default 20). | |
| market | No | 2-letter market whose price cache to read. Defaults to the server's configured market. | |
| origin | Yes | Origin IATA code. | |
| currency | No | Price currency (3 letters). Defaults to the server's currency. | |
| value_max | Yes | Highest acceptable price, in `currency`. | |
| value_min | Yes | Lowest acceptable price, in `currency`. | |
| destination | No | Destination IATA code. Optional — omit to search anywhere. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing that fares come from a cache, that pricing is per adult in economy, and — importantly — that a date argument is deliberately absent because the endpoint ignores one, verified empirically, with each result carrying its own `departure_at`. It doesn't mention result ordering, staleness windows, or rate limits, so it stops short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with the core behavior front-loaded, followed by the usage router and then the non-obvious date caveat. Every sentence carries distinct information; no preamble or restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return formatting is unnecessary, and the description covers what an agent needs to choose and call the tool: scope, routing to siblings, the intentional absence of a date param, and the interpretation of the price bounds. Nothing material is missing for a 7-param read-only search.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning: omitting `destination` switches the tool to an anywhere/budget-driven mode, and price bounds are framed as per-adult economy fares in the active currency. These contextualize otherwise mechanical min/max fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Find flights whose cached fare falls inside a minimum and maximum price'), naming the exact retrieval mechanism (cached fare) rather than a generic search. It explicitly differentiates itself from `search_flights` and `get_prices_calendar`, so an agent can pick it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('when the user has a budget, including anywhere under a price with no destination named'), an explicit parameter rule ('Leave destination unset to let the budget pick the city'), and names the two sibling alternatives plus the condition that selects them. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_flightsARead-onlyIdempotent
Search flight prices between two cities on a date or across a month.
Use when the user names both ends of a route and wants fares, a booking
link, or only departures inside a time window. For the cheapest day in a
month use get_prices_calendar; for the days around dates already chosen
use get_flexible_date_prices; for a budget with no destination use
search_by_price_range.
Both codes must be IATA — call lookup_cities first if you only have a city
name. For nearby airports use get_alternative_directions. A multi-city
trip needs one call per leg.
Note on passengers: the price data comes from a cache of recent searches and is always PER ADULT in economy. The adults/children/infants/trip_class parameters are encoded into each ticket's booking_link, so the link opens Aviasales with the full party pre-filled and shows the real total price.
Durations: each ticket reports duration_total (full door-to-door travel time), duration_to/duration_back (pure flight time per direction) and layover_minutes (combined ground time between connecting flights; 0 for direct flights). All values are in minutes.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max number of results (1-100, default 10). | |
| adults | No | Number of adult passengers, 1-9 (default 1). | |
| direct | No | If True, show only non-stop flights. | |
| market | No | 2-letter market whose price cache to read (e.g. "us", "ru", "th"). The same route in the same currency is priced differently per market, so set this to the traveller's country. Defaults to the server's configured market. | |
| origin | Yes | Origin city IATA code (e.g. "MOW", "LED"). | |
| infants | No | Number of infants under 2, 0-8 (default 0). Cannot exceed the number of adults; the excess is trimmed. | |
| one_way | No | If True, search one-way tickets only. | |
| children | No | Number of children 2-11 years, 0-8 (default 0). Adults plus children cannot exceed 9; the excess is trimmed. | |
| currency | No | Price currency code (3 letters, e.g. "rub", "usd"). Defaults to the server's configured currency. | |
| return_at | No | Return date or month (YYYY-MM-DD or YYYY-MM). Optional. | |
| trip_class | No | "economy", "comfort", "business" or "first" (default "economy"). | economy |
| destination | Yes | Destination city IATA code (e.g. "IST", "BCN"). | |
| depart_after | No | Keep only flights departing at or after this local time ("HH:MM", 24-hour). Optional. | |
| departure_at | No | Departure date or month (YYYY-MM-DD or YYYY-MM). Optional; a month searches every day in it. | |
| depart_before | No | Keep only flights departing at or before this local time ("HH:MM", 24-hour). Optional. Combined with depart_after and set earlier than it, the window wraps midnight (e.g. 22:00-06:00). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower. The description still adds non-obvious behaviour: prices come from a cache of recent searches, are always PER ADULT in economy, and the party size/trip class are only encoded into the booking_link. That is a genuine gotcha an agent would otherwise mis-handle. It stops short of describing result-paging or no-results behaviour.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and well-paragraphed: purpose, then sibling routing, then prerequisites, then caveats. Slight redundancy in the closing 'Durations' paragraph, which explains return fields already covered by the output schema, but every other sentence drives a routing or invocation decision.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 15-parameter, open-world search tool this is complete: routing, prerequisites, passenger/pricing semantics, and multi-leg handling are all covered. Safety is carried by annotations, parameter detail by a 100%-covered schema, and return shape by the output schema, so nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real meaning beyond it: the passengers/trip_class parameters do NOT change the returned price, they only pre-fill the booking link and reveal the true total. The IATA-code constraint on origin/destination is also reinforced in prose. It adds semantics the schema's field descriptions do not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Search flight prices between two cities on a date or across a month.' It immediately distinguishes itself from four named siblings (get_prices_calendar, get_flexible_date_prices, search_by_price_range), so an agent can route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('user names both ends of a route and wants fares, a booking link, or only departures inside a time window') plus named alternatives with the exact condition that selects each. Prerequisites are also stated: both codes must be IATA, call lookup_cities first, one call per leg for multi-city, get_alternative_directions for nearby airports.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
13 tool updates
v0.5.3- First observed
find_nearest_airports - First observed
get_alternative_directions - First observed
get_city_directions - First observed
get_flexible_date_prices - First observed
get_latest_prices - First observed
get_popular_directions - First observed
get_prices_calendar - First observed
lookup_airlines - First observed
lookup_airports - First observed
lookup_cities - First observed
lookup_countries - First observed
search_by_price_range - First observed
search_flights
TDQS
Scored across 13 tools
The price-search tools (search_flights, get_prices_calendar, get_flexible_date_prices, search_by_price_range, get_latest_prices) overlap conceptually, but each description explicitly states its trigger and points to sibling tools, which largely removes misselection risk. The direction trio (get_popular_directions vs get_city_directions vs get_alternative_directions) is the closest to confusing, yet descriptions clarify inbound vs outbound vs nearby-airport semantics.
All names are snake_case verb_noun and highly readable, with consistent get_/lookup_/search_/find_ prefixes. Minor deviation: retrieval verbs vary (lookup_cities vs find_nearest_airports vs get_popular_directions) for lookups that return lists, but the pattern stays predictable.
13 tools is squarely in the well-scoped range and each earns its place: four lookup/resolution tools, one core search, four price-variation tools, and four direction/alternative tools. No redundant or filler tools are present.
The read-only flight-price discovery domain is well covered end to end: code resolution, nearest-airport resolution, route search, calendar/flexible/range pricing, latest fares, and directional discovery. Minor gap is absence of a tool to fetch a specific offer's details (e.g. baggage/flight number), though booking links are provided as a workaround.
Maintenance
Related MCP Connectors
Travelpayouts MCP — wraps the Aviasales Flights Data API (travelpayouts.com)
Flight search, airfare analytics, flexible destinations
Google Flights search data: fares, routes, stops, and price insights via a hosted MCP server.
Cached flight fares on thousands of routes, each with the day it was seen. Not live prices. No key.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceFlight search for AI agents: flexible-date cheapest round-trips with a good-price verdict from historical data. Hosted remote MCP, free, no key.3MIT
- AlicenseNot gradedqualityBmaintenanceMCP server for the Travelpayouts (Aviasales) API. It provides 13 tools for flight search, price calendars, hotel search, and airport/airline/city lookup.57 npmMIT
- AlicenseNot gradedqualityDmaintenanceProvides live flight prices, booking links, and airport lookup via a hosted MCP server. Enables search for flights and direct booking URL retrieval.1MIT
- AlicenseAqualityBmaintenanceEnables real-time flight fare searches across date ranges and multiple destinations, with historical price insights and booking links. Provides one-way and round-trip search tools through MCP.41MIT