airports-search
Search for airport and flight details using Google Flights. Input departure and arrival airport codes, dates, and trip type to retrieve essential flight information, price insights, and booking links.
Instructions
Search for airport and flight information using Google Flights
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| arrival_id | Yes | Arrival airport code (e.g., 'NRT', 'LAX', 'JFK', 'LHR'). Use 3-letter IATA codes. | |
| departure_id | Yes | Departure airport code (e.g., 'CDG', 'AUS', 'LAX', 'SFO'). Use 3-letter IATA codes. | |
| include_airports | No | Include airport information | |
| include_links | No | Include booking links for each flight (off by default) | |
| include_price_insights | No | Include price insights and history | |
| max_best_flights | No | Maximum number of best flights to return | |
| max_other_flights | No | Maximum number of other flights to return | |
| multi_city_json | No | JSON string for multi-city trips with multiple legs (required when type=3) | |
| outbound_date | No | Outbound date in YYYY-MM-DD format | |
| return_date | No | Return date in YYYY-MM-DD format for round-trip (REQUIRED when type=1) | |
| summary_only | No | Return only essential flight information | |
| type | No | 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. |
Implementation Reference
- src/index.ts:151-179 (registration)Registration of the 'airports-search' MCP tool, which calls the searchAirports handler function.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) }`, }, ], }; } } );
- src/airports.ts:173-221 (handler)Main handler function for 'airports-search' tool. Queries SerpAPI Google Flights endpoint and formats response to markdown.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; } }
- src/airports.ts:6-58 (schema)Zod schema defining input parameters for the 'airports-search' tool.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/airports.ts:69-170 (helper)Helper function to format the API response data into a readable Markdown string for the tool output.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; }