Flyan — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Flyan (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
An open-source unofficial API wrapper to get flight data from Ryanair.
<!-- mcp-name: io.github.victorlane/flyan-mcp -->
[!TIP] New: MCP server for AI agents. Plug Flyan into Claude Desktop, Claude Code, or Cursor and search Ryanair flights in natural language. Jump to the MCP Quickstart.
pip install FlyanOr using uv:
uv add Flyanfrom datetime import datetime
from flyan import RyanAir, FlightSearchParams
# Initialize the client
client = RyanAir(currency="EUR")
# Set up search parameters
search_params = FlightSearchParams(
from_airport="DUB", # Dublin
to_airport="BCN", # Barcelona
from_date=datetime(2025, 8, 15),
to_date=datetime(2025, 8, 20),
max_price=200
)
# Search for one-way flights
flights = client.get_oneways(search_params)
# Display results
for flight in flights:
print(f"Flight {flight.flight_number}: {flight.departure_airport.name} → {flight.arrival_airport.name}")
print(f"Departure: {flight.departure_date}")
print(f"Price: {flight.price} {flight.currency}")
print("---")#### Constructor
RyanAir(currency: str = "EUR")Creates a new RyanAir client instance.
Parameters:
currency (str, optional): Preferred currency for pricing. Defaults to "EUR". Must be a valid currency code from the supported currencies list.Example:
# Default EUR currency
client = RyanAir()
# Specific currency
client = RyanAir(currency="USD")#### Methods
##### get_oneways(params: FlightSearchParams) -> list[Flight]
Search for one-way flights.
Parameters:
params (FlightSearchParams): Search parametersReturns:
list[Flight]: List of available flightsParameters for searching flights.
FlightSearchParams(
from_airport: str,
from_date: datetime,
to_date: datetime,
destination_country: Optional[str] = None,
max_price: Optional[int] = None,
to_airport: Optional[str] = None,
departure_time_from: Optional[str] = "00:00",
departure_time_to: Optional[str] = "23:59"
)Parameters:
from_airport (str): IATA code of departure airport (e.g., "DUB")from_date (datetime): Earliest departure dateto_date (datetime): Latest departure datedestination_country (str, optional): Country code for destinationmax_price (int, optional): Maximum price filterto_airport (str, optional): IATA code of arrival airportdeparture_time_from (str, optional): Earliest departure time (HH:MM format)departure_time_to (str, optional): Latest departure time (HH:MM format)Example:
from datetime import datetime
params = FlightSearchParams(
from_airport="DUB",
from_date=datetime(2025, 8, 15),
to_date=datetime(2025, 8, 20),
to_airport="BCN",
max_price=150,
departure_time_from="08:00",
departure_time_to="18:00"
)Extended parameters for return flight searches.
ReturnFlightSearchParams(
# All FlightSearchParams fields plus:
return_date_from: datetime,
return_date_to: datetime,
inbound_departure_time_from: Optional[str] = "00:00",
inbound_departure_time_to: Optional[str] = "23:59"
)Represents a single flight.
Attributes:
departure_airport (Airport): Departure airport informationarrival_airport (Airport): Arrival airport informationdeparture_date (datetime): Departure date and timearrival_date (datetime): Arrival date and timeprice (float): Flight pricecurrency (str): Price currencyflight_key (str): Unique flight identifierflight_number (str): Flight numberprevious_price (Optional[str | float]): Previous price if availableRepresents airport information.
Attributes:
country_name (str): Country nameiata_code (str): IATA airport codename (str): Airport nameseo_name (str): SEO-friendly namecity_name (str): City namecity_code (str): City codecity_country_code (str): Country codeRepresents a return flight booking.
Attributes:
outbound (Flight): Outbound flightinbound (Flight): Return flightsummary_price (float): Total price for both flightssummary_currency (str): Currency for total priceprevious_price (str | float): Previous total price if availableRepresents an airport in Ryanair's live network. Returned by the explore methods.
Attributes:
iata_code (str): IATA airport codename (str): Airport nameseo_name (str): SEO-friendly namecountry_code (str): Lowercase ISO2 country code (e.g. "ie", "es")city_code (str): City code (e.g. "LONDON", "DUBLIN")region_code (Optional[str]): Region code (e.g. "SCOTLAND", "ANDALUSIA")currency_code (str): Local currency codetime_zone (str): IANA timezone (e.g. "Europe/Dublin")base (bool): True if this is a Ryanair baselatitude (float), longitude (float): Coordinatesroutes (list[str]): Raw route strings (year-round)seasonal_routes (list[str]): Raw route strings (seasonal-only)categories (list[str]): Marketing categories assigned by Ryanairaliases (list[str]): Alternative namesHelpers: airport_routes(), country_routes(), seasonal_airport_routes(), typed_routes(), typed_seasonal_routes().
Returned by explore_with_fares(). Pairs a reachable destination with its cheapest sampled fare, if one was returned by the price probe.
Attributes:
airport (NetworkAirport): The destination airportfare (Optional[Flight]): The cheapest sampled fare in the window, or Noneif the route is in the network but no priced inventory came back (no flights in the window, sold out, etc.)
# Search flights to any airport in Spain
params = FlightSearchParams(
from_airport="DUB",
destination_country="ES",
from_date=datetime(2025, 9, 1),
to_date=datetime(2025, 9, 7)
)
flights = client.get_oneways(params)# Morning flights under €100
params = FlightSearchParams(
from_airport="STN", # London Stansted
to_airport="DUB", # Dublin
from_date=datetime(2025, 8, 1),
to_date=datetime(2025, 8, 5),
max_price=100,
departure_time_from="06:00",
departure_time_to="12:00"
)
flights = client.get_oneways(params)from flyan import RyanairException
try:
flights = client.get_oneways(params)
if not flights:
print("No flights found for the given criteria")
except RyanairException as e:
print(f"Ryanair API error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")Explore Mode answers the question "where can I actually fly from here?". It reads Ryanair's live network metadata once and exposes the reachable destinations from any airport, optionally grouped, filtered, or joined with the cheapest fare in a date window.
All methods below are available on both RyanAir and AsyncRyanAir.
destinations = client.get_destinations("DUB")
for airport in destinations:
print(f"{airport.iata_code} {airport.name} ({airport.country_code})")# All Scottish airports DUB flies to
in_scotland = client.get_destinations_in_region("DUB", "SCOTLAND")
# All London airports DUB flies to (LGW, LTN, STN)
in_london = client.get_destinations_in_city("DUB", "LONDON")
# All Spanish airports DUB flies to
in_spain = client.get_destinations_in_country("DUB", "es")Country codes are lowercase ISO2. Region and city codes come from the live network (uppercase, e.g. SCOTLAND, ANDALUSIA, COSTA_DE_SOL, LONDON, MILAN).
# {country_code: [airports]}
by_country = client.explore_by_country("DUB")
print(f"DUB flies to {len(by_country)} countries")
for country, airports in sorted(by_country.items()):
codes = ", ".join(a.iata_code for a in airports)
print(f" {country}: {codes}")# {region_code: [airports]}
by_region = client.explore_by_region("DUB")Airports without a region_code are collected under the empty-string key, so callers can decide whether to surface or drop them.
seasonal = client.get_seasonal_destinations("DUB")Ryanair's seasonalRoutes list is sparsely populated upstream, so this often returns [] outside of summer/winter schedule transitions. The method is provided so callers do not need to peek at the raw route strings.
explore_with_fares() joins the network destinations with a oneWayFares probe, so each destination comes back with its cheapest sampled Flight (or None if no fare was returned for that route in the window). It costs one network call plus one fare call.
from datetime import datetime, timedelta
start = datetime.now() + timedelta(days=14)
end = start + timedelta(days=7)
results = client.explore_with_fares("DUB", start, end, max_price=100)
priced = [d for d in results if d.fare is not None]
cheapest_first = sorted(priced, key=lambda d: d.fare.price)
for d in cheapest_first[:10]:
print(f"{d.airport.iata_code} {d.airport.name}: "
f"{d.fare.price} {d.fare.currency}")AsyncRyanAir mirrors every explore method:
import asyncio
from flyan import AsyncRyanAir
async def main():
async with AsyncRyanAir() as client:
by_country = await client.explore_by_country("DUB")
print(f"{len(by_country)} countries reachable from DUB")
asyncio.run(main())If you call multiple explore methods in a row, wrap the transport in CachingTransport so the network metadata is fetched once and reused.
[!IMPORTANT] Two commands and you're done:
>
``bash uv tool install "Flyan[mcp]" claude mcp add flyan flyan-mcp ``>
Now your agent can search Ryanair flights in natural language. No API keys, no accounts.
Flyan ships an optional Model Context Protocol server so your agent can search Ryanair fares from natural-language prompts like "find me a cheap flight from Dublin to Spain in August under €150" or "what's the cheapest day in July to fly DUB to BCN".
1. Install Flyan with the MCP extra:
uv tool install "Flyan[mcp]"Or with pip:
pipx install "Flyan[mcp]"This installs a flyan-mcp console script on your PATH.
2. Add it to your agent:
Claude Code (one-liner):
claude mcp add flyan flyan-mcpClaude Desktop: open ~/Library/Application Support/Claude/claude_desktop_config.json on macOS (or %APPDATA%\Claude\claude_desktop_config.json on Windows) and add:
{
"mcpServers": {
"flyan": {
"command": "flyan-mcp"
}
}
}Then restart Claude Desktop.
Cursor: Settings → MCP → Add new server, name flyan, command flyan-mcp.
The server returns prices in EUR by default. To get them in another currency, set the FLYAN_CURRENCY env var to any supported ISO 4217 code before launching flyan-mcp:
FLYAN_CURRENCY=GBP flyan-mcpOr pass it through your agent's MCP config:
{
"mcpServers": {
"flyan": {
"command": "flyan-mcp",
"env": { "FLYAN_CURRENCY": "GBP" }
}
}
}Unknown or unsupported codes silently fall back to EUR.
3. Try it. Ask your agent:
"Find me a one-way from Dublin to anywhere in Spain in the first week of August under €150."
The agent should call find_flights with destination_country="es", then summarize the cheapest options.
The server exposes four curated tools so the agent can pick reliably:
find_flights for one-way searches with optional country, IATA, or price filtersfind_anywhere_under for "where can I go for under £X" promptsexplore_destinations for "what countries can I reach from X"cheapest_per_day for "what's the cheapest day this month to fly X to Y"No API keys, accounts, or rate-limit setup. Ryanair's API is anonymous and the server reuses a single RyanAir client across calls.
The SDK supports all airports in Ryanair's network. Airport codes must be valid 3-letter IATA codes. The live list is fetched from Ryanair's aggregate endpoint via client.get_network(); iterate network.airports for the full set.
Popular airports include:
The SDK supports multiple currencies. Some popular ones include:
See currencies.json for the complete list.
The SDK includes automatic retry logic with exponential backoff to handle rate limiting and temporary API issues. It will retry failed requests up to 5 times before giving up.
This is an open-source project. Contributions are welcome!
This is an unofficial API wrapper and is not affiliated with Ryanair. Use at your own risk and ensure you comply with Ryanair's terms of service.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.