Skip to main content
Glama

airports-search

Search for flight options and airport information between specified departure and arrival airports using Google Flights data. Find available flights, compare prices, and get essential travel details for trip planning.

Instructions

Search for airport and flight information using Google Flights

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
departure_idYesDeparture airport code (e.g., 'CDG', 'AUS', 'LAX', 'SFO'). Use 3-letter IATA codes.
arrival_idYesArrival airport code (e.g., 'NRT', 'LAX', 'JFK', 'LHR'). Use 3-letter IATA codes.
outbound_dateNoOutbound date in YYYY-MM-DD format
return_dateNoReturn date in YYYY-MM-DD format for round-trip (REQUIRED when type=1)
multi_city_jsonNoJSON string for multi-city trips with multiple legs (required when type=3)
typeNoTrip type: 1=Round-trip (requires return_date), 2=One-way (default), 3=Multi-city (requires multi_city_json). Use type=2 for one-way trips to avoid errors.
max_best_flightsNoMaximum number of best flights to return
max_other_flightsNoMaximum number of other flights to return
include_price_insightsNoInclude price insights and history
include_airportsNoInclude airport information
summary_onlyNoReturn only essential flight information
include_linksNoInclude booking links for each flight (off by default)

Implementation Reference

  • The core handler function searchAirports that queries SerpAPI for Google Flights data using the provided parameters and returns formatted Markdown output.
    export async function searchAirports( params: z.infer<typeof airportsSearchSchema> ): Promise<string> { const apiKey = process.env.SERP_API_KEY; if (!apiKey) { throw new Error("SERP_API_KEY environment variable is required"); } const { max_best_flights, max_other_flights, include_price_insights, include_airports, summary_only, include_links, ...apiParams } = params; const searchParams = new URLSearchParams({ engine: "google_flights", api_key: apiKey, departure_id: apiParams.departure_id, arrival_id: apiParams.arrival_id, hl: "en", currency: "USD", ...(apiParams.outbound_date && { outbound_date: apiParams.outbound_date }), ...(apiParams.return_date && { return_date: apiParams.return_date }), ...(apiParams.multi_city_json && { multi_city_json: apiParams.multi_city_json, }), ...(apiParams.type !== undefined && { type: apiParams.type.toString() }), }); try { const response = await axios.get( `${SERPAPI_BASE_URL}?${searchParams.toString()}` ); return formatFlightToMarkdown(response.data, params); } catch (error) { if (axios.isAxiosError(error)) { throw new Error( `Airports API request failed: ${ error.response?.data?.error || error.message }` ); } throw error; } }
  • Zod schema defining input parameters for the airports-search tool, including airports, dates, trip type, and formatting options.
    const airportsSearchSchema = z.object({ departure_id: z .string() .describe("Departure airport code (e.g., 'CDG', 'AUS', 'LAX', 'SFO'). Use 3-letter IATA codes."), arrival_id: z.string().describe("Arrival airport code (e.g., 'NRT', 'LAX', 'JFK', 'LHR'). Use 3-letter IATA codes."), outbound_date: z .string() .optional() .describe("Outbound date in YYYY-MM-DD format"), return_date: z .string() .optional() .describe("Return date in YYYY-MM-DD format for round-trip (REQUIRED when type=1)"), multi_city_json: z .string() .optional() .describe("JSON string for multi-city trips with multiple legs (required when type=3)"), type: z .number() .optional() .default(2) .describe("Trip type: 1=Round-trip (requires return_date), 2=One-way (default), 3=Multi-city (requires multi_city_json). Use type=2 for one-way trips to avoid errors."), max_best_flights: z .number() .optional() .default(3) .describe("Maximum number of best flights to return"), max_other_flights: z .number() .optional() .default(5) .describe("Maximum number of other flights to return"), include_price_insights: z .boolean() .optional() .default(true) .describe("Include price insights and history"), include_airports: z .boolean() .optional() .default(false) .describe("Include airport information"), summary_only: z .boolean() .optional() .default(true) .describe("Return only essential flight information"), include_links: z .boolean() .optional() .default(false) .describe("Include booking links for each flight (off by default)"), });
  • src/index.ts:151-179 (registration)
    MCP server tool registration for 'airports-search', using the schema and wrapping searchAirports handler with error handling and content formatting.
    server.tool( "airports-search", "Search for airport and flight information using Google Flights", airportsSearchSchema.shape, async (params) => { try { const result = await searchAirports(params); return { content: [ { type: "text", text: result, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error searching airports data: ${ error instanceof Error ? error.message : String(error) }`, }, ], }; } } );
  • Helper function that formats the raw SerpAPI flight data into a structured Markdown report, handling best/other flights, durations, layovers, and price insights.
    function formatFlightToMarkdown(data: any, params: z.infer<typeof airportsSearchSchema>): string { if (!data) return "No flight data available."; let markdown = `# ${params.departure_id} → ${params.arrival_id}\n\n`; // Get the Google Flights URL for booking const googleFlightsUrl = data.search_metadata?.google_flights_url; // Add route summary if (params.summary_only) { const bestFlight = data.best_flights?.[0]; const bestPrice = bestFlight?.price || data.price_insights?.lowest_price; const flightCount = (data.best_flights?.length || 0) + (data.other_flights?.length || 0); markdown += `**Best Price**: $${bestPrice}\n`; if (bestFlight?.flights?.[0]?.airline) { markdown += `**Airline**: ${bestFlight.flights[0].airline}\n`; } markdown += `**Flights Found**: ${flightCount}\n\n`; if (params.include_price_insights !== false && data.price_insights) { markdown += `**Price Level**: ${data.price_insights.price_level}\n`; if (data.price_insights.typical_price_range) { markdown += `**Typical Range**: $${data.price_insights.typical_price_range.join('-$')}\n`; } } return markdown; } // Add best flights if (data.best_flights && params.max_best_flights && params.max_best_flights > 0) { markdown += `## Best Options\n\n`; const bestFlights = data.best_flights.slice(0, params.max_best_flights); bestFlights.forEach((flight: any) => { const stops = flight.flights && flight.flights.length > 1 ? `${flight.flights.length - 1} stop${flight.flights.length > 2 ? 's' : ''}` : 'Direct'; const totalDuration = formatDuration(flight.total_duration); markdown += `### $${flight.price} • ${totalDuration} • ${stops}\n`; if (params.include_links && googleFlightsUrl) { markdown += `**URL**: ${googleFlightsUrl}\n`; } if (flight.flights && flight.flights.length > 0) { flight.flights.forEach((segment: any, index: number) => { const depAirport = segment.departure_airport?.code || segment.departure_airport?.name || segment.departure_airport || 'Unknown'; const arrAirport = segment.arrival_airport?.code || segment.arrival_airport?.name || segment.arrival_airport || 'Unknown'; const depTime = segment.departure_airport?.time || 'Unknown'; const arrTime = segment.arrival_airport?.time || 'Unknown'; markdown += `${segment.airline} ${segment.flight_number}: ${depAirport} ${depTime} → ${arrAirport} ${arrTime}\n`; // Add layover information if this is not the last segment if (index < flight.flights.length - 1 && flight.layovers?.[index]) { const layover = flight.layovers[index]; const layoverDuration = formatDuration(layover.duration); markdown += ` Layover: ${layoverDuration}\n`; } }); } markdown += `\n`; }); } // Add other flights if (data.other_flights && params.max_other_flights && params.max_other_flights > 0) { markdown += `## Other Options\n\n`; const otherFlights = data.other_flights.slice(0, params.max_other_flights); otherFlights.forEach((flight: any) => { const stops = flight.flights && flight.flights.length > 1 ? `${flight.flights.length - 1} stop${flight.flights.length > 2 ? 's' : ''}` : 'Direct'; const totalDuration = formatDuration(flight.total_duration); markdown += `### $${flight.price} • ${totalDuration} • ${stops}\n`; if (params.include_links && googleFlightsUrl) { markdown += `**URL**: ${googleFlightsUrl}\n`; } if (flight.flights && flight.flights.length > 0) { flight.flights.forEach((segment: any, index: number) => { const depAirport = segment.departure_airport?.code || segment.departure_airport?.name || segment.departure_airport || 'Unknown'; const arrAirport = segment.arrival_airport?.code || segment.arrival_airport?.name || segment.arrival_airport || 'Unknown'; const depTime = segment.departure_airport?.time || 'Unknown'; const arrTime = segment.arrival_airport?.time || 'Unknown'; markdown += `${segment.airline} ${segment.flight_number}: ${depAirport} ${depTime} → ${arrAirport} ${arrTime}\n`; // Add layover information if this is not the last segment if (index < flight.flights.length - 1 && flight.layovers?.[index]) { const layover = flight.layovers[index]; const layoverDuration = formatDuration(layover.duration); markdown += ` Layover: ${layoverDuration}\n`; } }); } markdown += `\n`; }); } // Add price insights for detailed view if (params.include_price_insights !== false && data.price_insights && !params.summary_only) { markdown += `**Price Level**: ${data.price_insights.price_level} • Lowest: $${data.price_insights.lowest_price}\n`; } return markdown; }
  • Utility helper to format flight durations from minutes into HH:MM string format.
    function formatDuration(minutes: number | string): string { const mins = typeof minutes === 'string' ? parseInt(minutes) : minutes; if (isNaN(mins)) return 'Unknown'; const hours = Math.floor(mins / 60); const remainingMins = mins % 60; return `${hours}:${remainingMins.toString().padStart(2, '0')}`; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CaptainCrouton89/maps-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server